diff --git a/.travis.yml b/.travis.yml
index 1e4a18ea..06f8c3c9 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -6,3 +6,6 @@ script :
- mvn install -DskipTests
- mvn verify
sudo: false
+addons:
+ sonarcloud:
+ organization: "lequal"
diff --git a/README.md b/README.md
index 46ac0fbc..3e8ffe59 100644
--- a/README.md
+++ b/README.md
@@ -6,6 +6,42 @@ i-Code CNES is a static code analysis tool to help developers write code complia
All the informations on CNES standards coverage, and rules availabilities and limitations can be read in the [documentation](https://github.com/lequal/i-CodeCNES/tree/master/documentation).
+Release 3.1.0
+=============
+## New features
+* New command line #133
+* New parsing error handling, a violation named "Parser error" is added instead of suspend the analysis. #154
+* New rules (Shell)
+ * COM.DATA.Initialisation ( fix #113 )
+ * COM.DATA.Invariant ( fix #114 )
+ * COM.FLOW.FilePath ( fix #115 )
+ * COM.FLOW.Recursion ( fix #116 )
+ * COM.INST.BoolNegation ( fix #117 )
+ * COM.NAME.Homonymy ( fix #118 )
+ * COM.PRES.Indent ( fix #119 )
+ * COM.PRES.LengthLine ( fix #120 )
+ * SH.FLOW.CheckCodeReturn ( fix #121 )
+ * SH.Ref.Export ( fix #122 #52 #138 #137)
+ * SH.SYNC.Signals #123
+* New metrics
+ * SH.MET.LineOfComment
+ * F77.MET.LineOfComment
+ * F90.MET.LineOfComment
+
+## Fixes
+* Shell
+ * All checkers :
+ * Function correction on FUNCSTART and FNAME #138 #137 #150
+ * COM.FLOW.CaseSwitch :
+ * Case handling fixed #135
+ * Function localization fixed #52
+ * COM.DATA.LoopCondition
+ * Function localization fixed #52
+ * COM.DESIGN.ActiveWait
+ * Function localization fixed #52
+ * COM.FLOW.Abort
+ * Function localization fixed #52
+
Release 3.0.1
=============
* Fix of Eclipse's plug-in performances #101
diff --git a/documentation/i-Code CNES - Manuel Utilisateur.pdf b/documentation/i-Code CNES - Manuel Utilisateur.pdf
deleted file mode 100644
index 7422414b..00000000
Binary files a/documentation/i-Code CNES - Manuel Utilisateur.pdf and /dev/null differ
diff --git a/documentation/i-Code CNES - User Manual - EN.pdf b/documentation/i-Code CNES - User Manual.pdf
similarity index 74%
rename from documentation/i-Code CNES - User Manual - EN.pdf
rename to documentation/i-Code CNES - User Manual.pdf
index b456d47d..ab74dc18 100644
Binary files a/documentation/i-Code CNES - User Manual - EN.pdf and b/documentation/i-Code CNES - User Manual.pdf differ
diff --git a/fr.cnes.analysis.tools.analyzer/META-INF/MANIFEST.MF b/fr.cnes.analysis.tools.analyzer/META-INF/MANIFEST.MF
index 1104995a..80b54425 100755
--- a/fr.cnes.analysis.tools.analyzer/META-INF/MANIFEST.MF
+++ b/fr.cnes.analysis.tools.analyzer/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: i-Code CNES Analyzer
Bundle-SymbolicName: fr.cnes.analysis.tools.analyzer;singleton:=true
-Bundle-Version: 3.0.1.qualifier
+Bundle-Version: 3.1.0.qualifier
Bundle-Activator: fr.cnes.analysis.tools.analyzer.Activator
Require-Bundle: org.eclipse.core.resources,
org.eclipse.core.runtime
diff --git a/fr.cnes.analysis.tools.analyzer/plugin.xml b/fr.cnes.analysis.tools.analyzer/plugin.xml
index 85fecb95..c687c63b 100755
--- a/fr.cnes.analysis.tools.analyzer/plugin.xml
+++ b/fr.cnes.analysis.tools.analyzer/plugin.xml
@@ -3,5 +3,23 @@
+
+
+
+
+
+
+
+
diff --git a/fr.cnes.analysis.tools.analyzer/pom.xml b/fr.cnes.analysis.tools.analyzer/pom.xml
index b425e681..e623e3bf 100644
--- a/fr.cnes.analysis.tools.analyzer/pom.xml
+++ b/fr.cnes.analysis.tools.analyzer/pom.xml
@@ -6,7 +6,7 @@
fr.cnes.icode
fr.cnes.icode.parent
- 3.0.1-SNAPSHOT
+ 3.1.0-SNAPSHOT
fr.cnes.analysis.tools.analyzer
diff --git a/fr.cnes.analysis.tools.analyzer/src/fr/cnes/analysis/tools/analyzer/CallableChecker.java b/fr.cnes.analysis.tools.analyzer/src/fr/cnes/analysis/tools/analyzer/CallableChecker.java
index 495417d2..2c2bb221 100644
--- a/fr.cnes.analysis.tools.analyzer/src/fr/cnes/analysis/tools/analyzer/CallableChecker.java
+++ b/fr.cnes.analysis.tools.analyzer/src/fr/cnes/analysis/tools/analyzer/CallableChecker.java
@@ -14,6 +14,7 @@
import fr.cnes.analysis.tools.analyzer.datas.AbstractChecker;
import fr.cnes.analysis.tools.analyzer.datas.CheckResult;
+import fr.cnes.analysis.tools.analyzer.datas.ParsingError;
import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
import fr.cnes.analysis.tools.analyzer.logger.ICodeLogger;
@@ -62,7 +63,17 @@ public List call() throws IOException, JFlexException {
ICodeLogger.entering(CLASS, method);
final List results = new ArrayList<>();
rule.setInputFile(file);
- results.addAll(rule.run());
+ try {
+ results.addAll(rule.run());
+ } catch (JFlexException exception) {
+ ICodeLogger.error(exception.getFileName(), exception.getRuleName(), exception.getMessage());
+ CheckResult result = new CheckResult(ParsingError.PARSING_ERROR_NAME,ParsingError.PARSING_ERROR_ID, ParsingError.PARSING_ERROR_LANGUAGE);
+ result.setLine(Integer.valueOf(exception.getLine()));
+ result.setLocation(exception.getRuleName() +"[l"+exception.getLine()+":c"+exception.getColumn()+"]");
+ result.setMessage(exception.getErrorMessage());
+ result.setFile(file);
+ results.add(result);
+ }
ICodeLogger.exiting(CLASS, method, results);
return results;
}
diff --git a/fr.cnes.analysis.tools.analyzer/src/fr/cnes/analysis/tools/analyzer/datas/ParsingError.java b/fr.cnes.analysis.tools.analyzer/src/fr/cnes/analysis/tools/analyzer/datas/ParsingError.java
new file mode 100644
index 00000000..48495d11
--- /dev/null
+++ b/fr.cnes.analysis.tools.analyzer/src/fr/cnes/analysis/tools/analyzer/datas/ParsingError.java
@@ -0,0 +1,24 @@
+package fr.cnes.analysis.tools.analyzer.datas;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * This rule is intended to add record parsing exceptions.
+ *
+ */
+public class ParsingError extends AbstractChecker {
+
+ public final static String PARSING_ERROR_ID = "fr.cnes.analysis.tools.analyzer.parsingError";
+ public final static String PARSING_ERROR_LANGUAGE = "fr.cnes.analysis.tools.analyzer.parsingError";
+ public final static String PARSING_ERROR_NAME = "Parsing error";
+
+ public ParsingError() {
+ }
+
+
+ @Override
+ public List run() throws IOException {
+ return getCheckResults();
+ }
+}
diff --git a/fr.cnes.analysis.tools.analyzer/src/fr/cnes/analysis/tools/analyzer/exception/JFlexException.java b/fr.cnes.analysis.tools.analyzer/src/fr/cnes/analysis/tools/analyzer/exception/JFlexException.java
index 1003a4c3..178f9bbb 100755
--- a/fr.cnes.analysis.tools.analyzer/src/fr/cnes/analysis/tools/analyzer/exception/JFlexException.java
+++ b/fr.cnes.analysis.tools.analyzer/src/fr/cnes/analysis/tools/analyzer/exception/JFlexException.java
@@ -93,9 +93,9 @@ private static String errorMessage(String pRuleName, String pFileName, String pM
+ pMessage + BLANK + "CheckerId: " + pRuleName + BLANK + "File: "
+ pFileName + BLANK + "Line:" + pLine + BLANK + "Column:" + pColumn + BLANK
- + "Last word scanned : [" + pLastScan + "] [" + toDecimalCode(pLastScan)
+ + "Last word scanned: [" + pLastScan + "] [" + toDecimalCode(pLastScan)
+ "]" + BLANK
- + "Please report this issue on : https://github.com/dupuisa/i-CodeCNES/issues/";
+ + "Please report this issue on : https://github.com/lequal/i-CodeCNES/issues/";
return message;
}
diff --git a/fr.cnes.analysis.tools.export.csv/META-INF/MANIFEST.MF b/fr.cnes.analysis.tools.export.csv/META-INF/MANIFEST.MF
index 26205364..60b363c6 100644
--- a/fr.cnes.analysis.tools.export.csv/META-INF/MANIFEST.MF
+++ b/fr.cnes.analysis.tools.export.csv/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: i-Code CNES CSV Export
Bundle-SymbolicName: fr.cnes.analysis.tools.export.csv;singleton:=true
-Bundle-Version: 3.0.1.qualifier
+Bundle-Version: 3.1.0.qualifier
Bundle-Activator: fr.cnes.analysis.tools.export.csv.Activator
Bundle-Vendor: CNES
Require-Bundle: org.eclipse.core.runtime,
diff --git a/fr.cnes.analysis.tools.export.csv/pom.xml b/fr.cnes.analysis.tools.export.csv/pom.xml
index a584b026..1f8a6005 100644
--- a/fr.cnes.analysis.tools.export.csv/pom.xml
+++ b/fr.cnes.analysis.tools.export.csv/pom.xml
@@ -6,7 +6,7 @@
fr.cnes.icode
fr.cnes.icode.parent
- 3.0.1-SNAPSHOT
+ 3.1.0-SNAPSHOT
fr.cnes.analysis.tools.export.csv
diff --git a/fr.cnes.analysis.tools.export.xml/META-INF/MANIFEST.MF b/fr.cnes.analysis.tools.export.xml/META-INF/MANIFEST.MF
index 3e1046e0..5a9501cc 100644
--- a/fr.cnes.analysis.tools.export.xml/META-INF/MANIFEST.MF
+++ b/fr.cnes.analysis.tools.export.xml/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: i-Code CNES XML Export
Bundle-SymbolicName: fr.cnes.analysis.tools.export.xml;singleton:=true
-Bundle-Version: 3.0.1.qualifier
+Bundle-Version: 3.1.0.qualifier
Bundle-Activator: fr.cnes.analysis.tools.export.xml.Activator
Bundle-Vendor: CNES
Require-Bundle: fr.cnes.analysis.tools.analyzer;bundle-version="2.0.0",
diff --git a/fr.cnes.analysis.tools.export.xml/pom.xml b/fr.cnes.analysis.tools.export.xml/pom.xml
index ec7b7e01..fbf2568b 100644
--- a/fr.cnes.analysis.tools.export.xml/pom.xml
+++ b/fr.cnes.analysis.tools.export.xml/pom.xml
@@ -6,7 +6,7 @@
fr.cnes.icode
fr.cnes.icode.parent
- 3.0.1-SNAPSHOT
+ 3.1.0-SNAPSHOT
fr.cnes.analysis.tools.export.xml
diff --git a/fr.cnes.analysis.tools.export/META-INF/MANIFEST.MF b/fr.cnes.analysis.tools.export/META-INF/MANIFEST.MF
index b9c73515..95d9243f 100644
--- a/fr.cnes.analysis.tools.export/META-INF/MANIFEST.MF
+++ b/fr.cnes.analysis.tools.export/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: i-Code CNES Export
Bundle-SymbolicName: fr.cnes.analysis.tools.export;singleton:=true
-Bundle-Version: 3.0.1.qualifier
+Bundle-Version: 3.1.0.qualifier
Bundle-Vendor: CNES
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Require-Bundle: fr.cnes.analysis.tools.analyzer,
diff --git a/fr.cnes.analysis.tools.export/pom.xml b/fr.cnes.analysis.tools.export/pom.xml
index 70a68570..2b73e4fc 100644
--- a/fr.cnes.analysis.tools.export/pom.xml
+++ b/fr.cnes.analysis.tools.export/pom.xml
@@ -6,7 +6,7 @@
fr.cnes.icode
fr.cnes.icode.parent
- 3.0.1-SNAPSHOT
+ 3.1.0-SNAPSHOT
fr.cnes.analysis.tools.export
diff --git a/fr.cnes.analysis.tools.export/src/fr/cnes/analysis/tools/export/ExportService.java b/fr.cnes.analysis.tools.export/src/fr/cnes/analysis/tools/export/ExportService.java
index 6a6af8e2..b997453b 100644
--- a/fr.cnes.analysis.tools.export/src/fr/cnes/analysis/tools/export/ExportService.java
+++ b/fr.cnes.analysis.tools.export/src/fr/cnes/analysis/tools/export/ExportService.java
@@ -49,11 +49,24 @@ public class ExportService implements IExportService {
public void export(List checkResults, File outputFile,
Map parameters) throws NoContributorMatchingException,
NoExtensionIndicatedException, IOException, CoreException {
+ export(checkResults, outputFile, parameters,
+ ExportUtils.getExtensionFromFilePath(outputFile.getAbsolutePath()));
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see fr.cnes.analysis.tools.export.IExportService#export(java.util.List,
+ * java.io.File, java.util.Map, java.lang.String)
+ */
+ @Override
+ public void export(List pCheckResults, File pOutputFile,
+ Map pParameters, String pFormat) throws NoContributorMatchingException,
+ NoExtensionIndicatedException, IOException, CoreException {
final String method = "export";
ICodeLogger.entering(CLASS, method);
- final IExporter exporter = getExportClass(
- ExportUtils.getExtensionFromFilePath(outputFile.getAbsolutePath()));
- exporter.export(checkResults, outputFile, parameters);
+ final IExporter exporter = getExportClass(pFormat);
+ exporter.export(pCheckResults, pOutputFile, pParameters);
ICodeLogger.exiting(CLASS, method);
}
diff --git a/fr.cnes.analysis.tools.export/src/fr/cnes/analysis/tools/export/IExportService.java b/fr.cnes.analysis.tools.export/src/fr/cnes/analysis/tools/export/IExportService.java
index d4aec6b0..94f1707f 100644
--- a/fr.cnes.analysis.tools.export/src/fr/cnes/analysis/tools/export/IExportService.java
+++ b/fr.cnes.analysis.tools.export/src/fr/cnes/analysis/tools/export/IExportService.java
@@ -82,4 +82,32 @@ public boolean hasParameters(String formatExtension)
*/
public Map getParameters(String formatExtension)
throws NoContributorMatchingException, CoreException;
+
+ /**
+ * This function export each {@link CheckResult} of {@code checkResults}
+ * parameter into the {@link File} parameter.
+ *
+ * @param pCheckResults
+ * to export.
+ * @param pOutputFile
+ * to use for the export.
+ * @param pParameters
+ * parameter required by the export plugin.
+ * @param pFormat
+ * define the format of the results file.
+ * @throws NoContributorMatchingException
+ * when a format can not be handled by the @link
+ * {@link ExportService} service.
+ * @throws NoExtensionIndicatedException
+ * when the {@code outputFile} has no extension indicated.
+ * @throws IOException
+ * when the export failed due to a {@link java.io.File}
+ * exception.
+ * @throws CoreException
+ * when failing to create executable from contributor of
+ * {@link #EXPORT_EXTENSIONPOINT_ID}'s attribute
+ * {@link #EXPORT_EXTENSIONPOINT_ATTRIBUTE_EXPORTCLASS}.
+ */
+ void export(List pCheckResults, File pOutputFile, Map pParameters, String pFormat)
+ throws NoContributorMatchingException, NoExtensionIndicatedException, IOException, CoreException;
}
diff --git a/fr.cnes.analysis.tools.fortran77.metrics/META-INF/MANIFEST.MF b/fr.cnes.analysis.tools.fortran77.metrics/META-INF/MANIFEST.MF
index 6f109ecb..2f07183e 100755
--- a/fr.cnes.analysis.tools.fortran77.metrics/META-INF/MANIFEST.MF
+++ b/fr.cnes.analysis.tools.fortran77.metrics/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: i-Code CNES F77 Metrics
Bundle-SymbolicName: fr.cnes.analysis.tools.fortran77.metrics;singleton:=true
-Bundle-Version: 3.0.1.qualifier
+Bundle-Version: 3.1.0.qualifier
Bundle-Activator: fr.cnes.analysis.tools.fortran77.metrics.Activator
Require-Bundle: org.eclipse.core.runtime,
fr.cnes.analysis.tools.analyzer;bundle-version="2.0.0"
diff --git a/fr.cnes.analysis.tools.fortran77.metrics/lex/F77METLineOfComment.lex b/fr.cnes.analysis.tools.fortran77.metrics/lex/F77METLineOfComment.lex
new file mode 100644
index 00000000..88332677
--- /dev/null
+++ b/fr.cnes.analysis.tools.fortran77.metrics/lex/F77METLineOfComment.lex
@@ -0,0 +1,307 @@
+/************************************************************************************************/
+/* i-Code CNES is a static code analyzer. */
+/* This software is a free software, under the terms of the Eclipse Public License version 1.0. */
+/* http://www.eclipse.org/legal/epl-v10.html */
+/************************************************************************************************/
+
+/********************************************************************************/
+/* This file is used to generate a metric checker for comment's rate. For */
+/* further information on this, we advise you to refer to CNES manual dealing */
+/* with metrics. */
+/* As many comments have been done on the RATEComment.lex file, this file */
+/* will restrain its comments on modifications. */
+/* */
+/********************************************************************************/
+
+package fr.cnes.analysis.tools.fortran77.metrics;
+
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.util.List;
+import java.io.File;
+import java.util.logging.Logger;
+
+
+import org.eclipse.core.runtime.Path;
+
+import fr.cnes.analysis.tools.analyzer.datas.AbstractChecker;
+import fr.cnes.analysis.tools.analyzer.datas.CheckResult;
+import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
+%%
+
+%class F77METLineOfComment
+%extends AbstractChecker
+%public
+%ignorecase
+%column
+%line
+
+
+%function run
+%yylexthrow JFlexException
+%type List
+
+
+%state COMMENT, NAMING, NEW_LINE, LINE, AVOID, DECL
+
+/* We add TYPE notion, which represent FUNC, PROC, SUB, MOD and PROG. */
+/* We also add END, which is used to ignore end of function, etc. */
+COMMENT_WORD = \! | "c" |\*
+TYPE = "function" | "procedure" | "subroutine" | "program" | "module" |"interface"
+FALSE = [a-zA-Z0-9\_]({TYPE}) | ({TYPE})[a-zA-Z0-9\_] | [a-zA-Z0-9\_]({TYPE})[a-zA-Z0-9\_]
+ | [^a-zA-Z0-9\_]("module")({SPACE}*)("procedure")[^a-zA-Z0-9\_]
+SPACE = [\ \t\f]
+VAR = [a-zA-Z][a-zA-Z0-9\_]*
+STRING = \'[^\']*\' | \"[^\"]*\"
+
+END = END | end
+
+%{
+ private static final Logger LOGGER = Logger.getLogger(F77METLineOfComment.class.getName());
+
+
+ String location = "MAIN PROGRAM";
+ private String parsedFileName;
+ Float numLines = 0.0f;
+ Float numComments = 0.0f;
+ Float numCommentTotal = 0.0f;
+ boolean endLine = true;
+ int functionLine = 0;
+
+
+
+ public F77METLineOfComment() {
+ }
+
+ @Override
+ public void setInputFile(File file) throws FileNotFoundException {
+ super.setInputFile(file);
+ LOGGER.finest("begin method setInputFile");
+ this.parsedFileName = file.toString();
+ this.zzReader = new FileReader(new Path(file.getAbsolutePath()).toOSString());
+ this.parsedFileName = file.toString();
+ LOGGER.finest("end method setInputFile");
+ }
+
+ private void endLocation() throws JFlexException{
+ LOGGER.finest("begin method endLocation");
+ final List list = this.getCheckResults();
+ if (list.isEmpty()) {
+
+ this.computeMetric(location, numComments, functionLine+1);
+
+ } else {
+ final CheckResult last = list.get(list.size() - 1);
+ if (last.getLocation().equals(location)) {
+
+ last.setValue(numComments);
+
+ } else {
+
+ this.computeMetric(location, numComments, functionLine+1);
+
+ }
+ }
+ LOGGER.finest("end method endLocation");
+ }
+
+%}
+
+/* At the end of analysis, atEOF is set at true. This is not meant to be modified. */
+%eofval{
+ this.computeMetric(null, numCommentTotal, 0);
+ return getCheckResults();
+%eofval}
+
+%%
+
+/*********************/
+/* COMMENT PART */
+/*********************/
+
+ {
+ (\n|\r)+ {
+
+ numComments++;
+ numCommentTotal++;
+ numLines++;
+ LOGGER.finest("Setting values [numComments ="+numComments+" | numLines = "+ numLines+"]");
+ LOGGER.finest("COMMENT -> NEW_LINE (Transition : \\n | \\r)");
+ yybegin(NEW_LINE);
+ }
+ . {}
+ }
+
+/*****************/
+/* AVOID PART */
+/*****************/
+
+ {
+ (\n|\r)+ {
+ numLines++;
+ LOGGER.finest("Setting value [numLines ="+numLines+"]");
+ LOGGER.finest("AVOID -> NEW_LINE (Transition : \\n | \\r)");
+ yybegin(NEW_LINE);
+ }
+ . {}
+ }
+
+/*****************/
+/* NAMING PART */
+/*****************/
+
+ {
+ {VAR} {
+ numLines = 0.0f;
+ numComments = 0.0f;
+ functionLine = yyline;
+ location = location + " " + yytext();
+ LOGGER.finest("Setting values [numComments ="+numComments+" | numLines = "+ numLines+" | functionLine = "+ functionLine+" | location = "+ location+"]");
+ LOGGER.finest("NAMING -> DECL (Transition : VAR)");
+ yybegin(DECL);
+ }
+ (\n|\r)+ {
+ LOGGER.finest("NAMING -> NEW_LINE (Transition : \\n | \\r)");
+ yybegin(NEW_LINE);
+ }
+ . {}
+ }
+
+/*****************/
+/* DECL STATE */
+/*****************/
+
+ {
+ "&"{SPACE}*[^\n\r] {}
+ "&" {
+ endLine = false;
+ LOGGER.finest("Setting value [endLine ="+endLine+"]");
+ }
+ (\n|\r)+ {
+ if (endLine) {
+ LOGGER.finest("DECL -> NEW_LINE (Transition : \\n | \\r && endLine = true)");
+ yybegin(NEW_LINE);
+ }
+ endLine = true;
+ LOGGER.finest("Setting value [endLine ="+endLine+"]");
+ }
+ . {}
+
+ }
+
+/*********************/
+/* INITIAL STATE */
+/*********************/
+
+ {
+ {COMMENT_WORD} {
+ LOGGER.finest("YYINITIAL -> COMMENT (Transition : COMMENT_WORD)");
+ yybegin(COMMENT);
+ }
+ {STRING} {
+ LOGGER.finest("YYINITIAL -> LINE (Transition : STRING)");
+ yybegin(LINE);
+ }
+ {FALSE} {
+ LOGGER.finest("YYINITIAL -> LINE (Transition : FALSE)");
+ yybegin(LINE);
+ }
+ {TYPE} {
+ location = yytext();
+ LOGGER.finest("Setting value [location ="+location+"]");
+ LOGGER.finest("YYINITIAL -> NAMING (Transition : TYPE)");
+ yybegin(NAMING);
+ }
+ {SPACE} {
+ LOGGER.finest("YYINITIAL -> NEW_LINE (Transition : SPACE)");
+ yybegin(NEW_LINE);
+ }
+ (\n|\r)+ {
+ numLines = numLines + 1;
+ LOGGER.finest("Setting value [numLines ="+numLines+"]");
+ LOGGER.finest("YYINITIAL -> NEW_LINE (Transition : \\n | \\r)");
+ yybegin(NEW_LINE);
+ }
+ . {
+ LOGGER.finest("YYINITIAL -> NEW_LINE (Transition : .)");
+ yybegin(LINE);
+ }
+ }
+
+/*********************/
+/* NEW_LINE STATE */
+/*********************/
+
+ {
+ {COMMENT_WORD} {
+ if (yycolumn == 0) {
+ LOGGER.finest("NEW_LINE -> COMMENT (Transition : COMMENT_WORD && yycolumn == 0)");
+ yybegin(COMMENT);
+ } else {
+ LOGGER.finest("NEW_LINE -> LINE (Transition : COMMENT_WORD && yycolumn != 0)");
+ yybegin(LINE);
+ }
+ }
+ {STRING} {
+ LOGGER.finest("NEW_LINE -> LINE (Transition : STRING");
+ yybegin(LINE);
+ }
+ {FALSE} {
+ LOGGER.finest("NEW_LINE -> LINE (Transition : FALSE");
+ yybegin(LINE);
+ }
+ {TYPE} {
+ location = yytext();
+ LOGGER.finest("Setting value [location ="+location+"]");
+ LOGGER.finest("NEW_LINE -> NAMING (Transition : TYPE");
+ yybegin(NAMING);
+ }
+ {END} {
+ endLocation();
+ LOGGER.finest("NEW_LINE -> AVOID (Transition : END");
+ yybegin(AVOID);
+ }
+ {SPACE} {}
+ (\n|\r)+ {}
+ . {
+ LOGGER.finest("NEW_LINE -> LINE (Transition : .");
+ yybegin(LINE);
+ }
+ }
+
+/*****************/
+/* LINE STATE */
+/*****************/
+
+ {
+ {STRING} {}
+ {FALSE} {}
+ {TYPE} {
+ location = yytext();
+ LOGGER.finest("Setting value [location ="+location+"]");
+ LOGGER.finest("LINE -> NAMING (Transition : TYPE");
+ yybegin(NAMING);
+ }
+ {END} {
+ endLocation();
+ LOGGER.finest("LINE -> AVOID (Transition : END");
+ yybegin(AVOID);
+ }
+ (\n|\r)+ {
+ numLines = numLines + 1;
+ LOGGER.finest("Setting value [numLines ="+numLines+"]");
+ LOGGER.finest("LINE -> NEW_LINE (Transition : \\n | \\r)");
+ yybegin(NEW_LINE);
+ }
+ . {}
+ }
+
+/*********************/
+/* ERROR THROWN */
+/*********************/
+ [^] {
+
+ final String errorMessage = "Analysis failure : Your file could not be analyzed. Please verify that it was encoded in an UNIX format.";
+ throw new JFlexException(this.getClass().getName(), parsedFileName,
+ errorMessage, yytext(), yyline, yycolumn);
+ }
\ No newline at end of file
diff --git a/fr.cnes.analysis.tools.fortran77.metrics/plugin.xml b/fr.cnes.analysis.tools.fortran77.metrics/plugin.xml
index 474ac61e..819db5b2 100755
--- a/fr.cnes.analysis.tools.fortran77.metrics/plugin.xml
+++ b/fr.cnes.analysis.tools.fortran77.metrics/plugin.xml
@@ -33,5 +33,12 @@
languageId="fr.cnes.analysis.tools.languages.f77"
name="F77.MET.RatioComment">
+
diff --git a/fr.cnes.analysis.tools.fortran77.metrics/pom.xml b/fr.cnes.analysis.tools.fortran77.metrics/pom.xml
index 6b2299d7..309c51b0 100644
--- a/fr.cnes.analysis.tools.fortran77.metrics/pom.xml
+++ b/fr.cnes.analysis.tools.fortran77.metrics/pom.xml
@@ -6,7 +6,7 @@
fr.cnes.icode
fr.cnes.icode.parent
- 3.0.1-SNAPSHOT
+ 3.1.0-SNAPSHOT
fr.cnes.analysis.tools.fortran77.metrics
diff --git a/fr.cnes.analysis.tools.fortran77.rules/META-INF/MANIFEST.MF b/fr.cnes.analysis.tools.fortran77.rules/META-INF/MANIFEST.MF
index 2f0833ff..ab56f482 100755
--- a/fr.cnes.analysis.tools.fortran77.rules/META-INF/MANIFEST.MF
+++ b/fr.cnes.analysis.tools.fortran77.rules/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: i-Code CNES F77 Rules
Bundle-SymbolicName: fr.cnes.analysis.tools.fortran77.rules;singleton:=true
-Bundle-Version: 3.0.1.qualifier
+Bundle-Version: 3.1.0.qualifier
Bundle-Activator: fr.cnes.analysis.tools.fortran77.rules.Activator
Require-Bundle: org.eclipse.core.runtime,
fr.cnes.analysis.tools.analyzer;bundle-version="2.0.0"
diff --git a/fr.cnes.analysis.tools.fortran77.rules/pom.xml b/fr.cnes.analysis.tools.fortran77.rules/pom.xml
index eeaf8068..8f7c5687 100644
--- a/fr.cnes.analysis.tools.fortran77.rules/pom.xml
+++ b/fr.cnes.analysis.tools.fortran77.rules/pom.xml
@@ -6,7 +6,7 @@
fr.cnes.icode
fr.cnes.icode.parent
- 3.0.1-SNAPSHOT
+ 3.1.0-SNAPSHOT
fr.cnes.analysis.tools.fortran77.rules
diff --git a/fr.cnes.analysis.tools.fortran90.metrics/META-INF/MANIFEST.MF b/fr.cnes.analysis.tools.fortran90.metrics/META-INF/MANIFEST.MF
index 37051b1f..f47f1535 100755
--- a/fr.cnes.analysis.tools.fortran90.metrics/META-INF/MANIFEST.MF
+++ b/fr.cnes.analysis.tools.fortran90.metrics/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: i-Code CNES F90 Metrics
Bundle-SymbolicName: fr.cnes.analysis.tools.fortran90.metrics;singleton:=true
-Bundle-Version: 3.0.1.qualifier
+Bundle-Version: 3.1.0.qualifier
Bundle-Activator: fr.cnes.analysis.tools.fortran90.metrics.Activator
Require-Bundle: org.eclipse.core.runtime,
fr.cnes.analysis.tools.analyzer;bundle-version="2.0.0"
diff --git a/fr.cnes.analysis.tools.fortran90.metrics/lex/F90METLineOfComment.lex b/fr.cnes.analysis.tools.fortran90.metrics/lex/F90METLineOfComment.lex
new file mode 100644
index 00000000..d7dbb022
--- /dev/null
+++ b/fr.cnes.analysis.tools.fortran90.metrics/lex/F90METLineOfComment.lex
@@ -0,0 +1,219 @@
+/************************************************************************************************/
+/* i-Code CNES is a static code analyzer. */
+/* This software is a free software, under the terms of the Eclipse Public License version 1.0. */
+/* http://www.eclipse.org/legal/epl-v10.html */
+/************************************************************************************************/
+
+/********************************************************************************/
+/* This file is used to generate a metric checker for comment's rate. For */
+/* further information on this, we advise you to refer to CNES manual dealing */
+/* with metrics. */
+/* As many comments have been done on the RATEComment.lex file, this file */
+/* will restrain its comments on modifications. */
+/* */
+/********************************************************************************/
+
+package fr.cnes.analysis.tools.fortran90.metrics;
+
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.File;
+import java.util.List;
+
+import org.eclipse.core.runtime.Path;
+
+import fr.cnes.analysis.tools.analyzer.datas.AbstractChecker;
+import fr.cnes.analysis.tools.analyzer.datas.CheckResult;
+import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
+
+%%
+
+%class F90METLineOfComment
+%extends AbstractChecker
+%public
+%ignorecase
+%column
+%line
+
+
+%function run
+%yylexthrow JFlexException
+%type List
+
+%state COMMENT, NAMING, NEW_LINE, LINE, AVOID, DECL
+
+/* We add TYPE notion, which represent FUNC, PROC, SUB, MOD and PROG. */
+/* We also add END, which is used to ignore end of function, etc. */
+COMMENT_WORD = \!
+TYPE = "function" | "procedure" | "subroutine" | "program" | "module" |"interface"
+FALSE = [a-zA-Z0-9\_]({TYPE}) | ({TYPE})[a-zA-Z0-9\_] | [a-zA-Z0-9\_]({TYPE})[a-zA-Z0-9\_]
+ | [^a-zA-Z0-9\_]("module")({SPACE}*)("procedure")[^a-zA-Z0-9\_]
+SPACE = [\ \t\f]
+VAR = [a-zA-Z][a-zA-Z0-9\_]*
+STRING = \'[^\']*\' | \"[^\"]*\"
+
+END = END | end
+
+%{
+ String location = "MAIN PROGRAM";
+ private String parsedFileName;
+ Float numLines = 0.0f;
+ Float numComments = 0.0f;
+ Float numCommentTotal = 0.0f;
+ int functionLine = 0;
+ boolean endLine = true;
+
+ public F90METLineOfComment() {
+ }
+
+ @Override
+ public void setInputFile(File file) throws FileNotFoundException {
+ super.setInputFile(file);
+ this.parsedFileName = file.toString();
+ this.zzReader = new FileReader(new Path(file.getAbsolutePath()).toOSString());
+ }
+ //
+ private void endLocation() throws JFlexException {
+ final List list = this.getCheckResults();
+ if (list.isEmpty()) {
+
+ this.computeMetric(location, numComments, functionLine + 1);
+
+ } else {
+ final CheckResult last = list.get(list.size() - 1);
+ if (last.getLocation().equals(location)) {
+
+ last.setValue(numComments);
+
+ } else {
+
+ this.computeMetric(location, numComments, functionLine + 1);
+
+ }
+ }
+
+
+
+
+
+ }
+
+%}
+
+/* At the end of analysis, atEOF is set at true. This is not meant to be modified. */
+%eofval{
+ this.computeMetric(null, numCommentTotal, 0);
+ return getCheckResults();
+%eofval}
+
+%%
+
+/*********************/
+/* COMMENT PART */
+/*********************/
+
+ {
+ (\n|\r)+ {numComments++;
+ numLines++;
+ numCommentTotal++;
+ yybegin(NEW_LINE);}
+ . {}
+ }
+
+/*****************/
+/* AVOID PART */
+/*****************/
+
+ {
+ (\n|\r)+ {numLines++;
+ yybegin(NEW_LINE);}
+ . {}
+ }
+
+/*****************/
+/* NAMING PART */
+/*****************/
+
+ {
+ {VAR} {numLines = 0.0f;
+ numComments = 0.0f;
+ location = location + " " + yytext();
+ yybegin(DECL);}
+ (\n|\r)+ {yybegin(NEW_LINE);}
+ . {}
+ }
+
+/*****************/
+/* DECL STATE */
+/*****************/
+
+ {
+ "&"{SPACE}*[^\n\r] {}
+ "&" {endLine = false;}
+ (\n|\r)+ {if (endLine) {
+ yybegin(NEW_LINE);
+ }
+ endLine = true;
+ }
+ . {}
+
+ }
+
+/*********************/
+/* INITIAL STATE */
+/*********************/
+
+ {
+ {COMMENT_WORD} {yybegin(COMMENT);}
+ {STRING} {yybegin(LINE);}
+ {FALSE} {yybegin(LINE);}
+ {TYPE} {location = yytext(); functionLine = yyline;
+ yybegin(NAMING);}
+ {SPACE} {yybegin(NEW_LINE);}
+ (\n|\r)+ {numLines = numLines + 1;
+ yybegin(NEW_LINE);}
+ . {yybegin(LINE);}
+ }
+
+/*********************/
+/* NEW_LINE STATE */
+/*********************/
+
+ {
+ {COMMENT_WORD} {yybegin(COMMENT);}
+ {STRING} {yybegin(LINE);}
+ {FALSE} {yybegin(LINE);}
+ {TYPE} {location = yytext(); functionLine = yyline;
+ yybegin(NAMING);}
+ {END} {endLocation();
+ yybegin(AVOID);}
+ {SPACE} {}
+ (\n|\r)+ {}
+ . {yybegin(LINE);}
+ }
+
+/*****************/
+/* LINE STATE */
+/*****************/
+
+ {
+ {STRING} {}
+ {FALSE} {}
+ {TYPE} {location = yytext(); functionLine = yyline;
+ yybegin(NAMING);}
+ {END} {endLocation();
+ yybegin(AVOID);}
+ (\n|\r)+ {numLines = numLines + 1;
+ yybegin(NEW_LINE);}
+ . {}
+ }
+
+/*********************/
+/* ERROR THROWN */
+/*********************/
+ [^] {
+
+ final String errorMessage = "Analysis failure : Your file could not be analyzed. Please verify that it was encoded in an UNIX format.";
+ throw new JFlexException(this.getClass().getName(), parsedFileName,
+ errorMessage, yytext(), yyline, yycolumn);
+ }
\ No newline at end of file
diff --git a/fr.cnes.analysis.tools.fortran90.metrics/plugin.xml b/fr.cnes.analysis.tools.fortran90.metrics/plugin.xml
index 4476e383..81b1aaab 100755
--- a/fr.cnes.analysis.tools.fortran90.metrics/plugin.xml
+++ b/fr.cnes.analysis.tools.fortran90.metrics/plugin.xml
@@ -34,5 +34,12 @@
languageId="fr.cnes.analysis.tools.languages.f90"
name="F90.MET.RatioComment">
+
diff --git a/fr.cnes.analysis.tools.fortran90.metrics/pom.xml b/fr.cnes.analysis.tools.fortran90.metrics/pom.xml
index 190a82ed..df895d71 100644
--- a/fr.cnes.analysis.tools.fortran90.metrics/pom.xml
+++ b/fr.cnes.analysis.tools.fortran90.metrics/pom.xml
@@ -6,7 +6,7 @@
fr.cnes.icode
fr.cnes.icode.parent
- 3.0.1-SNAPSHOT
+ 3.1.0-SNAPSHOT
fr.cnes.analysis.tools.fortran90.metrics
diff --git a/fr.cnes.analysis.tools.fortran90.rules/META-INF/MANIFEST.MF b/fr.cnes.analysis.tools.fortran90.rules/META-INF/MANIFEST.MF
index e3e0dda2..15dafc7e 100755
--- a/fr.cnes.analysis.tools.fortran90.rules/META-INF/MANIFEST.MF
+++ b/fr.cnes.analysis.tools.fortran90.rules/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: i-Code CNES F90 Rules
Bundle-SymbolicName: fr.cnes.analysis.tools.fortran90.rules;singleton:=true
-Bundle-Version: 3.0.1.qualifier
+Bundle-Version: 3.1.0.qualifier
Bundle-Activator: fr.cnes.analysis.tools.fortran90.rules.Activator
Require-Bundle: org.eclipse.core.runtime,
fr.cnes.analysis.tools.analyzer;bundle-version="2.0.0"
diff --git a/fr.cnes.analysis.tools.fortran90.rules/pom.xml b/fr.cnes.analysis.tools.fortran90.rules/pom.xml
index ec528c0e..cdcf9557 100644
--- a/fr.cnes.analysis.tools.fortran90.rules/pom.xml
+++ b/fr.cnes.analysis.tools.fortran90.rules/pom.xml
@@ -6,7 +6,7 @@
fr.cnes.icode
fr.cnes.icode.parent
- 3.0.1-SNAPSHOT
+ 3.1.0-SNAPSHOT
fr.cnes.analysis.tools.fortran90.rules
diff --git a/fr.cnes.analysis.tools.languages/META-INF/MANIFEST.MF b/fr.cnes.analysis.tools.languages/META-INF/MANIFEST.MF
index c237aef4..03ae68d4 100644
--- a/fr.cnes.analysis.tools.languages/META-INF/MANIFEST.MF
+++ b/fr.cnes.analysis.tools.languages/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Languages
Bundle-SymbolicName: fr.cnes.analysis.tools.languages;singleton:=true
-Bundle-Version: 3.0.1.qualifier
+Bundle-Version: 3.1.0.qualifier
Bundle-Activator: fr.cnes.analysis.tools.languages.Activator
Bundle-Vendor: CNES
Require-Bundle: org.eclipse.core.runtime,
diff --git a/fr.cnes.analysis.tools.languages/pom.xml b/fr.cnes.analysis.tools.languages/pom.xml
index a7361c27..7d3f66c5 100644
--- a/fr.cnes.analysis.tools.languages/pom.xml
+++ b/fr.cnes.analysis.tools.languages/pom.xml
@@ -6,7 +6,7 @@
fr.cnes.icode
fr.cnes.icode.parent
- 3.0.1-SNAPSHOT
+ 3.1.0-SNAPSHOT
fr.cnes.analysis.tools.languages
diff --git a/fr.cnes.analysis.tools.shell.metrics/META-INF/MANIFEST.MF b/fr.cnes.analysis.tools.shell.metrics/META-INF/MANIFEST.MF
index 0550c4d4..912228ab 100755
--- a/fr.cnes.analysis.tools.shell.metrics/META-INF/MANIFEST.MF
+++ b/fr.cnes.analysis.tools.shell.metrics/META-INF/MANIFEST.MF
@@ -2,10 +2,11 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: i-Code CNES SH Metrics
Bundle-SymbolicName: fr.cnes.analysis.tools.shell.metrics;singleton:=true
-Bundle-Version: 3.0.1.qualifier
+Bundle-Version: 3.1.0.qualifier
Bundle-Activator: fr.cnes.analysis.tools.shell.metrics.Activator
Require-Bundle: org.eclipse.core.runtime,
fr.cnes.analysis.tools.analyzer;bundle-version="2.0.0"
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-Vendor: CNES
+Export-Package: fr.cnes.analysis.tools.shell.metrics
diff --git a/fr.cnes.analysis.tools.shell.metrics/lex/SHMETLineOfComment.lex b/fr.cnes.analysis.tools.shell.metrics/lex/SHMETLineOfComment.lex
new file mode 100644
index 00000000..56a47b94
--- /dev/null
+++ b/fr.cnes.analysis.tools.shell.metrics/lex/SHMETLineOfComment.lex
@@ -0,0 +1,382 @@
+/************************************************************************************************/
+/* i-Code CNES is a static code analyzer. */
+/* This software is a free software, under the terms of the Eclipse Public License version 1.0. */
+/* http://www.eclipse.org/legal/epl-v10.html */
+/************************************************************************************************/
+
+/********************************************************************************/
+/* This file is used to generate a metric checker for comment's rate. For */
+/* further information on this, we advise you to refer to CNES manual dealing */
+/* with metrics. */
+/* As many comments have been done on the MAXImbric.lex file, this file */
+/* will restrain its comments on modifications. */
+/* */
+/********************************************************************************/
+
+package fr.cnes.analysis.tools.shell.metrics;
+
+import fr.cnes.analysis.tools.analyzer.datas.AbstractChecker;
+import fr.cnes.analysis.tools.analyzer.datas.CheckResult;
+import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+
+import java.util.EmptyStackException;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Stack;
+
+import java.util.logging.Logger;
+
+import org.eclipse.core.runtime.Path;
+
+%%
+
+%class SHMETLineOfComment
+%extends AbstractChecker
+%public
+%column
+%line
+
+
+%function run
+%yylexthrow JFlexException
+%type List
+
+%state COMMENT, NAMING, BEGINFUNC, STRING, COMMAND
+
+COMMENT_WORD = [\#]
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FUNCTION = "function"
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
+SPACE = [\ \r\t\f\space]
+NAME = [a-zA-Z\_][a-zA-Z0-9\_]*
+SHELL_VAR = ([0-9]+|[\-\@\?\#\!\_\*\$])
+EXPANDED_VAR = [\$][\{](([\:]{SPACE}*[\-])|[a-zA-Z0-9\_\:\%\=\+\?\/\!\-\,\^\#\*\@]|([\[](([\:]{SPACE}*[\-])|[a-zA-Z0-9\_\/\:\%\=\+\?\!\$\-\,\^\#\*\@\[\]\{\}])+[\]]))+[\}]
+VAR = {NAME}|{EXPANDED_VAR}|([\$]({NAME}|{SHELL_VAR}))
+IGNORE_COMMAND = \\`
+COMMAND = \`
+STRING_D = \"
+IGNORE_STRING_D = \\\"
+STRING_S = \'
+IGNORE_STRING_S = \\\'
+IGNORE = {IGNORE_STRING_D} | {IGNORE_STRING_S} | {IGNORE_COMMAND}
+FUNCSTART = \{ | \( | \(\( | \[\[ | "if" | "case" | "select" | "for" | "while" | "until"
+FUNCEND = \} | \) | \)\) | \]\] | "fi" | "esac" | "done"
+
+%{
+ private String location = "MAIN PROGRAM";
+ private String parsedFileName;
+ private List identifiers = new LinkedList();
+ private float lines=0;
+ private boolean emptyLine = true;
+ private boolean inStringSimpleQuoted = false;
+ private boolean inStringDoubleQuoted = false;
+ private float lastLinesCommented = 0;
+ private int functionLine;
+ private float commentLinesMain=0;
+ private float commentLinesTotal=0;
+ private float linesMain=0;
+ private float linesTotal=0;
+ private Stack functionStack = new Stack<>();
+ private static final Logger LOGGER = Logger.getLogger(SHMETLineOfComment.class.getName());
+
+ public SHMETLineOfComment(){
+ }
+
+ @Override
+ public void setInputFile(File file) throws FileNotFoundException {
+ super.setInputFile(file);
+ LOGGER.fine("begin method setInputFile");
+ this.parsedFileName = file.toString();
+ this.zzReader = new FileReader(new Path(file.getAbsolutePath()).toOSString());
+ LOGGER.fine("end method setInputFile");
+ }
+
+ private void endLocation() throws JFlexException {
+ LOGGER.fine("begin method endLocation");
+ try{
+ FunctionLineOfComment functionFinished = functionStack.pop();
+ LOGGER.fine("["+ this.getInputFile().getAbsolutePath()+":"+(yyline+1)+":"+yycolumn+"] computing function :"+functionFinished.getName()+" line :"+ functionFinished.getBeginLine()+" with value : "+(functionFinished.getLineOfComment()/functionFinished.getLineOfCode())*100);
+ this.computeMetric(functionFinished.getName(), functionFinished.getLineOfComment(), functionFinished.getBeginLine());
+
+ if(functionStack.empty()){
+ linesMain+=functionFinished.getLineOfCode();
+ commentLinesMain+=functionFinished.getLineOfComment();
+ }else{
+ FunctionLineOfComment function = functionStack.peek();
+ function.setLineOfCode(function.getLineOfCode()+functionFinished.getLineOfCode());
+ function.setLineOfComment(function.getLineOfComment()+functionFinished.getLineOfComment());
+ }
+ }catch(EmptyStackException e){
+
+ final String errorMessage = e.getMessage();
+ throw new JFlexException(this.getClass().getName(), parsedFileName,
+ errorMessage, yytext(), yyline, yycolumn);
+ }
+ LOGGER.fine("end method setInputFile");
+ }
+
+ private void addLines(){
+ LOGGER.fine("begin method addLines");
+ if(!emptyLine){
+ if(functionStack.empty()){
+ LOGGER.fine("["+ this.getInputFile().getAbsolutePath()+":"+(yyline+1)+":"+yycolumn+"] counting one line to MAIN PROGRAM");
+ linesMain++;
+ } else {
+ LOGGER.fine("["+ this.getInputFile().getAbsolutePath()+":"+(yyline+1)+":"+yycolumn+"] counting one line to the function "+ functionStack.peek().getName());
+ functionStack.peek().addLineOfCode();
+ }
+ LOGGER.fine("["+ this.getInputFile().getAbsolutePath()+":"+(yyline+1)+":"+yycolumn+"] counting one line for the whole file");
+ linesTotal++;
+ }
+ LOGGER.fine("end method addLines");
+ }
+ private void addCommentLines(){
+ LOGGER.fine("begin method addCommentLines");
+ if(functionStack.empty()){
+ LOGGER.fine("["+ this.getInputFile().getAbsolutePath()+":"+(yyline+1)+":"+yycolumn+"] counting one comment line to MAIN PROGRAM");
+ commentLinesMain++;
+ } else {
+ LOGGER.fine("["+ this.getInputFile().getAbsolutePath()+":"+(yyline+1)+":"+yycolumn+"] counting one comment line to the function "+ functionStack.peek().getName());
+ functionStack.peek().addLineOfComment();
+ }
+ LOGGER.fine("["+ this.getInputFile().getAbsolutePath()+":"+(yyline+1)+":"+yycolumn+"] counting one comment line for the whole file");
+ commentLinesTotal++;
+ LOGGER.fine("end method addLines");
+ }
+
+%}
+
+%eofval{
+ if(functionStack.empty()){
+ this.computeMetric("MAIN PROGRAM", commentLinesMain, 1);
+ }else{
+
+ final String errorMessage = "Analysis failure : At least one function is not ending correctly.";
+ throw new JFlexException(this.getClass().getName(), parsedFileName,
+ errorMessage, yytext(), yyline, yycolumn);
+ }
+ this.computeMetric(null, commentLinesTotal, 0);
+
+ return getCheckResults();
+%eofval}
+%%
+
+/************************/
+/* COMMENT STATE */
+/************************/
+
+ {
+ \n {
+ lastLinesCommented++;
+ //Count pending the value of emptyline (as the comment might be on the right side of some code)
+ addLines();
+ addCommentLines();
+ emptyLine=true;
+ LOGGER.fine("["+ this.getInputFile().getAbsolutePath()+":"+(yyline+1)+":"+yycolumn+"] - COMMENT -> YYINITIAL (Transition : \\n )");
+ yybegin(YYINITIAL);
+ }
+ . | {SPACE} { }
+ }
+
+/************************/
+/* YYINITIAL STATE */
+/************************/
+
+ {
+
+
+ {COMMENT_WORD} {
+ LOGGER.fine("["+ this.getInputFile().getAbsolutePath()+":"+(yyline+1)+":"+yycolumn+"] - YYINITIAL -> COMMENT (Transition : COMMENT_WORD \""+yytext()+"\" )");
+ yybegin(COMMENT);
+ }
+ {FUNCTION} {
+ emptyLine = false;
+ LOGGER.fine("["+ this.getInputFile().getAbsolutePath()+":"+(yyline+1)+":"+yycolumn+"] - YYINITIAL -> NAMING (Transition : FUNCTION \""+yytext()+"\" )");
+ yybegin(NAMING);
+ }
+ {FUNCT} {
+ emptyLine = false;
+ functionLine = yyline+1;
+ location = yytext().substring(0,yytext().length()-2).trim();
+ LOGGER.fine("["+ this.getInputFile().getAbsolutePath()+":"+(yyline+1)+":"+yycolumn+"] - YYINITIAL -> BEGINFUNC (Transition : FUNCT \""+yytext()+"\" )");
+ yybegin(BEGINFUNC);
+ }
+
+ {FUNCSTART} {
+ emptyLine = false;
+ if(!functionStack.empty()){
+ if(functionStack.peek().getFinisher().equals(Function.finisherOf(yytext()))){
+ LOGGER.fine("["+ this.getInputFile().getAbsolutePath()+":"+(yyline+1)+":"+yycolumn+"] - [YYINITIAL] addStarterRepetition() for FUNCSTART \""+yytext()+"\" )");
+ functionStack.peek().addStarterRepetition();
+ }
+ LOGGER.fine("["+ this.getInputFile().getAbsolutePath()+":"+(yyline+1)+":"+yycolumn+"] - [YYINITIAL] do nothing for FUNCSTART \""+yytext()+"\" )");
+ }
+ }
+ {FUNCEND} {
+ lastLinesCommented=0;
+ emptyLine = false;
+ if(!functionStack.empty()){
+ if(functionStack.peek().isFinisher(yytext())){
+ if(functionStack.peek().getStarterRepetition()>0) {
+ LOGGER.fine("["+ this.getInputFile().getAbsolutePath()+":"+(yyline+1)+":"+yycolumn+"] - [YYINITIAL] removeStarterRepetition() for FUNCEND \""+yytext()+"\" )");
+ try{
+ functionStack.peek().removeStarterRepetition();
+ }catch(JFlexException e){
+
+ final String errorMessage = e.getMessage();
+ throw new JFlexException(this.getClass().getName(), parsedFileName,
+ errorMessage, yytext(), yyline, yycolumn);
+ }
+ } else {
+ LOGGER.fine("["+ this.getInputFile().getAbsolutePath()+":"+(yyline+1)+":"+yycolumn+"] - [YYINITIAL] endLocation() for FUNCEND \""+yytext()+"\" )");
+ addLines();
+ emptyLine=true;
+ endLocation();
+ }
+ }
+ }
+ }
+ {VAR} {
+ lastLinesCommented=0;
+ LOGGER.fine("["+ this.getInputFile().getAbsolutePath()+":"+(yyline+1)+":"+yycolumn+"] - [YYINITIAL] do nothing for VAR \""+yytext()+"\" )");
+ emptyLine = false;
+ }
+ {IGNORE} {
+ lastLinesCommented=0;
+ LOGGER.fine("["+ this.getInputFile().getAbsolutePath()+":"+(yyline+1)+":"+yycolumn+"] - [YYINITIAL] do nothing for IGNORE \""+yytext()+"\" )");
+ emptyLine = false;
+ }
+ {COMMAND} {
+ lastLinesCommented=0;
+ emptyLine = false;
+ LOGGER.fine("["+ this.getInputFile().getAbsolutePath()+":"+(yyline+1)+":"+yycolumn+"] - YYINITIAL -> COMMAND (Transition : COMMAND \""+yytext()+"\" )");
+ yybegin(COMMAND);
+ }
+ {STRING_S} {
+ lastLinesCommented=0;
+ emptyLine = false;
+ inStringSimpleQuoted = true;
+ LOGGER.fine("["+ this.getInputFile().getAbsolutePath()+":"+(yyline+1)+":"+yycolumn+"] - YYINITIAL -> STRING (Transition : STRING_S \""+yytext()+"\" )");
+ yybegin(STRING);
+ }
+ {STRING_D} {
+ lastLinesCommented=0;
+ emptyLine = false;
+ inStringDoubleQuoted = true;
+ LOGGER.fine("["+ this.getInputFile().getAbsolutePath()+":"+(yyline+1)+":"+yycolumn+"] - YYINITIAL -> STRING (Transition : STRING_D \""+yytext()+"\" )");
+ yybegin(STRING);
+ }
+
+ \n {
+ lastLinesCommented=0;
+ addLines();
+ emptyLine=true;
+ }
+ {SPACE} { }
+ . {
+ lastLinesCommented=0;
+ emptyLine = false;
+ }
+ }
+
+
+/************************/
+/* NAMING STATE */
+/************************/
+
+ {
+ {VAR} {
+ emptyLine = false;
+ location = yytext();
+ functionLine = yyline+1;
+ LOGGER.fine("["+ this.getInputFile().getAbsolutePath()+":"+(yyline+1)+":"+yycolumn+"] - NAMING -> BEGINFUNC (Transition : VAR \""+yytext()+"\" )");
+ yybegin(BEGINFUNC);
+ }
+ \n {
+ addLines();
+ emptyLine = true;
+ LOGGER.fine("["+ this.getInputFile().getAbsolutePath()+":"+(yyline+1)+":"+yycolumn+"] - NAMING -> YYINITIAL (Transition : \\n )");
+ yybegin(YYINITIAL);
+ }
+ . | {SPACE} {}
+ }
+
+/************************/
+/* BEGINFUNC STATE */
+/************************/
+/*
+ * This state target is to retrieve the function starter. For more information on fonction starter, have a look on {@link Function} class.
+ * Pending this starter, the function ender can be defined.
+ *
+ */
+
+ {
+ \(\) {}
+ {FUNCSTART} {
+ FunctionLineOfComment function = new FunctionLineOfComment(location, functionLine, yytext());
+ if(lastLinesCommented>0){
+ LOGGER.fine("["+ this.getInputFile().getAbsolutePath()+":"+(yyline+1)+":"+yycolumn+"] - [BEGINFUNC] Transfering "+ lastLinesCommented +" lines detected as header comment from the last function to the new one. )");
+ if(functionStack.empty()){
+ commentLinesMain-=lastLinesCommented;
+ }else{
+ functionStack.peek().setLineOfComment(functionStack.peek().getLineOfComment() - lastLinesCommented);
+ }
+ function.setLineOfComment(lastLinesCommented);
+ lastLinesCommented = 0;
+ }
+ LOGGER.fine("["+ this.getInputFile().getAbsolutePath()+":"+(yyline+1)+":"+yycolumn+"] - [BEGINFUNC] push("+location+") for FUNCSTART \""+yytext()+"\" )");
+ functionStack.push(function);
+ LOGGER.fine("["+ this.getInputFile().getAbsolutePath()+":"+(yyline+1)+":"+yycolumn+"] - BEGINFUNC -> YYINITIAL (Transition : FUNCSTART \""+yytext()+"\" )");
+ yybegin(YYINITIAL);
+ }
+ [^]|{SPACE} {}
+ }
+/************************/
+/* COMMAND STATE */
+/************************/
+
+ {
+ \n {
+ LOGGER.fine("["+ this.getInputFile().getAbsolutePath()+":"+(yyline+1)+":"+yycolumn+"] - [COMMAND] count line for \\n");
+ addLines();
+ }
+ {COMMAND} {
+ LOGGER.fine("["+ this.getInputFile().getAbsolutePath()+":"+(yyline+1)+":"+yycolumn+"] - COMMAND -> YYINITIAL (Transition : COMMAND \""+yytext()+"\" )");
+ yybegin(YYINITIAL);
+ }
+ . | {SPACE} { }
+ }
+/************************/
+/* STRING STATE */
+/************************/
+
+ {
+ \n {
+ LOGGER.fine("["+ this.getInputFile().getAbsolutePath()+":"+(yyline+1)+":"+yycolumn+"] - [STRING] count line for \\n");
+ addLines();
+ }
+ {IGNORE} {
+ LOGGER.fine("["+ this.getInputFile().getAbsolutePath()+":"+(yyline+1)+":"+yycolumn+"] - [STRING] do nothing for IGNORE \""+yytext()+"\" )");
+ }
+ {STRING_S} {
+ if(inStringSimpleQuoted){
+ inStringSimpleQuoted=false;
+ LOGGER.fine("["+ this.getInputFile().getAbsolutePath()+":"+(yyline+1)+":"+yycolumn+"] - STRING -> YYINITIAL (Transition : STRING_S \""+yytext()+"\" )");
+ yybegin(YYINITIAL);
+ }
+
+ }
+ {STRING_D} {
+ if(inStringDoubleQuoted){
+ inStringDoubleQuoted=false;
+ LOGGER.fine("["+ this.getInputFile().getAbsolutePath()+":"+(yyline+1)+":"+yycolumn+"] - STRING -> YYINITIAL (Transition : STRING_D \""+yytext()+"\" )");
+ yybegin(YYINITIAL);
+ }
+
+ }
+ . | {SPACE} { }
+ }
diff --git a/fr.cnes.analysis.tools.shell.metrics/plugin.xml b/fr.cnes.analysis.tools.shell.metrics/plugin.xml
index 4fc59342..65bf6fb5 100755
--- a/fr.cnes.analysis.tools.shell.metrics/plugin.xml
+++ b/fr.cnes.analysis.tools.shell.metrics/plugin.xml
@@ -34,5 +34,12 @@
languageId="fr.cnes.analysis.tools.languages.shell"
name="SH.MET.RatioComment">
+
diff --git a/fr.cnes.analysis.tools.shell.metrics/pom.xml b/fr.cnes.analysis.tools.shell.metrics/pom.xml
index a4d6abb1..8cec3668 100644
--- a/fr.cnes.analysis.tools.shell.metrics/pom.xml
+++ b/fr.cnes.analysis.tools.shell.metrics/pom.xml
@@ -6,7 +6,7 @@
fr.cnes.icode
fr.cnes.icode.parent
- 3.0.1-SNAPSHOT
+ 3.1.0-SNAPSHOT
fr.cnes.analysis.tools.shell.metrics
diff --git a/fr.cnes.analysis.tools.shell.rules/META-INF/MANIFEST.MF b/fr.cnes.analysis.tools.shell.rules/META-INF/MANIFEST.MF
index 38a53b37..a3f84637 100755
--- a/fr.cnes.analysis.tools.shell.rules/META-INF/MANIFEST.MF
+++ b/fr.cnes.analysis.tools.shell.rules/META-INF/MANIFEST.MF
@@ -2,10 +2,11 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: i-Code CNES SH Rules
Bundle-SymbolicName: fr.cnes.analysis.tools.shell.rules;singleton:=true
-Bundle-Version: 3.0.1.qualifier
+Bundle-Version: 3.1.0.qualifier
Bundle-Activator: fr.cnes.analysis.tools.shell.rules.Activator
Require-Bundle: org.eclipse.core.runtime,
- fr.cnes.analysis.tools.analyzer;bundle-version="2.0.0"
+ fr.cnes.analysis.tools.analyzer;bundle-version="2.0.0",
+ fr.cnes.analysis.tools.shell.metrics;bundle-version="3.1.0"
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-Vendor: CNES
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/COMDATAInitialisation.lex b/fr.cnes.analysis.tools.shell.rules/lex/COMDATAInitialisation.lex
index e386fc18..399fa110 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/COMDATAInitialisation.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/COMDATAInitialisation.lex
@@ -20,12 +20,15 @@ import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.EmptyStackException;
+import java.util.Stack;
import org.eclipse.core.runtime.Path;
import fr.cnes.analysis.tools.analyzer.datas.AbstractChecker;
import fr.cnes.analysis.tools.analyzer.datas.CheckResult;
import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
+import fr.cnes.analysis.tools.shell.metrics.Function;
%%
@@ -40,12 +43,24 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
%type List
-%state COMMENT, NAMING, WRITE, STRING, FORLOOP, READ
+%state COMMENT, NAMING, WRITE, STRING, FORLOOP, READ, BEGINFUNC
COMMENT_WORD = \#
-FUNC = "function"
-SPACE = [\ \r\t\f]
-VAR = [a-zA-Z][a-zA-Z0-9\_]*
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FUNCTION = "function"
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
+NAME = [a-zA-Z\_][a-zA-Z0-9\_]*
+SPACE = [\ \r\t\f]
+SHELL_VAR = ([0-9]+|[\-\@\?\#\!\_\*\$])
+EXPANDED_VAR = [\$][\{](([\:]{SPACE}*[\-])|[a-zA-Z0-9\_\:\%\=\+\?\/\!\-\,\^\#\*\@]|([\[](([\:]{SPACE}*[\-])|[a-zA-Z0-9\_\/\:\%\=\+\?\!\$\-\,\^\#\*\@\[\]\{\}])+[\]]))+[\}]
+VAR = {NAME}|{EXPANDED_VAR}|([\$]({NAME}|{SHELL_VAR}))
+
+FOR = "for"
+
+FUNCSTART = \{ | \( | \(\( | \[\[ | "if" | "case" | "select" | "for" | "while" | "until"
+FUNCEND = \} | \) | \)\) | \]\] | "fi" | "esac" | "done"
+
+
FILEEXIST = \[{SPACE}+{OPTION}{SPACE}+(\")?(\{)?\$(\{)?{VAR}(\})?(\")?
OPTION = \- ("a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "k" |
"p" | "r" | "s" | "u" | "w" | "x" | "O" | "G" | "L" |
@@ -53,8 +68,21 @@ OPTION = \- ("a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "k" |
%{
- String location = "MAIN PROGRAM";
- List variables = new ArrayList();
+ /* MAINPROGRAM: constant for main program localisation */
+ private static final String MAINPROGRAM = "MAIN PROGRAM";
+
+ /* FunctionWithVariables is used here with only initialized variables in locals and glabals */
+ private Stack functionStack = new Stack<>();
+
+ /* location: the current function name, or main program, that is the initial value */
+ private String location = MAINPROGRAM;
+ /* functionLine: the beginning line of the function */
+ int functionLine = 0;
+
+ /* parsedFileName: name of the current file */
+ private String parsedFileName;
+
+ List globalVariables = new ArrayList();
public COMDATAInitialisation() {
/** Initialize list with system variables **/
@@ -64,15 +92,80 @@ OPTION = \- ("a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "k" |
"MACHTYPE", "OLDPWD", "OSTYPE", "PATH", "PIPESTATUS", "PPID", "PROMPT_COMMAND",
"PS1", "PS2", "PS3", "PS4", "PWD", "REPLY", "SECONDS", "SHELLOPTS", "SHLVL", "TMOUT",
"UID" };
- variables.addAll(Arrays.asList(systemVariables));
+ globalVariables.addAll(Arrays.asList(systemVariables));
}
@Override
public void setInputFile(final File file) throws FileNotFoundException {
super.setInputFile(file);
+ this.parsedFileName = file.toString();
this.zzReader = new FileReader(new Path(file.getAbsolutePath()).toOSString());
}
-
+
+ private void endLocation() throws JFlexException {
+ try{
+ Function functionFinished = functionStack.pop();
+ if (!functionStack.empty()) {
+ /* there is a current function: change location to this function */
+ location = functionStack.peek().getName();
+ } else {
+ /* we are in the main program: change location to main */
+ location = MAINPROGRAM;
+ }
+ }catch(EmptyStackException e){
+ final String errorMessage = e.getMessage();
+ throw new JFlexException(this.getClass().getName(), parsedFileName,
+ errorMessage, yytext(), yyline, yycolumn);
+ }
+ }
+
+ /**
+ * checkVariable: checks for violations on the current variable name (var).
+ * Called from YYINITIAL and STRING.
+ */
+ private void checkVariable(final String var) throws JFlexException {
+ boolean found = false;
+ if(!functionStack.empty()){
+ /* we are in a function */
+ if (functionStack.peek().getLocalVariables().contains(var))
+ found = true;
+ if (functionStack.peek().getGlobalVariables().contains(var))
+ found = true;
+ }
+ if(!found && !globalVariables.contains(var)) {
+ setError(location,"The variable $" + var + " is used before being initialized." , yyline+1);
+ }
+ }
+
+ /**
+ * addVariable: adds the current variable name (var) to the list of variables : glabals if
+ * in main, locals if in funtion.
+ * Called from YYINITIAL, WRITE, FORLOOP and READ.
+ */
+ private void addVariable(final String var) throws JFlexException {
+ if(!functionStack.empty()){
+ /* we are in a function */
+ functionStack.peek().getLocalVariables().add(var);
+ } else {
+ /* we are in main */
+ globalVariables.add(var);
+ }
+ }
+
+ /**
+ * setGlobals: adds the current globals to the globals of pFunction.
+ * If there is a higher level function, its locals are also added.
+ * Called from BEGINFUNC.
+ */
+ private void setGlobals(FunctionWithVariables pFunction) throws JFlexException {
+ if(!functionStack.empty()){
+ /* we are in a function: add the locals of the current function as globals of the new function */
+ pFunction.getGlobalVariables().addAll(functionStack.peek().getLocalVariables());
+ }
+ /* in all cases add the current globals */
+ pFunction.getGlobalVariables().addAll(globalVariables);
+ }
+
%}
%eofval{
@@ -102,9 +195,15 @@ OPTION = \- ("a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "k" |
/************************/
{
- {VAR} {location = location + yytext(); yybegin(YYINITIAL);}
- \n {yybegin(YYINITIAL);}
- . {}
+ {FNAME} {
+ location = yytext();
+ functionLine = yyline+1;
+ yybegin(BEGINFUNC);
+ }
+ \n {
+ yybegin(YYINITIAL);
+ }
+ . {}
}
/************************/
@@ -113,18 +212,48 @@ OPTION = \- ("a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "k" |
{
{COMMENT_WORD} {yybegin(COMMENT);}
- {FUNC} {location = yytext(); yybegin(NAMING);}
- /** variables initialisation **/
+ {FUNCTION} {yybegin(NAMING);}
+ {FUNCT} {
+ functionLine = yyline+1;
+ location = yytext().substring(0,yytext().length()-2).trim();
+ yybegin(BEGINFUNC);
+ }
+ {FOR} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().getFinisher().equals(Function.finisherOf(yytext()))){
+ functionStack.peek().addStarterRepetition();
+ }
+ }
+ yybegin(FORLOOP);
+ }
+ {FUNCSTART} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().getFinisher().equals(Function.finisherOf(yytext()))){
+ functionStack.peek().addStarterRepetition();
+ }
+ }
+ }
+ {FUNCEND} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().isFinisher(yytext())){
+ if(functionStack.peek().getStarterRepetition()>0) {
+ functionStack.peek().removeStarterRepetition();
+ } else {
+ endLocation();
+ }
+ }
+ }
+ }
+ /** variables initialisation **/
{VAR}{SPACE}*\= {String var = yytext().substring(0,yytext().length()-1).trim();
- variables.add(var);}
+ addVariable(var);}
/** Varible use found **/
\${VAR} {String var = yytext().substring(1);
- if(!variables.contains(var)) setError(location,"The variable $" + var + " is used before being initialized." , yyline+1);}
+ checkVariable(var);}
"tee" | \>\> {yybegin(WRITE);}
- "for" {yybegin(FORLOOP);}
"read" {yybegin(READ);}
{FILEEXIST} {String var = yytext().replaceAll("\"", "").replaceAll("\\{", "").replaceAll("\\}", "").split("\\$")[1];
- variables.add(var);}
+ addVariable(var);}
{VAR} {}
\" {yybegin(STRING);}
. {}
@@ -137,7 +266,7 @@ OPTION = \- ("a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "k" |
{
\-{VAR} {}
\$(\{)?{VAR} {String var = yytext().substring(1).replace("{","");
- variables.add(var);}
+ addVariable(var);}
\n | \; {yybegin(YYINITIAL);}
. {}
}
@@ -147,7 +276,7 @@ OPTION = \- ("a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "k" |
/************************/
{
- {VAR} {variables.add(yytext()); yybegin(YYINITIAL);}
+ {VAR} {addVariable(yytext()); yybegin(YYINITIAL);}
\n | \; {yybegin(YYINITIAL);}
. {}
}
@@ -159,7 +288,7 @@ OPTION = \- ("a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "k" |
{
\\\$ {}
\$(\{)?{VAR} {String var = yytext().substring(1).replace("{","");
- if(!variables.contains(var)) setError(location,"The variable $" + var + " is used before being initialized." , yyline+1);}
+ checkVariable(var);}
\n | \; | \" {yybegin(YYINITIAL);}
. {}
}
@@ -169,11 +298,39 @@ OPTION = \- ("a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "k" |
/************************/
{
- {VAR} {variables.add(yytext()); }
+ {VAR} {addVariable(yytext()); }
\n | \; {yybegin(YYINITIAL);}
. {}
}
+/************************/
+/* BEGINFUNC STATE */
+/************************/
+/*
+ * This state target is to retrieve the function starter. For more information on fonction starter, have a look on {@link Function} class.
+ * Pending this starter, the function ender can be defined.
+ *
+ */
+
+ {
+ \(\) {}
+ {FOR} {
+ FunctionWithVariables function;
+ function = new FunctionWithVariables(location, functionLine, yytext());
+ setGlobals(function);
+ functionStack.push(function);
+ yybegin(FORLOOP);
+ }
+ {FUNCSTART} {
+ FunctionWithVariables function;
+ function = new FunctionWithVariables(location, functionLine, yytext());
+ setGlobals(function);
+ functionStack.push(function);
+ yybegin(YYINITIAL);
+ }
+ [^]|{SPACE} {}
+ }
+
/************************/
/* ERROR STATE */
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/COMDATAInvariant.lex b/fr.cnes.analysis.tools.shell.rules/lex/COMDATAInvariant.lex
index de0908f0..8a49e70a 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/COMDATAInvariant.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/COMDATAInvariant.lex
@@ -21,12 +21,15 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.EmptyStackException;
+import java.util.Stack;
import org.eclipse.core.runtime.Path;
import fr.cnes.analysis.tools.analyzer.datas.AbstractChecker;
import fr.cnes.analysis.tools.analyzer.datas.CheckResult;
import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
+import fr.cnes.analysis.tools.shell.metrics.Function;
%%
@@ -41,12 +44,16 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
%type List
-%state COMMENT, NAMING, INVARIANT, AVOID
+%state COMMENT, NAMING, INVARIANT, AVOID, BEGINFUNC, AWK, AWK_STRING, STRING_SIMPLE, STRING_DOUBLE, FOR
COMMENT_WORD = \#
-FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
-SPACE = [\ \r\t\f]
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FUNCTION = "function"
+FOR = "for"
+DONE = "done"
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
+NAME = [a-zA-Z\_][a-zA-Z0-9\_]*
+SPACE = [\ \r\t\f]*
VAR = [a-zA-Z][a-zA-Z0-9\_]*
EXTENSION = (\.{VAR})+
SEPAR = [\ ] | \+ | \- | \* | \/
@@ -68,7 +75,18 @@ OPER = "++" | "--"
IGNORE = "<<" {SPACE}* "EOF" [^"<<"]* "EOF" | "typeset" | "declare" | "--"[a-zA-Z\-]*"="
-CLE = "alias" | "apropos" | "apt-get" | "aptitude" | "ascp" | "aspell" | "awk" |
+FUNCSTART = \{ | \( | \(\( | \[\[ | "if" | "case" | "select" | "for" | "while" | "until"
+FUNCEND = \} | \) | \)\) | \]\] | "fi" | "esac" | "done"
+
+AWK = "awk"
+COMMAND_END = [\n;]
+
+STRING_D = \"
+IGNORE_STRING_D = [\\][\"]
+STRING_S = \'
+IGNORE_STRING_S = [\\][\']
+
+CLE = "alias" | "apropos" | "apt-get" | "aptitude" | "ascp" | "aspell" |
"basename" | "bash" | "bc" | "bg" | "break" | "builtin" | "bzip2" |
"cal" | "case" | "cd" | "cfdisk" | "chgrp" | "chmod" | "chown" |
"chroot" | "chkconfig" | "cksum" | "clear" | "cmp" | "comm" | "command" |
@@ -111,7 +129,7 @@ CLE = "alias" | "apropos" | "apt-get" | "aptitude" | "ascp" | "aspell" | "awk
private String parsedFileName;
private String location = MAINPROGRAM;
/* VARIABLE: constant for variable error message */
- private static final String VARIABLE = " -> The variable ";
+ private static final String VARIABLE = "The variable ";
/* DECLARE_CONST: message for constant error message */
private static final String DECLARE_CONST = " should be declared constant";
/* errVariables: contains all variables that for the moment should be consts */
@@ -124,23 +142,34 @@ CLE = "alias" | "apropos" | "apt-get" | "aptitude" | "ascp" | "aspell" | "awk
/* int: variable line in code, String: location in code (function name) */
private final Map varLocations = new HashMap();
- /* localErrVariables: contains all current function local variables that for the moment */
- /* should be consts */
- /* String: variable name, Integer: variable line in code */
- private final Map localErrVariables = new HashMap();
- /* localOkVariables: contains all current function variables that have either been declared as */
- /* consts or should be variables. There should be no violation on them. */
- private final List localOkVariables = new ArrayList();
-
+ List globalVariables = new ArrayList();
private boolean variableError = false;
private boolean invariantError = false;
private boolean separator = false;
private String variable = "";
+ /* functionLine: the beginning line of the function */
+ int functionLine = 0;
+
+ /* The global variables in the class will be used to stock the okVariables of the function */
+ private Stack functionStack = new Stack<>();
+
/* addVar: method that adds the just initialised variable var to the correct list according to its status */
- private void addVar(final String var) {
+ private void addVar(final String var) {
+ if(!functionStack.empty()){
+ /* we are in a function: add the variable to the correct list in the function */
+ functionAddVar(var);
+ } else {
+ /* we are in main */
+ mainAdd(var);
+ }
+ }
+
+ /* mainAdd: method that adds the just initialised variable var to the correct list according to its status */
+ /* we are in main */
+ private void mainAdd(final String var) {
final Boolean found = errVariables.containsKey(var);
if (found) {
/* var is in errVariables, this is the 2nd initialisation */
@@ -152,36 +181,77 @@ CLE = "alias" | "apropos" | "apt-get" | "aptitude" | "ascp" | "aspell" | "awk
/* this is its 1st initialisation */
errVariables.put(var, yyline);
varLocations.put(yyline, location);
+ globalVariables.add(var);
}
}
+
+ /* functionAddVar: method that adds the just initialised variable var to the correct list according to its status */
+ /* we are in a function */
+ private void functionAddVar(final String var) {
+ FunctionInvariant function = functionStack.peek();
+ HashMap functionErrVariables = function.getErrVariables();
+ final Boolean found = functionErrVariables.containsKey(var);
+ List functionOkVariables = function.getOkVariables();
+ List functionGlobals = function.getGlobalVariables();
+ List functionOkGlobalVariables = function.getOkGlobalVariables();
+
+ if (found) {
+ /* var is in function ErrVariables, this is the 2nd initialisation */
+ /* var doesn't need to be const */
+ functionErrVariables.remove(var);
+ functionOkVariables.add(var);
+ } else if (!functionOkVariables.contains(var)) {
+ /* var isn't in the already initiated local variables in any way */
+ /* this is its 1st initialisation */
+ if (!functionGlobals.contains(var))
+ {
+ /* the variable is not global: that means it is really a 1st local initialisation */
+ function.getLocalVariables().add(var);
+ functionErrVariables.put(var, yyline);
+ } else {
+ /* the variable is global for the function, meaning that this is its 2nd initialisation */
+ /* the functionOkVariables will be passed up to the containing function or main */
+ functionOkVariables.add(var);
+ functionOkGlobalVariables.add(var);
+ }
+ }
+ }
+
/* localAddVar: method that adds the just initialised local variable var to the correct list according to its status */
- private void localAddVar(final String var) {
- final Boolean found = localErrVariables.containsKey(var);
- if (found) {
- /* var is in localErrVariables, this is the 2nd initialisation */
+ /* always called in the case of a local variable */
+ private void localAddVar(final String var, Boolean localReadOnly) {
+ FunctionInvariant function = functionStack.peek();
+ HashMap functionErrVariables = function.getErrVariables();
+ final Boolean found = functionErrVariables.containsKey(var);
+ List functionOkVariables = function.getOkVariables();
+
+ if (localReadOnly) {
+ functionOkVariables.add(var);
+ function.getLocalVariables().add(var);
+ } else if (found) {
+ /* var is in function ErrVariables, this is the 2nd initialisation */
/* var doesn't need to be const */
- localErrVariables.remove(var);
- localOkVariables.add(var);
- } else if (!localOkVariables.contains(var)) {
+ functionErrVariables.remove(var);
+ functionOkVariables.add(var);
+ } else if (!functionOkVariables.contains(var)) {
/* var isn't in the already initiated variables in any way */
/* this is its 1st initialisation */
- localErrVariables.put(var, yyline);
- }
+ function.getLocalVariables().add(var);
+ functionErrVariables.put(var, yyline);
+ }
}
-
- /* addViolationLocation: adds the list of violations on variables of the just ended function (location) */
- private void addViolationsLocation() throws JFlexException {
- for (final Map.Entry entry : localErrVariables.entrySet()) {
+ /* addViolationLocation: adds the list of violations on variables of the just ended function (location) */
+ /* Called at the end of a function */
+ private void addViolationsLocation(HashMap functionErrVariables) throws JFlexException {
+ for (final Map.Entry entry : functionErrVariables.entrySet()) {
final String var = entry.getKey();
final Integer line = entry.getValue();
/* location is current location */
+
setError(location, VARIABLE + var + DECLARE_CONST, line+1);
}
- /* Clear the local tables ready for the next function */
- localErrVariables.clear();
- localOkVariables.clear();
}
public COMDATAInvariant() {
@@ -194,7 +264,48 @@ CLE = "alias" | "apropos" | "apt-get" | "aptitude" | "ascp" | "aspell" | "awk
this.parsedFileName = file.toString();
this.zzReader = new FileReader(new Path(file.getAbsolutePath()).toOSString());
}
-
+
+ private void endLocation() throws JFlexException {
+ try{
+ FunctionInvariant functionFinished = functionStack.pop();
+ addViolationsLocation(functionFinished.getErrVariables());
+ /* list of son function's locals, that also contain relative global OKs */
+ /* Remove those that were locals first */
+ ArrayList sonOkVariables = functionFinished.getOkGlobalVariables();
+ if (!functionStack.empty()) {
+ /* there is a current function */
+ FunctionInvariant currentFunction = functionStack.peek();
+ currentFunction.addSonOkVariables(sonOkVariables);
+ location = currentFunction.getName();
+ } else {
+ /* we are in the main program */
+ for (String var : sonOkVariables) {
+ errVariables.remove(var);
+ okVariables.add(var);
+ }
+ location = MAINPROGRAM;
+ }
+ }catch(EmptyStackException e){
+ final String errorMessage = e.getMessage();
+ throw new JFlexException(this.getClass().getName(), parsedFileName,
+ errorMessage, yytext(), yyline, yycolumn);
+ }
+ }
+
+ /**
+ * setGlobals: adds the current globals to the globals of pFunction.
+ * If there is a higher level function, its locals are also added.
+ */
+ private void setGlobals(FunctionWithVariables pFunction) throws JFlexException {
+ if(!functionStack.empty()){
+ /* we are in a function: add the locals of the current function as globals of the new function */
+ pFunction.getGlobalVariables().addAll(functionStack.peek().getGlobalVariables());
+ pFunction.getGlobalVariables().addAll(functionStack.peek().getLocalVariables());
+ } else {
+ pFunction.getGlobalVariables().addAll(globalVariables);
+ }
+ }
+
%}
%eofval{
@@ -240,7 +351,7 @@ CLE = "alias" | "apropos" | "apt-get" | "aptitude" | "ascp" | "aspell" | "awk
/************************/
{
- {VAR} {location = yytext(); yybegin(YYINITIAL);}
+ {VAR} {location = yytext(); yybegin(BEGINFUNC);}
\n {yybegin(YYINITIAL);}
. {}
}
@@ -251,8 +362,36 @@ CLE = "alias" | "apropos" | "apt-get" | "aptitude" | "ascp" | "aspell" | "awk
{
{COMMENT_WORD} {yybegin(COMMENT);}
- {FUNCTION} {if (! location.equals(MAINPROGRAM)) addViolationsLocation(); yybegin(NAMING);}
- {FUNCT} {if (! location.equals(MAINPROGRAM)) addViolationsLocation(); location = yytext().substring(0,yytext().length()-2).trim();}
+ {AWK} {yybegin(AWK);}
+ {FOR}{SPACE}*\(\( {
+ if(!functionStack.empty()){
+ if(functionStack.peek().getFinisher().equals(Function.finisherOf(yytext()))){
+ functionStack.peek().addStarterRepetition();
+ }
+ }
+ yybegin(FOR);
+ }
+ {FUNCTION} {yybegin(NAMING);}
+ {FUNCT} {location = yytext().substring(0,yytext().length()-2).trim();
+ yybegin(BEGINFUNC);}
+ {FUNCSTART} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().getFinisher().equals(Function.finisherOf(yytext()))){
+ functionStack.peek().addStarterRepetition();
+ }
+ }
+ }
+ {FUNCEND} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().isFinisher(yytext())){
+ if(functionStack.peek().getStarterRepetition()>0) {
+ functionStack.peek().removeStarterRepetition();
+ } else {
+ endLocation();
+ }
+ }
+ }
+ }
/** variables intialisation -> new sate to check rule **/
{CLE}{SPACE}+ {yybegin(AVOID);}
{IGNORE} {}
@@ -264,13 +403,15 @@ CLE = "alias" | "apropos" | "apt-get" | "aptitude" | "ascp" | "aspell" | "awk
{SPACE}{1}{VAR}{OPER} {addVar(yytext().substring(1, yytext().length()-2)); yybegin(INVARIANT);}
{OPER}{VAR}{SPACE}{1} {addVar(yytext().substring(2, yytext().length()-1)); yybegin(INVARIANT);}
{VAR}"+=" {addVar(yytext().substring(0, yytext().length()-2)); yybegin(INVARIANT);}
- {LOCALREADONLY}{VAR}\= {int varPos = yytext().lastIndexOf(' ');
+ {LOCALREADONLY}{SPACE}{VAR}\= {
+ int varPos = yytext().lastIndexOf(' ') + 1;
String var = yytext().substring(varPos, yytext().length()-1);
- localOkVariables.add(var);
+ localAddVar(var, true);
yybegin(INVARIANT);}
- {LOCAL}{VAR}\= {int varPos = yytext().lastIndexOf(' ');
+ {LOCAL}{SPACE}{VAR}\= {
+ int varPos = yytext().lastIndexOf(' ') + 1;
String var = yytext().substring(varPos, yytext().length()-1);
- localAddVar(var);
+ localAddVar(var, false);
yybegin(INVARIANT);}
[^] {}
}
@@ -294,6 +435,98 @@ CLE = "alias" | "apropos" | "apt-get" | "aptitude" | "ascp" | "aspell" | "awk
. {}
}
+/************************/
+/* BEGINFUNC STATE */
+/************************/
+/*
+ * This state target is to retrieve the function starter. For more information on fonction starter, have a look on {@link Function} class.
+ * Pending this starter, the function ender can be defined.
+ *
+ */
+
+ {
+ \(\) {}
+ {FOR}{SPACE}*\(\( {
+ FunctionInvariant function;
+ function = new FunctionInvariant(location, functionLine, yytext());
+ setGlobals(function);
+ functionStack.push(function);
+ yybegin(FOR);
+ }
+ {FUNCSTART} {
+ FunctionInvariant function;
+ function = new FunctionInvariant(location, functionLine, yytext());
+ setGlobals(function);
+ functionStack.push(function);
+ yybegin(YYINITIAL);
+ }
+ [^]|{SPACE} {}
+ }
+
+/*
+ * The string states are designed to avoid problems due to patterns found in strings.
+ */
+/************************/
+/* STRING_SIMPLE STATE */
+/************************/
+
+ {
+ {IGNORE_STRING_S} {}
+ {STRING_S} {yybegin(YYINITIAL);}
+ [^]|{SPACE} {}
+ }
+
+/************************/
+/* STRING_DOUBLE STATE */
+/************************/
+
+ {
+ {IGNORE_STRING_D} {}
+ {STRING_D} {yybegin(YYINITIAL);}
+ [^]|{SPACE} {}
+ }
+/*
+ * The AWK states are designed to ignore awk commands
+ */
+/************************/
+/* AWK STATE */
+/************************/
+
+ {
+ {STRING_S} {yybegin(AWK_STRING);}
+ {COMMAND_END} {yybegin(YYINITIAL);}
+ . {}
+ }
+
+/************************/
+/* AWK_STRING STATE */
+/************************/
+
+ {
+ {IGNORE_STRING_S} {}
+ {STRING_S} {yybegin(AWK);}
+ [^]|{SPACE} {}
+ }
+
+/************************/
+/* FOR STATE */
+/************************/
+
+ {
+ {DONE} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().isFinisher(yytext())){
+ if(functionStack.peek().getStarterRepetition()>0) {
+ functionStack.peek().removeStarterRepetition();
+ } else {
+ endLocation();
+ }
+ }
+ }
+ yybegin(YYINITIAL);
+ }
+ . {}
+ }
/************************/
/* ERROR STATE */
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/COMDATALoopCondition.lex b/fr.cnes.analysis.tools.shell.rules/lex/COMDATALoopCondition.lex
index 9edbd4ca..2493d6dc 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/COMDATALoopCondition.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/COMDATALoopCondition.lex
@@ -19,12 +19,15 @@ import java.io.FileReader;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
+import java.util.EmptyStackException;
+import java.util.Stack;
import org.eclipse.core.runtime.Path;
import fr.cnes.analysis.tools.analyzer.datas.AbstractChecker;
import fr.cnes.analysis.tools.analyzer.datas.CheckResult;
import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
+import fr.cnes.analysis.tools.shell.metrics.Function;
%%
@@ -40,23 +43,42 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
%type List
-%state COMMENT, NAMING, WHILE, FOR
+%state COMMENT, NAMING, WHILE, FOR, BEGINFUNC, STRING_SIMPLE, STRING_DOUBLE
COMMENT_WORD = \#
-FUNC = "function"
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FUNCTION = "function"
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
+SPACE = [\ \r\t\f]
VAR = [a-zA-Z][a-zA-Z0-9\_]*
-STRING = \'[^\']*\' | \"[^\"]*\"
-WHILE = "while"
+
+STRING_D = \"
+IGNORE_STRING_D = [\\][\"]
+STRING_S = \'
+IGNORE_STRING_S = [\\][\']
+
+WHILE = "while" | "until"
FOR = "for"
DONE = "done"
+FUNCSTART = \{ | \( | \(\( | \[\[ | "if" | "case" | "select" | "for" | "while" | "until"
+FUNCEND = \} | \) | \)\) | \]\] | "fi" | "esac" | "done"
+
%{
- String location = "MAIN PROGRAM";
+ /* MAINPROGRAM: constant for main program localisation */
+ private static final String MAINPROGRAM = "MAIN PROGRAM";
+
+ String location = MAINPROGRAM;
+ /* functionLine: the beginning line of the function */
+ int functionLine = 0;
+
private String parsedFileName;
List> conditions = new ArrayList>();
List variables = new ArrayList();
+ private Stack functionStack = new Stack<>();
+
public COMDATALoopCondition() {
}
@@ -90,7 +112,24 @@ DONE = "done"
}
}
}
-
+
+ private void endLocation() throws JFlexException {
+ try{
+ Function functionFinished = functionStack.pop();
+ if (!functionStack.empty()) {
+ /* there is a current function: change location to this function */
+ location = functionStack.peek().getName();
+ } else {
+ /* we are in the main program: change location to main */
+ location = MAINPROGRAM;
+ }
+ }catch(EmptyStackException e){
+ final String errorMessage = e.getMessage();
+ throw new JFlexException(this.getClass().getName(), parsedFileName,
+ errorMessage, yytext(), yyline, yycolumn);
+ }
+ }
+
%}
%eofval{
@@ -120,7 +159,7 @@ DONE = "done"
/************************/
{
- {VAR} {location = location + yytext(); yybegin(YYINITIAL);}
+ {FNAME} {location = yytext(); functionLine = yyline+1; yybegin(BEGINFUNC);}
\n {yybegin(YYINITIAL);}
. {}
}
@@ -131,12 +170,60 @@ DONE = "done"
{
{COMMENT_WORD} {yybegin(COMMENT);}
- {STRING} {}
- {FUNC} {location = yytext(); yybegin(NAMING);}
- {WHILE} {yybegin(WHILE);}
- {FOR} {yybegin(FOR);}
+ {STRING_D} {yybegin(STRING_DOUBLE);}
+ {STRING_S} {yybegin(STRING_SIMPLE);}
+ {FUNCTION} {yybegin(NAMING);}
+ {FUNCT} {functionLine = yyline+1;
+ location = yytext().substring(0,yytext().length()-2).trim();
+ yybegin(BEGINFUNC);}
+ {WHILE} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().getFinisher().equals(Function.finisherOf(yytext()))){
+ functionStack.peek().addStarterRepetition();
+ }
+ }
+ yybegin(WHILE);
+ }
+ {FOR} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().getFinisher().equals(Function.finisherOf(yytext()))){
+ functionStack.peek().addStarterRepetition();
+ }
+ }
+ yybegin(FOR);
+ }
+ {FUNCSTART} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().getFinisher().equals(Function.finisherOf(yytext()))){
+ functionStack.peek().addStarterRepetition();
+ }
+ }
+ }
{VAR}\= {String var = yytext().substring(0, yytext().length()-1); checkVariable(var);}
- {DONE} {int index = conditions.size() - 1; if (index >= 0) {conditions.remove(index);}}
+ {DONE} {
+ int index = conditions.size() - 1;
+ if (index >= 0) {conditions.remove(index);}
+ if(!functionStack.empty()){
+ if(functionStack.peek().isFinisher(yytext())){
+ if(functionStack.peek().getStarterRepetition()>0) {
+ functionStack.peek().removeStarterRepetition();
+ } else {
+ endLocation();
+ }
+ }
+ }
+ }
+ {FUNCEND} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().isFinisher(yytext())){
+ if(functionStack.peek().getStarterRepetition()>0) {
+ functionStack.peek().removeStarterRepetition();
+ } else {
+ endLocation();
+ }
+ }
+ }
+ }
{VAR} {}
[^] {}
}
@@ -168,6 +255,62 @@ DONE = "done"
. {}
}
+/************************/
+/* BEGINFUNC STATE */
+/************************/
+/*
+ * This state target is to retrieve the function starter. For more information on fonction starter, have a look on {@link Function} class.
+ * Pending this starter, the function ender can be defined.
+ *
+ */
+
+ {
+ \(\) {}
+ {WHILE} {
+ Function function;
+ function = new Function(location, functionLine, yytext());
+ functionStack.push(function);
+ yybegin(WHILE);
+ }
+ {FOR} {
+ Function function;
+ function = new Function(location, functionLine, yytext());
+ functionStack.push(function);
+ yybegin(FOR);
+ }
+ {FUNCSTART} {
+ Function function;
+ function = new Function(location, functionLine, yytext());
+ functionStack.push(function);
+ yybegin(YYINITIAL);
+ }
+ [^]|{SPACE} {}
+ }
+
+/*
+ * The string states are designed to avoid problems due to patterns found in strings.
+ */
+/************************/
+/* STRING_SIMPLE STATE */
+/************************/
+
+ {
+ {IGNORE_STRING_S} {}
+ {STRING_S} {yybegin(YYINITIAL);}
+ [^]|{SPACE} {}
+ }
+
+/************************/
+/* STRING_DOUBLE STATE */
+/************************/
+
+ {
+ {IGNORE_STRING_D} {}
+ {STRING_D} {yybegin(YYINITIAL);}
+ [^]|{SPACE} {}
+ }
+
+
/************************/
/* ERROR STATE */
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/COMDATANotUsed.lex b/fr.cnes.analysis.tools.shell.rules/lex/COMDATANotUsed.lex
index bc48fd67..6f9a30c3 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/COMDATANotUsed.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/COMDATANotUsed.lex
@@ -44,7 +44,8 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
COMMENT_WORD = \#
FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
SPACE = [\ \r\t\f]
VAR = [a-zA-Z][a-zA-Z0-9\_]*
@@ -123,7 +124,7 @@ VAR = [a-zA-Z][a-zA-Z0-9\_]*
/************************/
{
- {VAR} {location = yytext(); yybegin(YYINITIAL);}
+ {FNAME} {location = yytext(); yybegin(YYINITIAL);}
\n {yybegin(YYINITIAL);}
. {}
}
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/COMDESIGNActiveWait.lex b/fr.cnes.analysis.tools.shell.rules/lex/COMDESIGNActiveWait.lex
index 6b5c02c9..5f6892f7 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/COMDESIGNActiveWait.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/COMDESIGNActiveWait.lex
@@ -18,12 +18,15 @@ import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.File;
import java.util.List;
+import java.util.EmptyStackException;
+import java.util.Stack;
import org.eclipse.core.runtime.Path;
import fr.cnes.analysis.tools.analyzer.datas.AbstractChecker;
import fr.cnes.analysis.tools.analyzer.datas.CheckResult;
import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
+import fr.cnes.analysis.tools.shell.metrics.Function;
%%
@@ -39,21 +42,38 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
%type List
-%state COMMENT, NAMING
+%state COMMENT, NAMING, BEGINFUNC, STRING_SIMPLE, STRING_DOUBLE
COMMENT_WORD = \#
-FUNC = "function"
-SPACE = [\ \r\t\f]
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FUNCTION = "function"
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
+SPACE = [\ \r\t\f]
VAR = [a-zA-Z][a-zA-Z0-9\_]*
-STRING = \'[^\']*\' | \"[^\"]*\"
-ACTWAIT = "while"{SPACE}*\[{SPACE}*"1"{SPACE}*\]{SPACE}* |
- "read"
+FUNCSTART = \{ | \( | \(\( | \[\[ | "if" | "case" | "select" | "for" | "while" | "until"
+FUNCEND = \} | \) | \)\) | \]\] | "fi" | "esac" | "done"
+
+STRING_D = \"
+IGNORE_STRING_D = [\\][\"]
+STRING_S = \'
+IGNORE_STRING_S = [\\][\']
+
+ACTWAIT_WHILE = "while"{SPACE}*\[{SPACE}*"1"{SPACE}*\]{SPACE}*
+ACTWAIT = "read" | "sleep" | "wait"
%{
- String location = "MAIN PROGRAM";
+ /* MAINPROGRAM: constant for main program localisation */
+ private static final String MAINPROGRAM = "MAIN PROGRAM";
+
+ String location = MAINPROGRAM;
+ /* functionLine: the beginning line of the function */
+ int functionLine = 0;
+
private String parsedFileName;
+ private Stack functionStack = new Stack<>();
+
public COMDESIGNActiveWait() {
}
@@ -64,7 +84,24 @@ ACTWAIT = "while"{SPACE}*\[{SPACE}*"1"{SPACE}*\]{SPACE}* |
this.parsedFileName = file.toString();
this.zzReader = new FileReader(new Path(file.getAbsolutePath()).toOSString());
}
-
+
+ private void endLocation() throws JFlexException {
+ try{
+ Function functionFinished = functionStack.pop();
+ if (!functionStack.empty()) {
+ /* there is a current function: change location to this function */
+ location = functionStack.peek().getName();
+ } else {
+ /* we are in the main program: change location to main */
+ location = MAINPROGRAM;
+ }
+ }catch(EmptyStackException e){
+ final String errorMessage = e.getMessage();
+ throw new JFlexException(this.getClass().getName(), parsedFileName,
+ errorMessage, yytext(), yyline, yycolumn);
+ }
+ }
+
%}
%eofval{
@@ -94,7 +131,7 @@ ACTWAIT = "while"{SPACE}*\[{SPACE}*"1"{SPACE}*\]{SPACE}* |
/************************/
{
- {VAR} {location = location + yytext(); yybegin(YYINITIAL);}
+ {FNAME} {location = yytext(); functionLine = yyline+1; yybegin(BEGINFUNC);}
\n {yybegin(YYINITIAL);}
. {}
}
@@ -105,13 +142,93 @@ ACTWAIT = "while"{SPACE}*\[{SPACE}*"1"{SPACE}*\]{SPACE}* |
{
{COMMENT_WORD} {yybegin(COMMENT);}
- {FUNC} {location = yytext(); yybegin(NAMING);}
- {ACTWAIT} {setError(location,"There is an active wait in this point.", yyline+1); }
- {STRING} {}
+ {STRING_D} {yybegin(STRING_DOUBLE);}
+ {STRING_S} {yybegin(STRING_SIMPLE);}
+ {FUNCTION} {yybegin(NAMING);}
+ {FUNCT} {functionLine = yyline+1;
+ location = yytext().substring(0,yytext().length()-2).trim();
+ yybegin(BEGINFUNC);}
+ {ACTWAIT} {setError(location,"There is an active wait in this point.", yyline+1); }
+ {ACTWAIT_WHILE} {
+ setError(location,"There is an active wait in this point.", yyline+1);
+ if(!functionStack.empty()){
+ if(functionStack.peek().getFinisher().equals(Function.finisherOf(yytext()))){
+ functionStack.peek().addStarterRepetition();
+ }
+ }
+ }
+ {FUNCSTART} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().getFinisher().equals(Function.finisherOf(yytext()))){
+ functionStack.peek().addStarterRepetition();
+ }
+ }
+ }
+ {FUNCEND} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().isFinisher(yytext())){
+ if(functionStack.peek().getStarterRepetition()>0) {
+ functionStack.peek().removeStarterRepetition();
+ } else {
+ endLocation();
+ }
+ }
+ }
+ }
{VAR} {} /* Clause to match with words */
[^] {}
}
+/************************/
+/* BEGINFUNC STATE */
+/************************/
+/*
+ * This state target is to retrieve the function starter. For more information on fonction starter, have a look on {@link Function} class.
+ * Pending this starter, the function ender can be defined.
+ *
+ */
+
+ {
+ \(\) {}
+ {ACTWAIT_WHILE} {
+ setError(location,"There is an active wait in this point.", yyline+1);
+ Function function;
+ function = new Function(location, functionLine, yytext());
+ functionStack.push(function);
+ yybegin(YYINITIAL);
+ }
+ {FUNCSTART} {
+ Function function;
+ function = new Function(location, functionLine, yytext());
+ functionStack.push(function);
+ yybegin(YYINITIAL);
+ }
+ [^]|{SPACE} {}
+ }
+
+/*
+ * The string states are designed to avoid problems due to patterns found in strings.
+ */
+/************************/
+/* STRING_SIMPLE STATE */
+/************************/
+
+ {
+ {IGNORE_STRING_S} {}
+ {STRING_S} {yybegin(YYINITIAL);}
+ [^]|{SPACE} {}
+ }
+
+/************************/
+/* STRING_DOUBLE STATE */
+/************************/
+
+ {
+ {IGNORE_STRING_D} {}
+ {STRING_D} {yybegin(YYINITIAL);}
+ [^]|{SPACE} {}
+ }
+
/************************/
/* ERROR STATE */
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/COMFLOWAbort.lex b/fr.cnes.analysis.tools.shell.rules/lex/COMFLOWAbort.lex
index a2c8e114..f3a43c23 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/COMFLOWAbort.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/COMFLOWAbort.lex
@@ -18,12 +18,15 @@ import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.File;
import java.util.List;
+import java.util.EmptyStackException;
+import java.util.Stack;
import org.eclipse.core.runtime.Path;
import fr.cnes.analysis.tools.analyzer.datas.AbstractChecker;
import fr.cnes.analysis.tools.analyzer.datas.CheckResult;
import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
+import fr.cnes.analysis.tools.shell.metrics.Function;
%%
@@ -39,22 +42,40 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
%type List
-%state COMMENT, NAMING, KILL
+%state COMMENT, NAMING, KILL, BEGINFUNC, STRING_SIMPLE, STRING_DOUBLE
COMMENT_WORD = \#
-FUNC = "function"
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FUNCTION = "function"
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
+SPACE = [\ \r\t\f]
VAR = (\$)?[a-zA-Z][a-zA-Z0-9\_]*
-STRING = \'[^\']*\' | \"[^\"]*\"
+
+FUNCSTART = \{ | \( | \(\( | \[\[ | "if" | "case" | "select" | "for" | "while" | "until"
+FUNCEND = \} | \) | \)\) | \]\] | "fi" | "esac" | "done"
+
+STRING_D = \"
+IGNORE_STRING_D = [\\][\"]
+STRING_S = \'
+IGNORE_STRING_S = [\\][\']
ABORT = ("kill"|"pkill"|"killall")
OPTIONS = \- ("9" | "SIGKILL" | "kill")
%{
- String location = "MAIN PROGRAM";
+ /* MAINPROGRAM: constant for main program localisation */
+ private static final String MAINPROGRAM = "MAIN PROGRAM";
+
+ String location = MAINPROGRAM;
+ /* functionLine: the beginning line of the function */
+ int functionLine = 0;
+
private String parsedFileName;
String errorKill = "";
+ private Stack functionStack = new Stack<>();
+
public COMFLOWAbort() {
}
@@ -65,7 +86,23 @@ OPTIONS = \- ("9" | "SIGKILL" | "kill")
this.parsedFileName = file.toString();
this.zzReader = new FileReader(new Path(file.getAbsolutePath()).toOSString());
}
-
+
+ private void endLocation() throws JFlexException {
+ try{
+ Function functionFinished = functionStack.pop();
+ if (!functionStack.empty()) {
+ /* there is a current function: change location to this function */
+ location = functionStack.peek().getName();
+ } else {
+ /* we are in the main program: change location to main */
+ location = MAINPROGRAM;
+ }
+ }catch(EmptyStackException e){
+ final String errorMessage = e.getMessage();
+ throw new JFlexException(this.getClass().getName(), parsedFileName,
+ errorMessage, yytext(), yyline, yycolumn);
+ }
+ }
%}
%eofval{
@@ -95,7 +132,7 @@ OPTIONS = \- ("9" | "SIGKILL" | "kill")
/************************/
{
- {VAR} {location = location + yytext(); yybegin(YYINITIAL);}
+ {FNAME} {location = yytext(); functionLine = yyline+1; yybegin(BEGINFUNC);}
\n {yybegin(YYINITIAL);}
. {}
}
@@ -106,9 +143,31 @@ OPTIONS = \- ("9" | "SIGKILL" | "kill")
{
{COMMENT_WORD} {yybegin(COMMENT);}
- {FUNC} {location = yytext(); yybegin(NAMING);}
+ {FUNCTION} {yybegin(NAMING);}
+ {FUNCT} {functionLine = yyline+1;
+ location = yytext().substring(0,yytext().length()-2).trim();
+ yybegin(BEGINFUNC);}
+ {FUNCSTART} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().getFinisher().equals(Function.finisherOf(yytext()))){
+ functionStack.peek().addStarterRepetition();
+ }
+ }
+ }
+ {FUNCEND} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().isFinisher(yytext())){
+ if(functionStack.peek().getStarterRepetition()>0) {
+ functionStack.peek().removeStarterRepetition();
+ } else {
+ endLocation();
+ }
+ }
+ }
+ }
{ABORT} {errorKill= yytext(); yybegin(KILL);}
- {STRING} {}
+ {STRING_D} {yybegin(STRING_DOUBLE);}
+ {STRING_S} {yybegin(STRING_SIMPLE);}
{VAR} {} /* Clause to match with words that contains "kill" */
[^] {}
}
@@ -125,6 +184,48 @@ OPTIONS = \- ("9" | "SIGKILL" | "kill")
. {}
}
+/************************/
+/* BEGINFUNC STATE */
+/************************/
+/*
+ * This state target is to retrieve the function starter. For more information on fonction starter, have a look on {@link Function} class.
+ * Pending this starter, the function ender can be defined.
+ *
+ */
+
+ {
+ \(\) {}
+ {FUNCSTART} {
+ Function function;
+ function = new Function(location, functionLine, yytext());
+ functionStack.push(function);
+ yybegin(YYINITIAL);
+ }
+ [^]|{SPACE} {}
+ }
+
+/*
+ * The string states are designed to avoid problems due to patterns found in strings.
+ */
+/************************/
+/* STRING_SIMPLE STATE */
+/************************/
+
+ {
+ {IGNORE_STRING_S} {}
+ {STRING_S} {yybegin(YYINITIAL);}
+ [^]|{SPACE} {}
+ }
+
+/************************/
+/* STRING_DOUBLE STATE */
+/************************/
+
+ {
+ {IGNORE_STRING_D} {}
+ {STRING_D} {yybegin(YYINITIAL);}
+ [^]|{SPACE} {}
+ }
/************************/
/* ERROR STATE */
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/COMFLOWBooleanExpression.lex b/fr.cnes.analysis.tools.shell.rules/lex/COMFLOWBooleanExpression.lex
index 6e7edc1c..4f655358 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/COMFLOWBooleanExpression.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/COMFLOWBooleanExpression.lex
@@ -42,8 +42,9 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
%state COMMENT, NAMING, CONDITIONAL, LOOP
COMMENT_WORD = \#
-FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
+FUNCTION = "function"
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
SPACE = [\ \r\t\f]
VAR = [a-zA-Z][a-zA-Z0-9\_]*
STRING = \'[^\']*\' | \"[^\"]*\"
@@ -99,7 +100,7 @@ BOOL = \|\| | \&\& | \-"o" | \-"a"
/************************/
{
- {VAR} {location = yytext(); yybegin(YYINITIAL);}
+ {FNAME} {location = yytext(); yybegin(YYINITIAL);}
\n {yybegin(YYINITIAL);}
. {}
}
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/COMFLOWCaseSwitch.lex b/fr.cnes.analysis.tools.shell.rules/lex/COMFLOWCaseSwitch.lex
index 5705cbb1..07ab2b48 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/COMFLOWCaseSwitch.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/COMFLOWCaseSwitch.lex
@@ -18,12 +18,15 @@ import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.File;
import java.util.List;
+import java.util.EmptyStackException;
+import java.util.Stack;
import org.eclipse.core.runtime.Path;
import fr.cnes.analysis.tools.analyzer.datas.AbstractChecker;
import fr.cnes.analysis.tools.analyzer.datas.CheckResult;
import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
+import fr.cnes.analysis.tools.shell.metrics.Function;
%%
@@ -39,20 +42,39 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
%type List
-%state COMMENT, NAMING, CONDITIONAL
+%state COMMENT, NAMING, BEGINFUNC, STRING_SIMPLE, STRING_DOUBLE
COMMENT_WORD = \#
-FUNC = "function"
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FUNCTION = "function"
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
+SPACE = [\ \r\t\f]
VAR = [a-zA-Z][a-zA-Z0-9\_]*
-STRING = \'[^\']*\' | \"[^\"]*\"
+
+FUNCSTART = \{ | \( | \(\( | \[\[ | "if" | "case" | "select" | "for" | "while" | "until"
+FUNCEND = \} | \) | \)\) | \]\] | "fi" | "esac" | "done"
+
+STRING_D = \"
+IGNORE_STRING_D = [\\][\"]
+STRING_S = \'
+IGNORE_STRING_S = [\\][\']
CASE = "case"
ESAC = "esac"
%{
- String location = "MAIN PROGRAM";
- private String parsedFileName;
+ /* MAINPROGRAM: constant for main program localisation */
+ private static final String MAINPROGRAM = "MAIN PROGRAM";
+
+ String location = MAINPROGRAM;
+ /* functionLine: the beginning line of the function */
+ int functionLine = 0;
+
+ private String parsedFileName;
boolean defaultExpr = false;
+
+ private Stack functionStack = new Stack<>();
+
public COMFLOWCaseSwitch() {
}
@@ -64,7 +86,24 @@ ESAC = "esac"
this.parsedFileName = file.toString();
this.zzReader = new FileReader(new Path(file.getAbsolutePath()).toOSString());
}
-
+
+ private void endLocation() throws JFlexException {
+ try{
+ Function functionFinished = functionStack.pop();
+ if (!functionStack.empty()) {
+ /* there is a current function: change location to this function */
+ location = functionStack.peek().getName();
+ } else {
+ /* we are in the main program: change location to main */
+ location = MAINPROGRAM;
+ }
+ }catch(EmptyStackException e){
+ final String errorMessage = e.getMessage();
+ throw new JFlexException(this.getClass().getName(), parsedFileName,
+ errorMessage, yytext(), yyline, yycolumn);
+ }
+ }
+
%}
%eofval{
@@ -94,7 +133,7 @@ ESAC = "esac"
/************************/
{
- {VAR} {location = location + yytext(); yybegin(YYINITIAL);}
+ {FNAME} {location = yytext(); functionLine = yyline+1; yybegin(BEGINFUNC);}
\n {yybegin(YYINITIAL);}
. {}
}
@@ -105,24 +144,106 @@ ESAC = "esac"
{
{COMMENT_WORD} {yybegin(COMMENT);}
- {FUNC} {location = yytext(); yybegin(NAMING);}
- {STRING} {}
- {CASE} {defaultExpr=false; yybegin(CONDITIONAL);}
+ {STRING_D} {yybegin(STRING_DOUBLE);}
+ {STRING_S} {yybegin(STRING_SIMPLE);}
+ {FUNCTION} {yybegin(NAMING);}
+ {FUNCT} {functionLine = yyline+1;
+ location = yytext().substring(0,yytext().length()-2).trim();
+ yybegin(BEGINFUNC);}
+ {CASE} {
+ defaultExpr=false;
+ if(!functionStack.empty()){
+ if(functionStack.peek().getFinisher().equals(Function.finisherOf(yytext()))){
+ functionStack.peek().addStarterRepetition();
+ }
+ }
+ }
+ {FUNCSTART} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().getFinisher().equals(Function.finisherOf(yytext()))){
+ functionStack.peek().addStarterRepetition();
+ }
+ }
+ }
+ {ESAC} {
+ if(!defaultExpr) setError(location,"The default case of the case switch condition is missing.", yyline+1);
+ defaultExpr=false;
+ if(!functionStack.empty()){
+ if(functionStack.peek().isFinisher(yytext())){
+ if(functionStack.peek().getStarterRepetition()>0) {
+ functionStack.peek().removeStarterRepetition();
+ } else {
+ endLocation();
+ }
+ }
+ }
+ }
+ {FUNCEND} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().isFinisher(yytext())){
+ if(functionStack.peek().getStarterRepetition()>0) {
+ functionStack.peek().removeStarterRepetition();
+ } else {
+ endLocation();
+ }
+ }
+ }
+ }
+ \*\) {defaultExpr=true;}
{VAR} {} /* Clause to match with words that contains "kill" */
[^] {}
}
/************************/
-/* CONDITIONAL STATE */
+/* BEGINFUNC STATE */
/************************/
-
+/*
+ * This state target is to retrieve the function starter. For more information on fonction starter, have a look on {@link Function} class.
+ * Pending this starter, the function ender can be defined.
+ *
+ */
+
{
- \*\) {defaultExpr=true;}
- {ESAC} {if(!defaultExpr) setError(location,"The default case of the case switch condition is missing.", yyline+1); yybegin(YYINITIAL);}
- {VAR} {}
- [^] {}
+ \(\) {}
+ {CASE} {
+ defaultExpr=false;
+ Function function;
+ function = new Function(location, functionLine, yytext());
+ functionStack.push(function);
+ yybegin(YYINITIAL);
+ }
+ {FUNCSTART} {
+ Function function;
+ function = new Function(location, functionLine, yytext());
+ functionStack.push(function);
+ yybegin(YYINITIAL);
+ }
+ [^]|{SPACE} {}
}
-
+
+/*
+ * The string states are designed to avoid problems due to patterns found in strings.
+ */
+/************************/
+/* STRING_SIMPLE STATE */
+/************************/
+
+ {
+ {IGNORE_STRING_S} {}
+ {STRING_S} {yybegin(YYINITIAL);}
+ [^]|{SPACE} {}
+ }
+
+/************************/
+/* STRING_DOUBLE STATE */
+/************************/
+
+ {
+ {IGNORE_STRING_D} {}
+ {STRING_D} {yybegin(YYINITIAL);}
+ [^]|{SPACE} {}
+ }
+
/************************/
/* ERROR STATE */
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/COMFLOWExit.lex b/fr.cnes.analysis.tools.shell.rules/lex/COMFLOWExit.lex
index 5300831d..a6a732d4 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/COMFLOWExit.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/COMFLOWExit.lex
@@ -43,7 +43,8 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
COMMENT_WORD = \#
FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
SPACE = [\ \r\t\f]
VAR = [a-zA-Z][a-zA-Z0-9\_]*
STRING = \'[^\']*\' | \"[^\"]*\"
@@ -97,7 +98,7 @@ RETURN = "return"
/************************/
{
- {VAR} {location = yytext(); returns=0; brackets=0; yybegin(FUNCTION);}
+ {FNAME} {location = yytext(); returns=0; brackets=0; yybegin(FUNCTION);}
\n {returns=0; yybegin(YYINITIAL);}
. {}
}
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/COMFLOWExitLoop.lex b/fr.cnes.analysis.tools.shell.rules/lex/COMFLOWExitLoop.lex
index 2ebdfae3..70dc77ba 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/COMFLOWExitLoop.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/COMFLOWExitLoop.lex
@@ -43,7 +43,8 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
COMMENT_WORD = \#
FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
SPACE = [\ \r\t\f]
VAR = [a-zA-Z][a-zA-Z0-9\_]*
STRING = \'[^\']*\' | \"[^\"]*\"
@@ -102,7 +103,7 @@ BREAK = "break" | "exit"
/************************/
{
- {VAR} {location = yytext(); yybegin(YYINITIAL);}
+ {FNAME} {location = yytext(); yybegin(YYINITIAL);}
\n {yybegin(YYINITIAL);}
. {}
}
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/COMFLOWFileExistence.lex b/fr.cnes.analysis.tools.shell.rules/lex/COMFLOWFileExistence.lex
index b9f800ae..94325018 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/COMFLOWFileExistence.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/COMFLOWFileExistence.lex
@@ -25,6 +25,9 @@ import org.eclipse.core.runtime.Path;
import fr.cnes.analysis.tools.analyzer.datas.AbstractChecker;
import fr.cnes.analysis.tools.analyzer.datas.CheckResult;
import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
+import java.util.EmptyStackException;
+import java.util.Stack;
+import fr.cnes.analysis.tools.shell.metrics.Function;
import java.util.logging.Logger;
@@ -42,7 +45,7 @@ import java.util.logging.Logger;
%type List
-%state COMMENT, NAMING, FILE, STRING
+%state COMMENT, NAMING, FILE, STRING, BEGINFUNC
COMMENT_WORD = [\#]
FUNCTION = "function"
@@ -54,6 +57,8 @@ SHELL_VAR = ([0-9]+|[\-\@\?\#\!\_\*\$])
EXPANDED_VAR = [\!]?{NAME}([\:]|(([\%]?[\%])|([\#]?[\#]))|([\:]?[\=\+\?\-]))({NAME}|[\[]{NAME}[\]])|([\#]{NAME})
VAR = ({NAME}|([\$][\{]({NAME}|{SHELL_VAR}|{EXPANDED_VAR})[\}])|([\$]({NAME}|{SHELL_VAR})))
+FUNCSTART = \{ | \( | \(\( | \[\[ | "if" | "case" | "select" | "for" | "while" | "until"
+FUNCEND = \} | \) | \)\) | \]\] | "fi" | "esac" | "done"
OPERATOR_RIGHT = [\>]|[\>][\&]|[\&][\>]|[\>][\>]|[\>][\>][\>]
OPERATOR_LEFT = [\<]|[\<][\&]|[\&][\<]|[\<][\<]|[\<][\<][\<]
@@ -92,10 +97,18 @@ IGNORE = {REDIRECT_IGNORE} | {STRING_ESCAPED} | ([\\][\#]) | "ssh"
%{
private static final Logger LOGGER = Logger.getLogger(COMFLOWFileExistence.class.getName());
- private String location = "MAIN PROGRAM";
- private String parsedFileName;
-
+
+ /* MAINPROGRAM: constant for main program localisation */
+ private static final String MAINPROGRAM = "MAIN PROGRAM";
+
+ String location = MAINPROGRAM;
+ /* functionLine: the beginning line of the function */
+ int functionLine = 0;
+
+ private String parsedFileName;
+ private Stack functionStack = new Stack<>();
+
List filesExistence = new ArrayList();
private String stringBeginner = "";
@@ -116,6 +129,23 @@ IGNORE = {REDIRECT_IGNORE} | {STRING_ESCAPED} | ([\\][\#]) | "ssh"
this.zzReader = new FileReader(new Path(file.getAbsolutePath()).toOSString());
LOGGER.fine("end method setInputFile");
}
+
+ private void endLocation() throws JFlexException {
+ try{
+ Function functionFinished = functionStack.pop();
+ if (!functionStack.empty()) {
+ /* there is a current function: change location to this function */
+ location = functionStack.peek().getName();
+ } else {
+ /* we are in the main program: change location to main */
+ location = MAINPROGRAM;
+ }
+ }catch(EmptyStackException e){
+ final String errorMessage = e.getMessage();
+ throw new JFlexException(this.getClass().getName(), parsedFileName,
+ errorMessage, yytext(), yyline, yycolumn);
+ }
+ }
%}
@@ -145,9 +175,10 @@ IGNORE = {REDIRECT_IGNORE} | {STRING_ESCAPED} | ([\\][\#]) | "ssh"
/************************/
{
- {VAR} {location = yytext();
+ {FNAME} {location = yytext();
+ functionLine = yyline+1;
LOGGER.fine("["+this.parsedFileName+":"+(yyline+1)+":"+yycolumn+"] - NAMING -> YYINITIAL (Transition : VAR \""+yytext()+"\" )");
- yybegin(YYINITIAL);}
+ yybegin(BEGINFUNC);}
\n {
LOGGER.fine("["+this.parsedFileName+":"+(yyline+1)+":"+yycolumn+"] - NAMING -> YYINITIAL (Transition : \\n )");
yybegin(YYINITIAL);}
@@ -165,8 +196,28 @@ IGNORE = {REDIRECT_IGNORE} | {STRING_ESCAPED} | ([\\][\#]) | "ssh"
yybegin(NAMING);
}
{FUNCT} {
+ functionLine = yyline+1;
location = yytext().substring(0,yytext().length()-2).trim();
+ yybegin(BEGINFUNC);
}
+ {FUNCSTART} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().getFinisher().equals(Function.finisherOf(yytext()))){
+ functionStack.peek().addStarterRepetition();
+ }
+ }
+ }
+ {FUNCEND} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().isFinisher(yytext())){
+ if(functionStack.peek().getStarterRepetition()>0) {
+ functionStack.peek().removeStarterRepetition();
+ } else {
+ endLocation();
+ }
+ }
+ }
+ }
{FILEEXIST} {
int index = yytext().indexOf('-');
String subfile = yytext().substring(index);
@@ -266,7 +317,28 @@ IGNORE = {REDIRECT_IGNORE} | {STRING_ESCAPED} | ([\\][\#]) | "ssh"
}
. {}
}
+/************************/
+/* BEGINFUNC STATE */
+/************************/
+/*
+ * This state's target is to retrieve the function starter. For more information on fonction starter, have a look on {@link Function} class.
+ * Pending this starter, the function ender can be defined.
+ *
+ */
+
+ {
+ \(\) {}
+ {FUNCSTART} {
+ Function function;
+ function = new Function(location, functionLine, yytext());
+ functionStack.push(function);
+ yybegin(YYINITIAL);
+ }
+ [^]|{SPACE} {}
+ }
+
+
/************************/
/* ERROR STATE */
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/COMFLOWFilePath.lex b/fr.cnes.analysis.tools.shell.rules/lex/COMFLOWFilePath.lex
index b499c906..307337ad 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/COMFLOWFilePath.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/COMFLOWFilePath.lex
@@ -18,12 +18,15 @@ import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.File;
import java.util.List;
+import java.util.EmptyStackException;
+import java.util.Stack;
import org.eclipse.core.runtime.Path;
import fr.cnes.analysis.tools.analyzer.datas.AbstractChecker;
import fr.cnes.analysis.tools.analyzer.datas.CheckResult;
import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
+import fr.cnes.analysis.tools.shell.metrics.Function;
%%
@@ -39,21 +42,68 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
%type List
-%state COMMENT, NAMING, INITIALISATION
+%state COMMENT, NAMING, FILE, STRING, BEGINFUNC
COMMENT_WORD = \#
FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
SPACE = [\ \r\t\f]
-VAR = [a-zA-Z][a-zA-Z0-9\_]*
+NAME = ([a-zA-Z\_][a-zA-Z0-9\_]*)
+SHELL_VAR = ([0-9]+|[\-\@\?\#\!\_\*\$])
+EXPANDED_VAR = [\!]?{NAME}([\:]|(([\%]?[\%])|([\#]?[\#]))|([\:]?[\=\+\?\-]))({NAME}|[\[]{NAME}[\]])|([\#]{NAME})
+VAR = ({NAME}|([\$][\{]({NAME}|{SHELL_VAR}|{EXPANDED_VAR})[\}])|([\$]({NAME}|{SHELL_VAR})))
-POSERROR = {VAR}\= | \> | "cat" | "rm" | "more"
-FILEEXT = \.[a-zA-Z][^\.]{0,5}
-
+STRING = [\"]|[\']
+ESCAPE = [\\]
+FILE_SEPARATOR = [\/]|[\\]
+
+FILECHAR = [a-zA-Z0-9\_\.\?\!\^\+\*\-\%\ยง]
+FILEWORD = (([\.]?{FILE_SEPARATOR})|([\~]))?(({FILECHAR}+|{VAR}){FILE_SEPARATOR}?)+
+FILESTRING = (([\"]{SPACE}*{FILEWORD}{SPACE}*[\"])|([\']{SPACE}*{FILEWORD}{SPACE}*[\'])|{FILEWORD})+
+
+FILEEXIST = "test" (\!)? {SPACE}+ {OPTION}{SPACE}+{FILESTRING}+ | \[ {SPACE}* (\!)? {SPACE}+ {OPTION}{SPACE}+{FILESTRING}+ {SPACE}+ \]
+
+OPTION = \- ("a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "k" |
+ "p" | "r" | "s" | "u" | "w" | "x" | "O" | "G" | "L" |
+ "N" | "S")
+
+COMMAND_END = [\n] | [\;] | [\|] | [\`]
+COMMAND_NAME = "cat" | "tee" | "more" | "less" | "head" | "wc" | "sh" | "rm"
+GREP_COMMAND = "grep"{SPACE}+(([\-][AB]{SPACE}+[0-9]+{SPACE}+)?|([\-]?[\-][a-zC-Z]+{SPACE}+)?)*([\-][\e]{SPACE}+)?[\^]?(([\"]([^\"]|([\\][\"]))*[\"])|([\']([^\']|([\\][\']))*[\'])|({FNAME}+|{VAR})+)
+BASE_COMMAND = {COMMAND_NAME}{SPACE}+([\-]?[\-]({VAR}|{FNAME})+([\=]({VAR}|{FNAME})+)?{SPACE}*)*{SPACE}*
+ASSIGN = {VAR}\={SPACE}*([\-]?[\-]({VAR}|{FNAME})+([\=]({VAR}|{FNAME})+)?{SPACE}*)*{SPACE}*
+FILE_COMMAND = {GREP_COMMAND} | {BASE_COMMAND} | {ASSIGN}
+
+OPERATOR_RIGHT = [\>]|[\>][\&]|[\&][\>]|[\>][\>]|[\>][\>][\>]
+OPERATOR_LEFT = [\<]|[\<][\&]|[\&][\<]|[\<][\<]|[\<][\<][\<]
+OPERATOR_RL = [\<][\>]
+RIGHT_FILE_REDIRECT = ({OPERATOR_RIGHT}|{OPERATOR_RL}){SPACE}*{FILESTRING}
+LEFT_FILE_REDIRECT = {FILESTRING}{SPACE}*({OPERATOR_LEFT}|{OPERATOR_RL})
+REDIRECT_IGNORE = ([0-2]({OPERATOR_LEFT}|{OPERATOR_RL})) | (({OPERATOR_RIGHT}|{OPERATOR_RL})[0-2])
+
+STRING_ESCAPED = [\\]{STRING}
+IGNORE = {REDIRECT_IGNORE} | {STRING_ESCAPED} | ([\\][\#]) | "ssh"
+
+FUNCSTART = \{ | \( | \(\( | \[\[ | "if" | "case" | "select" | "for" | "while" | "until"
+FUNCEND = \} | \) | \)\) | \]\] | "fi" | "esac" | "done"
+
%{
- String location = "MAIN PROGRAM";
+ /* MAINPROGRAM: constant for main program localisation */
+ private static final String MAINPROGRAM = "MAIN PROGRAM";
+
+ String location = MAINPROGRAM;
+ /* functionLine: the beginning line of the function */
+ int functionLine = 0;
+
private String parsedFileName;
+ private String stringBeginner = "";
+ private boolean escapeNext = false;
+
+ private Stack functionStack = new Stack<>();
+
+
public COMFLOWFilePath() {
}
@@ -64,7 +114,24 @@ FILEEXT = \.[a-zA-Z][^\.]{0,5}
this.parsedFileName = file.toString();
this.zzReader = new FileReader(new Path(file.getAbsolutePath()).toOSString());
}
-
+
+ private void endLocation() throws JFlexException {
+ try{
+ Function functionFinished = functionStack.pop();
+ if (!functionStack.empty()) {
+ /* there is a current function: change location to this function */
+ location = functionStack.peek().getName();
+ } else {
+ /* we are in the main program: change location to main */
+ location = MAINPROGRAM;
+ }
+ }catch(EmptyStackException e){
+ final String errorMessage = e.getMessage();
+ throw new JFlexException(this.getClass().getName(), parsedFileName,
+ errorMessage, yytext(), yyline, yycolumn);
+ }
+ }
+
%}
%eofval{
@@ -94,7 +161,7 @@ FILEEXT = \.[a-zA-Z][^\.]{0,5}
/************************/
{
- {VAR} {location = yytext(); yybegin(YYINITIAL);}
+ {FNAME} {location = yytext(); functionLine = yyline+1; yybegin(BEGINFUNC);}
\n {yybegin(YYINITIAL);}
. {}
}
@@ -104,24 +171,116 @@ FILEEXT = \.[a-zA-Z][^\.]{0,5}
/************************/
{
- {COMMENT_WORD} {yybegin(COMMENT);}
+ {COMMENT_WORD} {if (!escapeNext) {yybegin(COMMENT);}}
{FUNCTION} {yybegin(NAMING);}
- {FUNCT} {location = yytext().substring(0,yytext().length()-2).trim();}
- {POSERROR} {yybegin(INITIALISATION);}
- {VAR} {} /* Clause to match with words */
- [^] {}
+ {FUNCT} {functionLine = yyline+1;
+ location = yytext().substring(0,yytext().length()-2).trim();
+ yybegin(BEGINFUNC);
+ }
+ {FUNCSTART} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().getFinisher().equals(Function.finisherOf(yytext()))){
+ functionStack.peek().addStarterRepetition();
+ }
+ }
+ }
+ {FUNCEND} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().isFinisher(yytext())){
+ if(functionStack.peek().getStarterRepetition()>0) {
+ functionStack.peek().removeStarterRepetition();
+ } else {
+ endLocation();
+ }
+ }
+ }
+ }
+ {IGNORE} {}
+ {FILEEXIST} {
+ int index = yytext().indexOf('-');
+ String subfile = yytext().substring(index);
+ String name = subfile.replaceAll("\"", "").replaceAll("\\{", "").replaceAll("\\}", "").replaceAll("]", "").split(" ")[1];
+ setError(location,"It is forbidden to use a file name such as " + name + " directly.", yyline+1);
+ }
+ {LEFT_FILE_REDIRECT}|{RIGHT_FILE_REDIRECT}
+ {
+ String name = yytext().replaceAll("([\\s]|[\\>]|[\\\"]|[\\']|[\\<]|[\\&]|[\\{]|[\\}])+","");
+ setError(location,"It is forbidden to use a file name such as " + name + " directly.", yyline+1);
+ }
+ {FILE_COMMAND} {yybegin(FILE);}
+ {STRING} {
+ stringBeginner=yytext();
+ yybegin(STRING);
+ }
+ [^] {}
}
/************************/
-/* INITIALISATION STATE */
+/* FILE STATE */
/************************/
-
+
{
- {FILEEXT} {setError(location,"It is not allowed to specify the file with this name. Use a variable instead.", yyline+1); yybegin(YYINITIAL);}
- \n | \; {yybegin(YYINITIAL);}
- . {}
+ {FILESTRING}+ {
+ String name = yytext().replaceAll("([\\\"]|[\\']|[\\{]|[\\}]|[\\[]|[\\]])+","");
+ setError(location,"It is forbidden to use a file name such as " + name + " directly.", yyline+1);
+ escapeNext=false;
+ yybegin(YYINITIAL);
+ }
+ {COMMAND_END} {escapeNext=false; yybegin(YYINITIAL);}
+ {LEFT_FILE_REDIRECT}|{RIGHT_FILE_REDIRECT}
+ {
+ String name = yytext().replaceAll("([\\s]|[\\>]|[\\\"]|[\\']|[\\<]|[\\&]|[\\{]|[\\}])+","");
+ setError(location,"It is forbidden to use a file name such as " + name + " directly.", yyline+1);
+ escapeNext=false;
+ yybegin(YYINITIAL);
+ }
+ . {}
}
+/************************/
+/* STRING STATE */
+/************************/
+
+ {
+ {ESCAPE} {
+ if(!escapeNext)
+ {
+ escapeNext=true;
+ } else
+ {
+ escapeNext=false;
+ }
+ }
+ {STRING} {
+ if(!escapeNext && yytext().equals(stringBeginner))
+ {
+ yybegin(YYINITIAL);
+ }
+ escapeNext=false;
+ }
+ {COMMENT_WORD} {escapeNext=false;}
+ [^] {escapeNext=false;}
+ }
+
+/************************/
+/* BEGINFUNC STATE */
+/************************/
+/*
+ * This state target is to retrieve the function starter. For more information on fonction starter, have a look on {@link Function} class.
+ * Pending this starter, the function ender can be defined.
+ *
+ */
+
+ {
+ \(\) {}
+ {FUNCSTART} {
+ Function function;
+ function = new Function(location, functionLine, yytext());
+ functionStack.push(function);
+ yybegin(YYINITIAL);
+ }
+ [^]|{SPACE} {}
+ }
/************************/
/* ERROR STATE */
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/COMFLOWRecursion.lex b/fr.cnes.analysis.tools.shell.rules/lex/COMFLOWRecursion.lex
index 8b95640b..844a088d 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/COMFLOWRecursion.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/COMFLOWRecursion.lex
@@ -17,16 +17,20 @@ package fr.cnes.analysis.tools.shell.rules;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.File;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.EmptyStackException;
+import java.util.Stack;
import org.eclipse.core.runtime.Path;
import fr.cnes.analysis.tools.analyzer.datas.AbstractChecker;
import fr.cnes.analysis.tools.analyzer.datas.CheckResult;
import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
+import fr.cnes.analysis.tools.shell.metrics.Function;
%%
@@ -41,28 +45,50 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
%type List
-%state COMMENT, FUNCOMMENT, NAMING, FUNCTIONSTATE
+%state COMMENT, NAMING, BEGINFUNC, STRING_DOUBLE, STRING_SIMPLE
COMMENT_WORD = \#
FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
-SPACE = [\ \r\t\f]
-VAR = [a-zA-Z][a-zA-Z0-9\_\-]*
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
STRING = \'[^\']*\' | \"[^\"]*\"
+IGNORE = "EOF" [^]* "EOF"
+
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
+SPACE = [\ \r\t\f]
+NAME = [a-zA-Z\_][a-zA-Z0-9\_]*
+SHELL_VAR = ([0-9]+|[\-\@\?\#\!\_\*\$])
+EXPANDED_VAR = [\$][\{](([\:]{SPACE}*[\-])|[a-zA-Z0-9\_\:\%\=\+\?\/\!\-\,\^\#\*\@]|([\[](([\:]{SPACE}*[\-])|[a-zA-Z0-9\_\/\:\%\=\+\?\!\$\-\,\^\#\*\@\[\]\{\}])+[\]]))+[\}]
+VAR = {NAME}|{EXPANDED_VAR}|([\$]({NAME}|{SHELL_VAR}))
+
OPTCHAR = \# | \! | % | \* | @ | \^ | \' | , | \/ | : | = | \+ | \?
EXTENDEDVAR = \$\{ {OPTCHAR}* {VAR} {OPTCHAR}* {VAR}? (\[)? {OPTCHAR}* (\])? \}
-IGNORE = "EOF" [^]* "EOF"
+
+FUNCSTART = \{ | \( | \(\( | \[\[ | "if" | "case" | "select" | "for" | "while" | "until"
+FUNCEND = \} | \) | \)\) | \]\] | "fi" | "esac" | "done"
+
+STRING_D = \"
+IGNORE_STRING_D = [\\][\"]
+STRING_S = \'
+IGNORE_STRING_S = [\\][\']
%{
- String location = "MAIN PROGRAM";
- /** Map that contains all the functions with its calls **/
+ /* MAINPROGRAM: constant for main program localisation */
+ private static final String MAINPROGRAM = "MAIN PROGRAM";
+
+ String location = MAINPROGRAM;
+ int brackets = 0;
+ /* functionLine: the beginning line of the function */
+ int functionLine = 0;
+
+ /** Map that contains all the functions with its calls **/
Map> functionCalls = new HashMap>();
/** Current list of calls **/
List calls = new ArrayList();
- /** Number of brackets **/
- int brackets = 0;
+
+ private String parsedFileName;
+ private Stack functionStack = new Stack<>();
public COMFLOWRecursion() {
}
@@ -80,16 +106,51 @@ IGNORE = "EOF" [^]* "EOF"
* @param
* var: string called inside the current function
*/
- private void checkCircularCalling(String var) throws JFlexException {
+ private Boolean checkCircularCalling(String var) throws JFlexException {
List callings = functionCalls.get(var);
if (callings!=null) {
- if (callings.contains(location)) setError(location,"The use of recursivity is not allowed.", yyline+1);
+ if (callings.contains(location)) {
+ setError(location,"The use of recursivity is not allowed.", yyline+1);
+ return true;
+ }
else {
- for (String element : callings) checkCircularCalling(element);
+ Boolean found = false;
+ for (String element : callings) {
+ found = checkCircularCalling(element);
+ if (found) return true;
+ }
}
}
+ return false;
}
-
+
+ private void endLocation() throws JFlexException {
+ try{
+ Function functionFinished = functionStack.pop();
+ List list = new ArrayList(calls);
+ functionCalls.put(location,list);
+ calls.clear();
+
+ if (!functionStack.empty()) {
+ /* there is a current function: change location to this function */
+ location = functionStack.peek().getName();
+ List currentCalls = functionCalls.get(location);
+ if (currentCalls != null)
+ {
+ calls.addAll(currentCalls);
+ }
+ } else {
+ /* we are in the main program: change location to main */
+ location = MAINPROGRAM;
+ }
+ }catch(EmptyStackException e){
+ final String errorMessage = e.getMessage();
+ throw new JFlexException(this.getClass().getName(), parsedFileName,
+ errorMessage, yytext(), yyline, yycolumn);
+ }
+ }
+
+
%}
%eofval{
@@ -114,21 +175,13 @@ IGNORE = "EOF" [^]* "EOF"
. {}
}
-/************************/
-/* FUNCOMMENT STATE */
-/************************/
-
- {
- \n {yybegin(FUNCTIONSTATE);}
- . {}
- }
-
+
/************************/
/* NAMING STATE */
/************************/
{
- {VAR} {location = yytext(); brackets=0; yybegin(FUNCTIONSTATE);}
+ {FNAME} {location = yytext(); yybegin(BEGINFUNC);}
\n {yybegin(YYINITIAL);}
. {}
}
@@ -139,38 +192,89 @@ IGNORE = "EOF" [^]* "EOF"
{
{COMMENT_WORD} {yybegin(COMMENT);}
+ {STRING_D} {yybegin(STRING_DOUBLE);}
+ {STRING_S} {yybegin(STRING_SIMPLE);}
{FUNCTION} {yybegin(NAMING);}
- {FUNCT} {location = yytext().substring(0,yytext().length()-2).trim(); brackets=0; yybegin(FUNCTIONSTATE);}
- {STRING} {}
+ {FUNCT} {location = yytext().substring(0,yytext().length()-2).trim(); brackets=0; yybegin(BEGINFUNC);}
+ {FUNCSTART} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().getFinisher().equals(Function.finisherOf(yytext()))){
+ functionStack.peek().addStarterRepetition();
+ }
+ }
+ }
+ {FUNCEND} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().isFinisher(yytext())){
+ if(functionStack.peek().getStarterRepetition()>0) {
+ functionStack.peek().removeStarterRepetition();
+ } else {
+ endLocation();
+ }
+ }
+ }
+ }
+ {VAR} {/** call to the same function **/
+ if(yytext().equals(location)) setError(location,"The use of recursivity is not allowed.", yyline+1);
+ /** save in list to verify circular calling **/
+ else {
+ if (!functionStack.empty()){
+ // we are in a function
+ checkCircularCalling(yytext());
+ if (!calls.contains(yytext()))
+ calls.add(yytext());
+ }
+ }
+ }
. {}
+
}
/************************/
-/* FUNCTIONSTATE STATE */
+/* BEGINFUNC STATE */
/************************/
-
+/*
+ * This state target is to retrieve the function starter. For more information on fonction starter, have a look on {@link Function} class.
+ * Pending this starter, the function ender can be defined.
+ *
+ */
+
{
- {COMMENT_WORD} {yybegin(FUNCOMMENT);}
- {STRING} {}
- {EXTENDEDVAR} {}
- {VAR} {/** call to the same function **/
- if(yytext().equals(location)) setError(location,"The use of recursivity is not allowed.", yyline+1);
- /** save in list to verify circular calling **/
- else {
- calls.add(yytext());
- checkCircularCalling(yytext());
- }}
- \{(\#)? {brackets++;}
- \} {brackets--;
- if(brackets==0) {
- List list = new ArrayList(calls);
- functionCalls.put(location,list);
- calls.clear();
- yybegin(YYINITIAL);}}
- {IGNORE} {}
- . {}
+ \(\) {}
+ {FUNCSTART} {
+ Function function;
+ function = new Function(location, functionLine, yytext());
+ functionStack.push(function);
+ yybegin(YYINITIAL);
+ }
+ [^]|{SPACE} {}
}
+
+/*
+ * The string states are designed to avoid problems due to patterns found in strings.
+ */
+/************************/
+/* STRING_SIMPLE STATE */
+/************************/
+
+ {
+ {IGNORE_STRING_S} {}
+ {STRING_S} {yybegin(YYINITIAL);}
+ [^]|{SPACE} {}
+ }
+
+/************************/
+/* STRING_DOUBLE STATE */
+/************************/
+
+ {
+ {IGNORE_STRING_D} {}
+ {STRING_D} {yybegin(YYINITIAL);}
+ [^]|{SPACE} {}
+ }
+
+
/************************/
/* ERROR STATE */
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/COMINSTBoolNegation.lex b/fr.cnes.analysis.tools.shell.rules/lex/COMINSTBoolNegation.lex
index e0097449..915b9e96 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/COMINSTBoolNegation.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/COMINSTBoolNegation.lex
@@ -18,12 +18,15 @@ import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.File;
import java.util.List;
+import java.util.EmptyStackException;
+import java.util.Stack;
import org.eclipse.core.runtime.Path;
import fr.cnes.analysis.tools.analyzer.datas.AbstractChecker;
import fr.cnes.analysis.tools.analyzer.datas.CheckResult;
import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
+import fr.cnes.analysis.tools.shell.metrics.Function;
%%
@@ -39,14 +42,24 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
%type List
-%state COMMENT, NAMING, LOGICAL
+%state COMMENT, NAMING, LOGICAL, BEGINFUNC, STRING_SIMPLE, STRING_DOUBLE
COMMENT_WORD = \#
FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
SPACE = [\ \r\t\f]
VAR = [a-zA-Z][a-zA-Z0-9\_]*
-STRING = \'[^\']*\' | \"[^\"]*\"
+
+IGNORE = \$\{[^\}"\n"]*\} | \$\([^\)"\n"]*\)
+
+FUNCSTART = \{ | \( | \(\( | \[\[ | "if" | "case" | "select" | "for" | "while" | "until"
+FUNCEND = \} | \) | \)\) | \]\] | "fi" | "esac" | "done"
+
+STRING_D = \"
+IGNORE_STRING_D = [\\][\"]
+STRING_S = \'
+IGNORE_STRING_S = [\\][\']
NOT = \!
OPER = \&\& | \|\| | \-"o" | \-"a"
@@ -54,11 +67,19 @@ OPER = \&\& | \|\| | \-"o" | \-"a"
%{
- String location = "MAIN PROGRAM";
+ /* MAINPROGRAM: constant for main program localisation */
+ private static final String MAINPROGRAM = "MAIN PROGRAM";
+
+ String location = MAINPROGRAM;
+ /* functionLine: the beginning line of the function */
+ int functionLine = 0;
+
private String parsedFileName;
/** Bool to knkow if there are open brackets **/
int bracket = 0, brace = 0, parenth = 0;
+ private Stack functionStack = new Stack<>();
+
public COMINSTBoolNegation() {
}
@@ -70,6 +91,22 @@ OPER = \&\& | \|\| | \-"o" | \-"a"
this.zzReader = new FileReader(new Path(file.getAbsolutePath()).toOSString());
}
+ private void endLocation() throws JFlexException {
+ try{
+ Function functionFinished = functionStack.pop();
+ if (!functionStack.empty()) {
+ /* there is a current function: change location to this function */
+ location = functionStack.peek().getName();
+ } else {
+ /* we are in the main program: change location to main */
+ location = MAINPROGRAM;
+ }
+ }catch(EmptyStackException e){
+ final String errorMessage = e.getMessage();
+ throw new JFlexException(this.getClass().getName(), parsedFileName,
+ errorMessage, yytext(), yyline, yycolumn);
+ }
+ }
%}
@@ -100,7 +137,7 @@ OPER = \&\& | \|\| | \-"o" | \-"a"
/************************/
{
- {VAR} {location = yytext(); yybegin(YYINITIAL);}
+ {FNAME} {location = yytext(); yybegin(BEGINFUNC);}
\n {yybegin(YYINITIAL);}
. {}
}
@@ -111,10 +148,30 @@ OPER = \&\& | \|\| | \-"o" | \-"a"
{
{COMMENT_WORD} {yybegin(COMMENT);}
+ {STRING_D} {yybegin(STRING_DOUBLE);}
+ {STRING_S} {yybegin(STRING_SIMPLE);}
{FUNCTION} {yybegin(NAMING);}
- {FUNCT} {location = yytext().substring(0,yytext().length()-2).trim();}
+ {FUNCT} {location = yytext().substring(0,yytext().length()-2).trim(); yybegin(BEGINFUNC);}
+ {IGNORE} {}
{NOT} {bracket=0; brace=0; parenth=0; yybegin(LOGICAL);}
- {STRING} {}
+ {FUNCSTART} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().getFinisher().equals(Function.finisherOf(yytext()))){
+ functionStack.peek().addStarterRepetition();
+ }
+ }
+ }
+ {FUNCEND} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().isFinisher(yytext())){
+ if(functionStack.peek().getStarterRepetition()>0) {
+ functionStack.peek().removeStarterRepetition();
+ } else {
+ endLocation();
+ }
+ }
+ }
+ }
[^] {}
}
@@ -135,6 +192,48 @@ OPER = \&\& | \|\| | \-"o" | \-"a"
. {}
}
+/************************/
+/* BEGINFUNC STATE */
+/************************/
+/*
+ * This state target is to retrieve the function starter. For more information on fonction starter, have a look on {@link Function} class.
+ * Pending this starter, the function ender can be defined.
+ *
+ */
+
+ {
+ \(\) {}
+ {FUNCSTART} {
+ Function function;
+ function = new Function(location, functionLine, yytext());
+ functionStack.push(function);
+ yybegin(YYINITIAL);
+ }
+ [^]|{SPACE} {}
+ }
+
+/*
+ * The string states are designed to avoid problems due to patterns found in strings.
+ */
+/************************/
+/* STRING_SIMPLE STATE */
+/************************/
+
+ {
+ {IGNORE_STRING_S} {}
+ {STRING_S} {yybegin(YYINITIAL);}
+ [^]|{SPACE} {}
+ }
+
+/************************/
+/* STRING_DOUBLE STATE */
+/************************/
+
+ {
+ {IGNORE_STRING_D} {}
+ {STRING_D} {yybegin(YYINITIAL);}
+ [^]|{SPACE} {}
+ }
/************************/
/* ERROR STATE */
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/COMINSTBrace.lex b/fr.cnes.analysis.tools.shell.rules/lex/COMINSTBrace.lex
index 960de83d..3b8e5611 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/COMINSTBrace.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/COMINSTBrace.lex
@@ -44,7 +44,8 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
COMMENT_WORD = \#
FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
SPACE = [\ \r\t\f]
VAR = [a-zA-Z][a-zA-Z0-9\_]*
@@ -159,7 +160,7 @@ BRACING = "expr" | "let"
/************************/
{
- {FUNCT} {location = yytext().substring(0,yytext().length()-2).trim(); yybegin(YYINITIAL);}
+ {FNAME} {location = yytext().substring(0,yytext().length()-2).trim(); yybegin(YYINITIAL);}
\n {yybegin(YYINITIAL);}
. {}
}
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/COMINSTCodeComment.lex b/fr.cnes.analysis.tools.shell.rules/lex/COMINSTCodeComment.lex
index 5a0b0a69..d5a76987 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/COMINSTCodeComment.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/COMINSTCodeComment.lex
@@ -43,7 +43,8 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
COMMENT_WORD = \#
FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
SPACE = [\ \r\t\f]
VAR = [a-zA-Z][a-zA-Z0-9\_]*
STRING = \'[^\']*\' | \"[^\"]*\"
@@ -162,7 +163,7 @@ CLE = {RESERVED}| {POSIX} | {BUILTINS}
/************************/
{
- {VAR} {location = yytext(); loc.add(yytext()); yybegin(PREHEADER);}
+ {FNAME} {location = yytext(); loc.add(yytext()); yybegin(PREHEADER);}
\n {yybegin(YYINITIAL);}
. {}
}
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/COMINSTLine.lex b/fr.cnes.analysis.tools.shell.rules/lex/COMINSTLine.lex
index 27271234..98d32cf6 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/COMINSTLine.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/COMINSTLine.lex
@@ -46,7 +46,8 @@ import java.util.logging.Logger;
COMMENT_WORD = [\#]
FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
SPACE = [\ \r\t\f]
VALUE = [0-9][0-9]*([\.][0-9][0-9]*)?
VAR = ([a-zA-Z][a-zA-Z0-9\_\-]*)|([$]([\-\@\?\#\!\_\*]|([a-zA-Z0-9]*)|[\{][a-zA-Z0-9]*[\}]))
@@ -118,7 +119,7 @@ CONDITIONAL_STRUCT = [\[][\[]({VAR}|{SPACE}|{VALUE}|{OPERATOR}|{BRACKET})*[\]][
/************************/
{
- {VAR} {
+ {FNAME} {
location = yytext();
LOGGER.fine("["+this.parsedFileName+":"+(yyline+1)+":"+yycolumn+"] - NAMING -> YYINITIAL (Transition : VAR \""+yytext()+"\" )");
yybegin(YYINITIAL);}
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/COMINSTLoopCondition.lex b/fr.cnes.analysis.tools.shell.rules/lex/COMINSTLoopCondition.lex
index 7580cb14..78da2a27 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/COMINSTLoopCondition.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/COMINSTLoopCondition.lex
@@ -43,7 +43,8 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
COMMENT_WORD = \#
FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
SPACE = [\ \r\t\f]
VAR = [a-zA-Z][a-zA-Z0-9\_]*
STRING = \'[^\']*\' | \"[^\"]*\"
@@ -111,7 +112,7 @@ LOOP = {WHILE} | {UNTIL}
/************************/
{
- {VAR} {location = yytext(); yybegin(YYINITIAL);}
+ {FNAME} {location = yytext(); yybegin(YYINITIAL);}
\n {yybegin(YYINITIAL);}
. {}
}
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/COMNAMEHomonymy.lex b/fr.cnes.analysis.tools.shell.rules/lex/COMNAMEHomonymy.lex
index 8534368a..a273eb16 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/COMNAMEHomonymy.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/COMNAMEHomonymy.lex
@@ -44,7 +44,8 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
COMMENT_WORD = \#
FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
SPACE = [\ \r\t\f]
VAR = [a-zA-Z0-9\_\-]+
STRING = \'[^\']*\' | \"[^\"]*\"
@@ -267,7 +268,7 @@ FUNCEND = \} | \) | \)\) | \]\] | "fi" | "esac" | "done"
/************************/
{
- {VAR} {location = yytext(); functions.add(yytext()); yybegin(BEGINFUNC);}
+ {FNAME} {location = yytext(); functions.add(yytext()); yybegin(BEGINFUNC);}
\n {yybegin(YYINITIAL);}
. {}
}
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/COMPRESHeader.lex b/fr.cnes.analysis.tools.shell.rules/lex/COMPRESHeader.lex
index 977e9f81..1d78b587 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/COMPRESHeader.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/COMPRESHeader.lex
@@ -44,7 +44,8 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
COMMENT_WORD = \#
FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
SPACE = [\ \r\t\f]
VAR = [a-zA-Z][a-zA-Z0-9\_]* | \$\#
STRING = \'[^\']*\' | \"[^\"]*\"
@@ -158,7 +159,7 @@ STRING = \'[^\']*\' | \"[^\"]*\"
/************************/
{
- {VAR} {if (first){
+ {FNAME} {if (first){
errorLine = yyline + 1;
location = yytext();
first=false;
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/COMPRESIndent.lex b/fr.cnes.analysis.tools.shell.rules/lex/COMPRESIndent.lex
index 1931ed3e..d1b9e581 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/COMPRESIndent.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/COMPRESIndent.lex
@@ -19,12 +19,15 @@ import java.io.FileReader;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
+import java.util.EmptyStackException;
+import java.util.Stack;
import org.eclipse.core.runtime.Path;
import fr.cnes.analysis.tools.analyzer.datas.AbstractChecker;
import fr.cnes.analysis.tools.analyzer.datas.CheckResult;
import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
+import fr.cnes.analysis.tools.shell.metrics.Function;
%%
@@ -39,29 +42,49 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
%type List
-%state COMMENT, NAMING, AVOID
+%state COMMENT, NAMING, CONSUME_LINE, BEGINFUNC, STRING_SIMPLE, STRING_DOUBLE
COMMENT_WORD = \#
FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
+FUNCT = {FNAME}{SPACETAB}*[\(]{SPACETAB}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
+
SPACE = [\ \r\f]
TAB = [\t]
SPACETAB = {SPACE}|{TAB}
VAR = [a-zA-Z][a-zA-Z0-9\_]*
CONTINUEDLINE = \\ {SPACETAB}* \n
-BEGIN = "if" | "case" | "for" | "while" |
- "until"
+CASE_STMT = [^"\n""("" ""\r""\f""#"][^"\n""("]*\)
+
+CASE = "case"
+ESAC = "esac"
+
+BEGIN = "if" | "case" | "for" | "while" | "until"
CONT = "do" | "then"
END = "done" | "fi" | "esac"
ELSE = "else" | "elif"
+FUNCSTART = \{ | \( | \(\( | \[\[ | "if" | "case" | "select" | "for" | "while" | "until"
+FUNCEND = \} | \) | \)\) | \]\] | "fi" | "esac" | "done"
+
+STRING_D = \"
+IGNORE_STRING_D = [\\][\"]
+STRING_S = \'
+IGNORE_STRING_S = [\\][\']
+
IGNORETEXT = "<<" {SPACE}* "EOF" [^"<<"]* "EOF" | ` [^`]* `
%{
- String location = "MAIN PROGRAM";
+ /* MAINPROGRAM: constant for main program localisation */
+ private static final String MAINPROGRAM = "MAIN PROGRAM";
+
+ String location = MAINPROGRAM;
+ /* functionLine: the beginning line of the function */
+ int functionLine = 0;
+
private String parsedFileName;
int currentPos = 0, pos = 0;
List desiredPos = new ArrayList();
@@ -69,10 +92,17 @@ IGNORETEXT = "<<" {SPACE}* "EOF" [^"<<"]* "EOF" | ` [^`]* `
Boolean inTabs = false;
/* indentationRequired is true when the next line should be indented compared to the last */
Boolean indentationRequired = false;
- /* avoid is true when the {} should not be taken into account */
- Boolean avoid = false;
- /* checkEnd is true when in AVOID we are after a ";", requiring that ENDs should be taken into account */
+ /* checkEnd is true when in CONSUME_LINE we are after a ";", requiring that ENDs should be taken into account */
Boolean checkEnd=false;
+
+ /* firstInCase is true when the case statement is the first one of a case structure */
+ Boolean firstInCase = false;
+
+ /* decrementAtEnd is true when the body of the function is incremented, eg. when body is an if */
+ /* with no { and is incremented compared to the function line */
+ Boolean decrementAtEnd = false;
+
+ private Stack functionStack = new Stack<>();
public COMPRESIndent() {
desiredPos.add(0);
@@ -105,7 +135,7 @@ IGNORETEXT = "<<" {SPACE}* "EOF" [^"<<"]* "EOF" | ` [^`]* `
indentationRequired = false; /* continue at same position */
} else { /* indentationRequired == false */
/* we are not at the beginning of a new indentation. The indentation should be the same as the last line */
- setError(location,"This line is not indented in comparison with the last one.", yyline+1);
+ setError(location,"This line should not be indented in comparison with the last one.", yyline+1);
}
} else { /* currentPos == value */
/* The indentation is what was expected */
@@ -142,10 +172,30 @@ IGNORETEXT = "<<" {SPACE}* "EOF" [^"<<"]* "EOF" | ` [^`]* `
if (index >= 0) {
int value = desiredPos.get(index);
if (currentPos != value)
- setError(location,"This line is not indented in comparison with the last one.", yyline+1);
+ setError(location,"This line is not aligned with its corresponding structure.", yyline+1);
}
}
-
+
+ private void endLocation() throws JFlexException {
+ try{
+ Function functionFinished = functionStack.pop();
+ if (!functionStack.empty()) {
+ /* there is a current function: change location to this function */
+ location = functionStack.peek().getName();
+ } else {
+ /* we are in the main program: change location to main */
+ location = MAINPROGRAM;
+ }
+ if (decrementAtEnd) {
+ if(desiredPos.size()>=1) {desiredPos.remove(desiredPos.size()-1);}
+ decrementAtEnd = false;
+ }
+ }catch(EmptyStackException e){
+ final String errorMessage = e.getMessage();
+ throw new JFlexException(this.getClass().getName(), parsedFileName,
+ errorMessage, yytext(), yyline, yycolumn);
+ }
+ }
%}
@@ -177,21 +227,60 @@ IGNORETEXT = "<<" {SPACE}* "EOF" [^"<<"]* "EOF" | ` [^`]* `
/************************/
{
- {VAR} {location = yytext(); yybegin(AVOID);}
+ {FNAME} {location = yytext(); yybegin(BEGINFUNC);}
\n {currentPos=0; yybegin(YYINITIAL);}
. {}
}
/************************/
-/* AVOID STATE */
+/* CONSUME_LINE STATE */
/************************/
/* Consume characters till end of line */
-
+
{
; {checkEnd=true;}
{COMMENT_WORD} {checkEnd=false; yybegin(COMMENT);}
- {END} {if(checkEnd && desiredPos.size()>=1) {desiredPos.remove(desiredPos.size()-1);}}
+ {IGNORE_STRING_D} {}
+ {STRING_D} {yybegin(STRING_DOUBLE);}
+ {IGNORE_STRING_S} {}
+ {STRING_S} {yybegin(STRING_SIMPLE);}
+ {ESAC} {
+ if(checkEnd && desiredPos.size()>=1) {desiredPos.remove(desiredPos.size()-1);}
+ if(!functionStack.empty()){
+ if(functionStack.peek().isFinisher(yytext())){
+ if(functionStack.peek().getStarterRepetition()>0) {
+ functionStack.peek().removeStarterRepetition();
+ } else {
+ endLocation();
+ }
+ }
+ }
+ firstInCase = false;
+ }
+ {END} {
+ if(checkEnd && desiredPos.size()>=1) {desiredPos.remove(desiredPos.size()-1);}
+ if(!functionStack.empty()){
+ if(functionStack.peek().isFinisher(yytext())){
+ if(functionStack.peek().getStarterRepetition()>0) {
+ functionStack.peek().removeStarterRepetition();
+ } else {
+ endLocation();
+ }
+ }
+ }
+ }
+ {FUNCEND} { /* for the remaining endings not in END */
+ if(!functionStack.empty()){
+ if(functionStack.peek().isFinisher(yytext())){
+ if(functionStack.peek().getStarterRepetition()>0) {
+ functionStack.peek().removeStarterRepetition();
+ } else {
+ endLocation();
+ }
+ }
+ }
+ }
{IGNORETEXT} {}
{CONTINUEDLINE} {}
\n {checkEnd=false; currentPos=0; yybegin(YYINITIAL);}
@@ -204,26 +293,225 @@ IGNORETEXT = "<<" {SPACE}* "EOF" [^"<<"]* "EOF" | ` [^`]* `
{
{COMMENT_WORD} {inTabs=false; yybegin(COMMENT);}
- {FUNCTION} {inTabs=false; checkIndentation(); indentationRequired=true; desiredPos.add(currentPos+1); yybegin(NAMING);}
- {FUNCT} {inTabs=false; location = yytext().substring(0,yytext().length()-2).trim(); checkIndentation(); indentationRequired=true; desiredPos.add(currentPos+1); yybegin(AVOID);}
- {BEGIN} {inTabs=false; checkIndentation(); indentationRequired=true; desiredPos.add(currentPos+1); yybegin(AVOID);}
- {CONT} | {ELSE} {inTabs=false; checkIndentationElse(); indentationRequired=true; yybegin(AVOID);}
- {END} {inTabs=false; if(desiredPos.size()>=1) {desiredPos.remove(desiredPos.size()-1);} indentationRequired=false; checkIndentation(); yybegin(AVOID);}
+ {IGNORE_STRING_D} {}
+ {STRING_D} {yybegin(STRING_DOUBLE);}
+ {IGNORE_STRING_S} {}
+ {STRING_S} {yybegin(STRING_SIMPLE);}
+ {FUNCTION} {
+ inTabs=false;
+ checkIndentation();
+ indentationRequired=true;
+ desiredPos.add(currentPos+1);
+ yybegin(NAMING);
+ }
+ {FUNCT} {
+ inTabs=false;
+ location = yytext().substring(0,yytext().length()-2).trim();
+ checkIndentation();
+ indentationRequired=true;
+ desiredPos.add(currentPos+1);
+ yybegin(BEGINFUNC);
+ }
+ {CASE} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().getFinisher().equals(Function.finisherOf(yytext()))){
+ functionStack.peek().addStarterRepetition();
+ }
+ }
+ inTabs=false;
+ checkIndentation();
+ indentationRequired=true;
+ desiredPos.add(currentPos+1);
+ /* Next case statement will be the first */
+ firstInCase = true;
+ yybegin(CONSUME_LINE);
+ }
+ {BEGIN} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().getFinisher().equals(Function.finisherOf(yytext()))){
+ functionStack.peek().addStarterRepetition();
+ }
+ }
+ inTabs=false;
+ checkIndentation();
+ indentationRequired=true;
+ desiredPos.add(currentPos+1);
+ yybegin(CONSUME_LINE);
+ }
+ {CONT} | {ELSE} {
+ inTabs=false;
+ checkIndentationElse();
+ indentationRequired=true;
+ yybegin(CONSUME_LINE);
+ }
+ {ESAC} {
+ inTabs=false;
+ if(desiredPos.size()>=1) {desiredPos.remove(desiredPos.size()-1);}
+ /* Another one to compensate for the added indentation of the previous case statement */
+ if(desiredPos.size()>=1) {desiredPos.remove(desiredPos.size()-1);}
+ indentationRequired=false;
+ checkIndentation();
+ firstInCase = false;
+ if(!functionStack.empty()){
+ if(functionStack.peek().isFinisher(yytext())){
+ if(functionStack.peek().getStarterRepetition()>0) {
+ functionStack.peek().removeStarterRepetition();
+ } else {
+ endLocation();
+ }
+ }
+ }
+ yybegin(CONSUME_LINE);
+ }
+ {END} {
+ inTabs=false;
+ if(desiredPos.size()>=1) {
+ desiredPos.remove(desiredPos.size()-1);}
+ indentationRequired=false;
+ checkIndentation();
+ if(!functionStack.empty()){
+ if(functionStack.peek().isFinisher(yytext())){
+ if(functionStack.peek().getStarterRepetition()>0) {
+ functionStack.peek().removeStarterRepetition();
+ } else {
+ endLocation();
+ }
+ }
+ }
+ yybegin(CONSUME_LINE);
+ }
{TAB} {pos=currentPos; currentPos+=yytext().length();
if(pos==0 | inTabs==true) {
/* a tab was found at the beginning of a line */
inTabs=true;
setError(location,"Tabulations are not allowed.", yyline+1);
}}
- {SPACE} {if(currentPos==0) {inTabs=true;}; currentPos+=yytext().length();}
- {VAR} {inTabs=false; checkIndentation(); yybegin(AVOID);}
+ {SPACE}+ {if(currentPos==0) {inTabs=true;}; currentPos+=yytext().length();}
+ {VAR} {inTabs=false; checkIndentation(); yybegin(CONSUME_LINE);}
{IGNORETEXT} {}
- \{ {inTabs=false; yybegin(AVOID);}
- \} {inTabs=false; if(desiredPos.size()>=1) {desiredPos.remove(desiredPos.size()-1);} checkIndentationNoChange(); yybegin(AVOID);}
+ \{ {
+ if(!functionStack.empty()){
+ if(functionStack.peek().getFinisher().equals(Function.finisherOf(yytext()))){
+ functionStack.peek().addStarterRepetition();
+ }
+ }
+ inTabs=false;
+ yybegin(CONSUME_LINE);
+ }
+ \} {
+ inTabs=false;
+ if(desiredPos.size()>=1) {desiredPos.remove(desiredPos.size()-1);}
+ checkIndentationNoChange();
+ if(!functionStack.empty()){
+ if(functionStack.peek().isFinisher(yytext())){
+ if(functionStack.peek().getStarterRepetition()>0) {
+ functionStack.peek().removeStarterRepetition();
+ } else {
+ endLocation();
+ }
+ }
+ }
+ yybegin(CONSUME_LINE);
+ }
+ {FUNCSTART} { /* for the remaining beginnings not in BEGIN */
+ if(!functionStack.empty()){
+ if(functionStack.peek().getFinisher().equals(Function.finisherOf(yytext()))){
+ functionStack.peek().addStarterRepetition();
+ }
+ }
+ yybegin(CONSUME_LINE);
+ }
+ {FUNCEND} { /* for the remaining endings not in END */
+ if(!functionStack.empty()){
+ if(functionStack.peek().isFinisher(yytext())){
+ if(functionStack.peek().getStarterRepetition()>0) {
+ functionStack.peek().removeStarterRepetition();
+ } else {
+ endLocation();
+ }
+ }
+ }
+ }
\n {inTabs=false; currentPos=0;}
- . {inTabs=false; checkIndentation(); yybegin(AVOID);}
+ {CASE_STMT} {
+ inTabs=false;
+ if (!firstInCase) {
+ if(desiredPos.size()>=1) {desiredPos.remove(desiredPos.size()-1);}
+ checkIndentationNoChange();
+ } else {
+ firstInCase = false;
+ checkIndentation();
+ }
+ indentationRequired=true;
+ desiredPos.add(currentPos+1);
+ yybegin(CONSUME_LINE);
+ }
+ . {inTabs=false; checkIndentation(); yybegin(CONSUME_LINE);}
}
-
+
+/************************/
+/* BEGINFUNC STATE */
+/************************/
+/*
+ * This state target is to retrieve the function starter. For more information on fonction starter, have a look on {@link Function} class.
+ * Pending this starter, the function ender can be defined.
+ *
+ */
+
+ {
+ \(\) {}
+ "\n"{SPACE}* {
+ currentPos = currentPos+yytext().length() -1;
+ decrementAtEnd = true;
+ }
+ {BEGIN} {
+ inTabs=false;
+ checkIndentation();
+ indentationRequired=true;
+ desiredPos.add(currentPos+1);
+ Function function;
+ function = new Function(location, functionLine, yytext());
+ functionStack.push(function);
+ yybegin(CONSUME_LINE);
+ }
+ \{ {
+ inTabs=false;
+ Function function;
+ function = new Function(location, functionLine, yytext());
+ functionStack.push(function);
+ yybegin(CONSUME_LINE);
+ }
+ {FUNCSTART} {
+ Function function;
+ function = new Function(location, functionLine, yytext());
+ functionStack.push(function);
+ yybegin(CONSUME_LINE);
+ }
+ [^]|{SPACE} {}
+ }
+
+/*
+ * The string states are designed to avoid problems due to patterns found in strings.
+ */
+/************************/
+/* STRING_SIMPLE STATE */
+/************************/
+
+ {
+ {IGNORE_STRING_S} {}
+ {STRING_S} {yybegin(CONSUME_LINE);}
+ [^]|{SPACE} {}
+ }
+
+/************************/
+/* STRING_DOUBLE STATE */
+/************************/
+
+ {
+ {IGNORE_STRING_D} {}
+ {STRING_D} {yybegin(CONSUME_LINE);}
+ [^]|{SPACE} {}
+ }
/************************/
/* ERROR STATE */
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/COMPRESLengthLine.lex b/fr.cnes.analysis.tools.shell.rules/lex/COMPRESLengthLine.lex
index 2e4e0565..8bea8a94 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/COMPRESLengthLine.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/COMPRESLengthLine.lex
@@ -18,12 +18,15 @@ import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.File;
import java.util.List;
+import java.util.EmptyStackException;
+import java.util.Stack;
import org.eclipse.core.runtime.Path;
import fr.cnes.analysis.tools.analyzer.datas.AbstractChecker;
import fr.cnes.analysis.tools.analyzer.datas.CheckResult;
import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
+import fr.cnes.analysis.tools.shell.metrics.Function;
%%
@@ -39,19 +42,38 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
%type List
-%state COMMENT, NAMING
+%state COMMENT, NAMING, BEGINFUNC, STRING_DOUBLE, STRING_SIMPLE
-FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
-SPACE = [\ \r\t\f]
-VAR = [a-zA-Z][a-zA-Z0-9\_]*
+COMMENT_WORD = \#
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FUNCTION = "function"
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
+SPACE = [\ \r\t\f]
+NAME = [a-zA-Z\_][a-zA-Z0-9\_]*
+SHELL_VAR = ([0-9]+|[\-\@\?\#\!\_\*\$])
+EXPANDED_VAR = [\$][\{](([\:]{SPACE}*[\-])|[a-zA-Z0-9\_\:\%\=\+\?\/\!\-\,\^\#\*\@]|([\[](([\:]{SPACE}*[\-])|[a-zA-Z0-9\_\/\:\%\=\+\?\!\$\-\,\^\#\*\@\[\]\{\}])+[\]]))+[\}]
+VAR = {NAME}|{EXPANDED_VAR}|([\$]({NAME}|{SHELL_VAR}))
+FUNCSTART = \{ | \( | \(\( | \[\[ | "if" | "case" | "select" | "for" | "while" | "until"
+FUNCEND = \} | \) | \)\) | \]\] | "fi" | "esac" | "done"
+
+STRING_D = \"
+IGNORE_STRING_D = [\\][\"]
+STRING_S = \'
+IGNORE_STRING_S = [\\][\']
%{
- String location = "MAIN PROGRAM";
+ /* MAINPROGRAM: constant for main program localisation */
+ private static final String MAINPROGRAM = "MAIN PROGRAM";
+
+ String location = MAINPROGRAM;
+ /* functionLine: the beginning line of the function */
+ int functionLine = 0;
+
private String parsedFileName;
int length = 0;
+ private Stack functionStack = new Stack<>();
public COMPRESLengthLine() {
@@ -70,7 +92,23 @@ VAR = [a-zA-Z][a-zA-Z0-9\_]*
setError(location,"There are more than 100 characters in this line.", yyline+1);
length = 0;
}
-
+
+ private void endLocation() throws JFlexException {
+ try{
+ Function functionFinished = functionStack.pop();
+ if (!functionStack.empty()) {
+ /* there is a current function: change location to this function */
+ location = functionStack.peek().getName();
+ } else {
+ /* we are in the main program: change location to main */
+ location = MAINPROGRAM;
+ }
+ }catch(EmptyStackException e){
+ final String errorMessage = e.getMessage();
+ throw new JFlexException(this.getClass().getName(), parsedFileName,
+ errorMessage, yytext(), yyline, yycolumn);
+ }
+ }
%}
%eofval{
@@ -84,14 +122,25 @@ VAR = [a-zA-Z][a-zA-Z0-9\_]*
/************************/
-
+/************************/
+/* COMMENT STATE */
+/************************/
+
+ {
+ \n {checkLine(); yybegin(YYINITIAL);}
+ . {length+=yytext().length();}
+ }
+
/************************/
/* NAMING STATE */
/************************/
{
- {VAR} {location = yytext(); length+=yytext().length(); yybegin(YYINITIAL);}
+ {FNAME} {location = yytext();
+ length+=yytext().length();
+ functionLine = yyline+1;
+ yybegin(BEGINFUNC);}
\n {checkLine(); yybegin(YYINITIAL);}
. {length+=yytext().length();}
}
@@ -101,12 +150,94 @@ VAR = [a-zA-Z][a-zA-Z0-9\_]*
/************************/
{
+ {COMMENT_WORD} {length+=yytext().length();yybegin(COMMENT);}
+ {STRING_D} {
+ length+=yytext().length();
+ yybegin(STRING_DOUBLE);
+ }
+ {STRING_S} {
+ length+=yytext().length();
+ yybegin(STRING_SIMPLE);
+ }
{FUNCTION} {length+=yytext().length(); yybegin(NAMING);}
- {FUNCT} {length+=yytext().length(); location = yytext().substring(0,yytext().length()-2).trim(); }
+ {FUNCT} {length+=yytext().length();
+ functionLine = yyline+1;
+ location = yytext().substring(0,yytext().length()-2).trim();
+ yybegin(BEGINFUNC);
+ }
+ {FUNCSTART} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().getFinisher().equals(Function.finisherOf(yytext()))){
+ functionStack.peek().addStarterRepetition();
+ }
+ }
+ length+=yytext().length();
+ }
+ {FUNCEND} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().isFinisher(yytext())){
+ if(functionStack.peek().getStarterRepetition()>0) {
+ functionStack.peek().removeStarterRepetition();
+ } else {
+ endLocation();
+ }
+ }
+ }
+ length+=yytext().length();
+ }
\n {checkLine();}
. {length+=yytext().length();}
}
+/************************/
+/* BEGINFUNC STATE */
+/************************/
+/*
+ * This state target is to retrieve the function starter. For more information on fonction starter, have a look on {@link Function} class.
+ * Pending this starter, the function ender can be defined.
+ *
+ */
+
+ {
+ \(\) {length+=yytext().length();}
+ {FUNCSTART} {
+ Function function;
+ function = new Function(location, functionLine, yytext());
+ functionStack.push(function);
+ length+=yytext().length();
+ yybegin(YYINITIAL);
+ }
+ [^]|{SPACE} {length+=yytext().length();}
+ }
+
+/*
+ * The string states are designed to avoid problems due to patterns found in strings.
+ */
+/************************/
+/* STRING_SIMPLE STATE */
+/************************/
+
+ {
+ {IGNORE_STRING_S} {length+=yytext().length();}
+ {STRING_S} {
+ length+=yytext().length();
+ yybegin(YYINITIAL);
+ }
+ [^]|{SPACE} {length+=yytext().length();}
+ }
+
+/************************/
+/* STRING_DOUBLE STATE */
+/************************/
+
+ {
+ {IGNORE_STRING_D} {length+=yytext().length();}
+ {STRING_D} {
+ length+=yytext().length();
+ yybegin(YYINITIAL);
+ }
+ [^]|{SPACE} {length+=yytext().length();}
+ }
/************************/
/* ERROR STATE */
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/COMTYPEExpression.lex b/fr.cnes.analysis.tools.shell.rules/lex/COMTYPEExpression.lex
index a1b3e8fb..d53471d8 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/COMTYPEExpression.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/COMTYPEExpression.lex
@@ -44,7 +44,8 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
COMMENT_WORD = \#
FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
SPACE = [\ \r\t\f]
VAR = [a-zA-Z][a-zA-Z0-9\_]*
STRING = \'[^\']*\' | \"[^\"]*\"
@@ -144,7 +145,7 @@ EXPR = {VARIABLE} {SPACE}+ {OPER} {SPACE}+ ({STRING}|{INT}|{VARIABLE})
/************************/
{
- {VAR} {location = yytext(); yybegin(YYINITIAL);}
+ {FNAME} {location = yytext(); yybegin(YYINITIAL);}
\n {yybegin(YYINITIAL);}
. {}
}
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/SHDATAIFS.lex b/fr.cnes.analysis.tools.shell.rules/lex/SHDATAIFS.lex
index 0ab46a01..8967df65 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/SHDATAIFS.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/SHDATAIFS.lex
@@ -43,7 +43,8 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
COMMENT_WORD = \#
FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
SPACE = [\ \r\t\f]
VAR = [a-zA-Z][a-zA-Z0-9\_]*
STRING = \'[^\']*\' | \"[^\"]*\"
@@ -98,7 +99,7 @@ IFS = "IFS"\=
/************************/
{
- {VAR} {location = yytext(); yybegin(YYINITIAL);}
+ {FNAME} {location = yytext(); yybegin(YYINITIAL);}
\n {yybegin(YYINITIAL);}
. {}
}
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/SHDATAInteger.lex b/fr.cnes.analysis.tools.shell.rules/lex/SHDATAInteger.lex
index 2e8313a6..0a2b0967 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/SHDATAInteger.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/SHDATAInteger.lex
@@ -44,7 +44,8 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
COMMENT_WORD = \#
FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
SPACE = [\ \r\t\f]
VAR = [a-zA-Z][a-zA-Z0-9\_]*
STRING = \'[^\']*\' | \"[^\"]*\"
@@ -104,7 +105,7 @@ TYPESET = "typeset"{SPACE}+\-"i"
/************************/
{
- {VAR} {location = yytext(); yybegin(LINE);}
+ {FNAME} {location = yytext(); yybegin(LINE);}
\n {yybegin(YYINITIAL);}
. {}
}
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/SHDESIGNOptions.lex b/fr.cnes.analysis.tools.shell.rules/lex/SHDESIGNOptions.lex
index 7ccfe7db..c5092fab 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/SHDESIGNOptions.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/SHDESIGNOptions.lex
@@ -42,7 +42,8 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
COMMENT_WORD = \#
FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
SPACE = [\ \r\t\f]
VAR = [a-zA-Z][a-zA-Z0-9\_]*
@@ -121,7 +122,7 @@ ESAC = "esac"
/************************/
{
- {VAR} {location = yytext(); yybegin(YYINITIAL);}
+ {FNAME} {location = yytext(); yybegin(YYINITIAL);}
\n {yybegin(YYINITIAL);}
. {}
}
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/SHERRHelp.lex b/fr.cnes.analysis.tools.shell.rules/lex/SHERRHelp.lex
index e6e2c986..f02eb6ba 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/SHERRHelp.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/SHERRHelp.lex
@@ -43,7 +43,8 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
COMMENT_WORD = \#
FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
SPACE = [\ \r\t\f]
VAR = [a-zA-Z][a-zA-Z0-9\_]*
STRING = \'[^\']*\' | \"[^\"]*\"
@@ -121,7 +122,7 @@ HELP = "help"
/************************/
{
- {VAR} {location = yytext(); yybegin(YYINITIAL);}
+ {FNAME} {location = yytext(); yybegin(YYINITIAL);}
\n {yybegin(YYINITIAL);}
. {}
}
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/SHERRNoPipe.lex b/fr.cnes.analysis.tools.shell.rules/lex/SHERRNoPipe.lex
index c2aa4d5c..480b83e0 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/SHERRNoPipe.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/SHERRNoPipe.lex
@@ -46,7 +46,8 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
COMMENT_WORD = \#
FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
SPACE = [\ \r\t\f]
VAR = [a-zA-Z][a-zA-Z0-9\_]*
STRING = \'[^\']*\' | \"[^\"]*\"
@@ -128,7 +129,7 @@ OR = \|\|
/************************/
{
- {VAR} {location = yytext(); yybegin(YYINITIAL);}
+ {FNAME} {location = yytext(); yybegin(YYINITIAL);}
\n {if(inCase){
yybegin(CASE);
}else{
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/SHERRString.lex b/fr.cnes.analysis.tools.shell.rules/lex/SHERRString.lex
index fe24d30d..0d96f672 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/SHERRString.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/SHERRString.lex
@@ -43,7 +43,8 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
COMMENT_WORD = \#
FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
SPACE = [\ \r\t\f]
VAR = [a-zA-Z][a-zA-Z0-9\_]*
STRING = \'[^\']*\' | \"[^\"]*\"
@@ -98,7 +99,7 @@ COMPARISON = ("if" | "while") {SPACE}* \[ {SPACE}
/************************/
{
- {VAR} {location = yytext(); yybegin(YYINITIAL);}
+ {FNAME} {location = yytext(); yybegin(YYINITIAL);}
\n {yybegin(YYINITIAL);}
. {}
}
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/SHFLOWCheckArguments.lex b/fr.cnes.analysis.tools.shell.rules/lex/SHFLOWCheckArguments.lex
index 48a55e02..6035de27 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/SHFLOWCheckArguments.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/SHFLOWCheckArguments.lex
@@ -43,7 +43,8 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
COMMENT_WORD = \#
FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
SPACE = [\ \r\t\f]
VAR = [a-zA-Z][a-zA-Z0-9\_]*
STRING = \'[^\']*\' | \"[^\"]*\"
@@ -51,7 +52,8 @@ STRING = \'[^\']*\' | \"[^\"]*\"
COMP = "-eq" | "-ne" | "-gt" | "-ge" |
"-lt" | "-le" | \< | \<\= |
\> | \>\=
-ARGS = "if"{SPACE}+\[{SPACE}+\$\#{SPACE}+{COMP}
+ARGS = "if"{SPACE}+\[{SPACE}+{NUMBER_PARAMS}{SPACE}+{COMP}
+NUMBER_PARAMS = \$\# | \$\{\#\}
%{
String location = "MAIN PROGRAM";
@@ -106,7 +108,7 @@ ARGS = "if"{SPACE}+\[{SPACE}+\$\#{SPACE}+{COMP}
/************************/
{
- {VAR} {location = yytext(); yybegin(CHECKARGUMENTS);}
+ {FNAME} {location = yytext(); yybegin(CHECKARGUMENTS);}
\n {yybegin(CHECKARGUMENTS);}
. {}
}
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/SHFLOWCheckCodeReturn.lex b/fr.cnes.analysis.tools.shell.rules/lex/SHFLOWCheckCodeReturn.lex
index 164099a0..c8c622e1 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/SHFLOWCheckCodeReturn.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/SHFLOWCheckCodeReturn.lex
@@ -20,12 +20,15 @@ import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.EmptyStackException;
+import java.util.Stack;
import org.eclipse.core.runtime.Path;
import fr.cnes.analysis.tools.analyzer.datas.AbstractChecker;
import fr.cnes.analysis.tools.analyzer.datas.CheckResult;
import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
+import fr.cnes.analysis.tools.shell.metrics.Function;
%%
@@ -40,19 +43,35 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
%type List
-%state COMMENT, NAMING, CHECKRET, FINLINE, COMMENTARGS, PIPELINE
+%state COMMENT, NAMING, CHECKRET, FINLINE, COMMENTARGS, PIPELINE, CONSUMECOMMAND, BEGINFUNC, STRING_SIMPLE, STRING_DOUBLE
COMMENT_WORD = \#
SPACE = [\ \r\t\f]
FUNCTION = "function"
-FUNC = {VAR}{SPACE}*\(\)
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
VAR = [a-zA-Z][a-zA-Z0-9\_]*
-STRING = \'[^\']*\' | \"[^\"]*\"
+PIPEIGNORE = "||"
+PIPE = \|
+
+FUNCSTART = \{ | \( | \(\( | \[\[ | "if" | "case" | "select" | "for" | "while" | "until"
+FUNCEND = \} | \) | \)\) | \]\] | "fi" | "esac" | "done"
+
+STRING_D = \"
+IGNORE_STRING_D = [\\][\"]
+STRING_S = \'
+IGNORE_STRING_S = [\\][\']
%{
- private String location = "MAIN PROGRAM";
+ /* MAINPROGRAM: constant for main program localisation */
+ private static final String MAINPROGRAM = "MAIN PROGRAM";
+
+ String location = MAINPROGRAM;
+ /* functionLine: the beginning line of the function */
+ int functionLine = 0;
+
private String parsedFileName;
/** Map with each function name and if contains a return or not **/
private Map functions = new HashMap();
@@ -65,6 +84,8 @@ STRING = \'[^\']*\' | \"[^\"]*\"
/** Last function called **/
private String functionCall = "";
+ private Stack functionStack = new Stack<>();
+
public SHFLOWCheckCodeReturn() {
/** The command 'cd' must be checked as the functions **/
functions.put("awk",true);
@@ -117,14 +138,33 @@ STRING = \'[^\']*\' | \"[^\"]*\"
this.parsedFileName = file.toString();
this.zzReader = new FileReader(new Path(file.getAbsolutePath()).toOSString());
}
-
+
+ private void endLocation() throws JFlexException {
+ try{
+ Function functionFinished = functionStack.pop();
+ if (!functionStack.empty()) {
+ /* there is a current function: change location to this function */
+ location = functionStack.peek().getName();
+ } else {
+ /* we are in the main program: change location to main */
+ location = MAINPROGRAM;
+ }
+ }catch(EmptyStackException e){
+ final String errorMessage = e.getMessage();
+ throw new JFlexException(this.getClass().getName(), parsedFileName,
+ errorMessage, yytext(), yyline, yycolumn);
+ }
+ }
%}
-%eofval{
- if(!verified && functionCalled) addViolation();
- return getCheckResults();
-%eofval}
+/* ------------------------------------------------------------------------------------------------- */
+/* The eofval function has been removed to treat EOF differently when found in different states */
+/* This is due to the fact that the violation is raised when at least one of the following lines */
+/* has been parsed. According to what is parsed, the violation needs to be raised on a previous line */
+/* or not. */
+/* The eofval function MUST NOT be used in combination with EOF recognition in states (exclusive). */
+/* ------------------------------------------------------------------------------------------------- */
%%
@@ -141,6 +181,7 @@ STRING = \'[^\']*\' | \"[^\"]*\"
{
\n {yybegin(YYINITIAL);}
+ <> {return getCheckResults();}
. {}
}
@@ -149,8 +190,9 @@ STRING = \'[^\']*\' | \"[^\"]*\"
/************************/
{
- {VAR} {location = yytext(); functions.put(location, false); yybegin(YYINITIAL);}
+ {FNAME} {location = yytext(); functions.put(location, false); yybegin(BEGINFUNC);}
\n {yybegin(YYINITIAL);}
+ <> {return getCheckResults();}
. {}
}
@@ -159,10 +201,13 @@ STRING = \'[^\']*\' | \"[^\"]*\"
/************************/
{
+ {PIPEIGNORE} {pipeline = false;}
{COMMENT_WORD} {yybegin(COMMENT);}
- {FUNCTION} {location = yytext(); yybegin(NAMING);}
- {FUNC} {location = yytext().substring(0,yytext().length()-2).trim(); functions.put(location, false);}
- {STRING} {}
+ {STRING_D} {yybegin(STRING_DOUBLE);}
+ {STRING_S} {yybegin(STRING_SIMPLE);}
+ {PIPE} {pipeline = true;}
+ {FUNCTION} {yybegin(NAMING);}
+ {FUNCT} {location = yytext().substring(0,yytext().length()-2).trim(); functions.put(location, false); yybegin(BEGINFUNC);}
{VAR} {Boolean found = functions.get(yytext());
if(found!=null) {
functionCalled=true;
@@ -172,7 +217,27 @@ STRING = \'[^\']*\' | \"[^\"]*\"
yybegin(FINLINE);
} else {
functionCalled=false;
+ yybegin(CONSUMECOMMAND);
}}
+ {FUNCSTART} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().getFinisher().equals(Function.finisherOf(yytext()))){
+ functionStack.peek().addStarterRepetition();
+ }
+ }
+ }
+ {FUNCEND} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().isFinisher(yytext())){
+ if(functionStack.peek().getStarterRepetition()>0) {
+ functionStack.peek().removeStarterRepetition();
+ } else {
+ endLocation();
+ }
+ }
+ }
+ }
+ <> {return getCheckResults();}
[^] {}
}
@@ -181,8 +246,14 @@ STRING = \'[^\']*\' | \"[^\"]*\"
/************************/
{
- \| {pipeline = true; yybegin(PIPELINE);}
+ {PIPEIGNORE} {pipeline = false; yybegin(YYINITIAL);}
+ {PIPE} {pipeline = true; yybegin(PIPELINE);}
\n {yybegin(CHECKRET);}
+ <> {
+ linesError=0;
+ if(!verified && functionCalled) addViolation();
+ return getCheckResults();
+ }
. {}
}
@@ -196,11 +267,34 @@ STRING = \'[^\']*\' | \"[^\"]*\"
functionCalled=true;
verified=false;
linesError=1;
- functionCall+=", " + yytext();
+ if (functionCall.length() != 0) functionCall+=", ";
+ functionCall+=yytext();
}}
\n {yybegin(CHECKRET);}
+ <> {
+ linesError=0;
+ if(!verified && functionCalled) addViolation();
+ return getCheckResults();
+ }
+ . {}
+ }
+
+/************************/
+/* CONSUMECOMMAND STATE */
+/************************/
+
+ {
+ {PIPEIGNORE} {pipeline = false; yybegin(YYINITIAL);}
+ {PIPE} {pipeline = true; yybegin(PIPELINE);}
+ \n | ";" {yybegin(YYINITIAL);}
+ <> {
+ linesError=0;
+ if(!verified && functionCalled) addViolation();
+ return getCheckResults();
+ }
. {}
}
+
/************************/
@@ -208,7 +302,7 @@ STRING = \'[^\']*\' | \"[^\"]*\"
/************************/
{
- \# {yybegin(COMMENTARGS);}
+ {COMMENT_WORD} {yybegin(COMMENTARGS);}
{VAR} {Boolean found = functions.get(yytext());
if(found!=null) {
addViolation();
@@ -222,9 +316,15 @@ STRING = \'[^\']*\' | \"[^\"]*\"
}}
\$\? {verified=true;}
{SPACE} {}
- \n {if(!verified) addViolation();
+ \n {
+ if(!verified) addViolation();
functionCalled = false;
+ functionCall="";
yybegin(YYINITIAL);}
+ <> {
+ if(!verified && functionCalled) addViolation();
+ return getCheckResults();
+ }
. {}
}
@@ -234,9 +334,59 @@ STRING = \'[^\']*\' | \"[^\"]*\"
{
\n {linesError++; yybegin(CHECKRET);}
+ <> {
+ linesError=0;
+ if(!verified && functionCalled) addViolation();
+ return getCheckResults();
+ }
. {}
}
+/************************/
+/* BEGINFUNC STATE */
+/************************/
+/*
+ * This state target is to retrieve the function starter. For more information on fonction starter, have a look on {@link Function} class.
+ * Pending this starter, the function ender can be defined.
+ *
+ */
+
+ {
+ \(\) {}
+ {FUNCSTART} {
+ Function function;
+ function = new Function(location, functionLine, yytext());
+ functionStack.push(function);
+ yybegin(YYINITIAL);
+ }
+ <> {return getCheckResults();}
+ [^]|{SPACE} {}
+ }
+
+/*
+ * The string states are designed to avoid problems due to patterns found in strings.
+ */
+/************************/
+/* STRING_SIMPLE STATE */
+/************************/
+
+ {
+ {IGNORE_STRING_S} {}
+ {STRING_S} {yybegin(YYINITIAL);}
+ <> {return getCheckResults();}
+ [^]|{SPACE} {}
+ }
+
+/************************/
+/* STRING_DOUBLE STATE */
+/************************/
+
+ {
+ {IGNORE_STRING_D} {}
+ {STRING_D} {yybegin(YYINITIAL);}
+ <> {return getCheckResults();}
+ [^]|{SPACE} {}
+ }
/************************/
/* ERROR STATE */
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/SHFLOWCheckUser.lex b/fr.cnes.analysis.tools.shell.rules/lex/SHFLOWCheckUser.lex
index 3b6b7861..9e50df1f 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/SHFLOWCheckUser.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/SHFLOWCheckUser.lex
@@ -43,7 +43,8 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
COMMENT_WORD = \#
FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
SPACE = [\ \r\t\f]
VAR = [a-zA-Z][a-zA-Z0-9\_]*
@@ -128,7 +129,7 @@ DIRECT_CHECK = {DIRECT_USER} {SPACE}+ {OP} {SPACE}+ {ROOT_VALUE}
/************************/
{
- {VAR} {location = yytext(); yybegin(YYINITIAL);}
+ {FNAME} {location = yytext(); yybegin(YYINITIAL);}
\n {yybegin(YYINITIAL);}
. {}
}
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/SHINSTBasename.lex b/fr.cnes.analysis.tools.shell.rules/lex/SHINSTBasename.lex
index 5f0a9976..b3b5539d 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/SHINSTBasename.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/SHINSTBasename.lex
@@ -43,7 +43,8 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
COMMENT_WORD = \#
FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
SPACE = [\ \r\t\f]
VAR = [a-zA-Z][a-zA-Z0-9\_]*
@@ -99,7 +100,7 @@ DIRNAME = "dirname"{SPACE}+\$"0" | "dirname"{SPACE}+\"\$"0"\"
/************************/
{
- {VAR} {location = yytext(); yybegin(YYINITIAL);}
+ {FNAME} {location = yytext(); yybegin(YYINITIAL);}
\n {yybegin(YYINITIAL);}
. {}
}
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/SHINSTContinue.lex b/fr.cnes.analysis.tools.shell.rules/lex/SHINSTContinue.lex
index 39b7ee02..afec7cff 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/SHINSTContinue.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/SHINSTContinue.lex
@@ -42,7 +42,10 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
%state COMMENT, NAMING,
COMMENT_WORD = \#
-FUNC = "function"
+FUNCTION = "function"
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
+SPACE = [\ \r\t\f]
VAR = [a-zA-Z][a-zA-Z0-9\_]*
STRING = \'[^\']*\' | \"[^\"]*\"
@@ -92,7 +95,7 @@ CONTINUE = "continue"
/************************/
{
- {VAR} {location = location + yytext(); yybegin(YYINITIAL);}
+ {FNAME} {location = location + yytext(); yybegin(YYINITIAL);}
\n {yybegin(YYINITIAL);}
. {}
}
@@ -104,7 +107,8 @@ CONTINUE = "continue"
{
{COMMENT_WORD} {yybegin(COMMENT);}
{STRING} {}
- {FUNC} {location = yytext(); yybegin(NAMING);}
+ {FUNCTION} {yybegin(NAMING);}
+ {FUNCT} {location = yytext().substring(0,yytext().length()-2).trim(); }
{CONTINUE} {setError(location,"The keyword CONTINUE is not allowed.", yyline+1); }
{VAR} {} /* Clause to match with words that contains "continue" */
[^] {}
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/SHINSTFind.lex b/fr.cnes.analysis.tools.shell.rules/lex/SHINSTFind.lex
index 4afdb4b8..92366435 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/SHINSTFind.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/SHINSTFind.lex
@@ -43,7 +43,8 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
COMMENT_WORD = \#
FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
SPACE = [\ \r\t\f]
VAR = [a-zA-Z][a-zA-Z0-9\_\/]*
STRING = \'[^\']*\' | \"[^\"]*\"
@@ -98,7 +99,7 @@ LS = "ls" | "/bin/ls"
/************************/
{
- {VAR} {location = yytext(); yybegin(YYINITIAL);}
+ {FNAME} {location = yytext(); yybegin(YYINITIAL);}
\n {yybegin(YYINITIAL);}
. {}
}
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/SHINSTGetOpts.lex b/fr.cnes.analysis.tools.shell.rules/lex/SHINSTGetOpts.lex
index 2e362428..6b6597b8 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/SHINSTGetOpts.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/SHINSTGetOpts.lex
@@ -44,7 +44,8 @@ import java.util.logging.Logger;
COMMENT_WORD = \#
FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
SPACE = [\ \r\t\f]
PARAMETER = [\$](([1-9][0-9]*)|[\*])
VAR = ([a-zA-Z][a-zA-Z0-9\_\-]*)|([\$]([\-\@\?\#\!\_\0]|([a-zA-Z]*)|[\{][a-zA-Z]*[\}]))
@@ -122,7 +123,7 @@ ESCAPE_STRING = [\\]([\']|[\"])
/************************/
{
- {VAR} {
+ {FNAME} {
LOGGER.fine("["+this.parsedFileName+":"+(yyline+1)+":"+yycolumn+"] - NAMING -> YYINITIAL (Transition : VAR \""+yytext()+"\" )");
location = yytext();
functionContainGetOpt=false;
@@ -197,7 +198,7 @@ ESCAPE_STRING = [\\]([\']|[\"])
LOGGER.fine("["+this.parsedFileName+":"+(yyline+1)+":"+yycolumn+"] - YYINITIAL -> YYINITIAL (Transition : VAR \""+yytext()+"\" )");
yybegin(STRING);
}
- {FUNCT} {}
+ {FUNCT} {location = yytext().substring(0,yytext().length()-2).trim();}
{GETOPT} {
foundGetOpt=true;
functionContainGetOpt=true;
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/SHINSTLogical.lex b/fr.cnes.analysis.tools.shell.rules/lex/SHINSTLogical.lex
index b51b77da..dec760db 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/SHINSTLogical.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/SHINSTLogical.lex
@@ -43,7 +43,8 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
COMMENT_WORD = \#
FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
SPACE = [\ \r\t\f]
VAR = [a-zA-Z][a-zA-Z0-9\_]*
STRING = \'[^\']*\' | \"[^\"]*\"
@@ -101,7 +102,7 @@ ENDCOND = "do" | "then"
/************************/
{
- {VAR} {location = yytext(); yybegin(YYINITIAL);}
+ {FNAME} {location = yytext(); yybegin(YYINITIAL);}
\n {yybegin(YYINITIAL);}
. {}
}
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/SHINSTPOSIX.lex b/fr.cnes.analysis.tools.shell.rules/lex/SHINSTPOSIX.lex
index e7602fe8..59ac1c55 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/SHINSTPOSIX.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/SHINSTPOSIX.lex
@@ -52,7 +52,8 @@ import java.util.regex.Matcher;
COMMENT_WORD = \#
FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
SPACE = [\ \r\t\f]
VAR = ([a-zA-Z][a-zA-Z0-9\_\-]*)|([\$]([\-\@\?\#\!\_\*]|([a-zA-Z0-9]*)|[\{][a-zA-Z0-9]*[\}]))
ECHO = "echo"
@@ -168,7 +169,7 @@ VAR_ERROR = ([\$]{ERROR}) | ([\$][\{]{ERROR}[\}])
/************************/
{
- {VAR} {location = yytext(); yybegin(YYINITIAL);}
+ {FNAME} {location = yytext(); yybegin(YYINITIAL);}
\n {yybegin(YYINITIAL);}
. {}
}
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/SHINSTSetShift.lex b/fr.cnes.analysis.tools.shell.rules/lex/SHINSTSetShift.lex
index cfc8b5b8..689333c5 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/SHINSTSetShift.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/SHINSTSetShift.lex
@@ -43,7 +43,8 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
COMMENT_WORD = \#
FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
SPACE = [\ \r\t\f]
VAR = [a-zA-Z][a-zA-Z0-9\_]*
STRING = \'[^\']*\' | \"[^\"]*\"
@@ -99,7 +100,7 @@ AVOID = "set"{SPACE}+\-"o"{SPACE}+"pipefail"
/************************/
{
- {VAR} {location = yytext(); yybegin(YYINITIAL);}
+ {FNAME} {location = yytext(); yybegin(YYINITIAL);}
\n {yybegin(YYINITIAL);}
. {}
}
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/SHIORedirect.lex b/fr.cnes.analysis.tools.shell.rules/lex/SHIORedirect.lex
index b01e7008..67fc8661 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/SHIORedirect.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/SHIORedirect.lex
@@ -37,12 +37,15 @@ import java.io.FileReader;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
+import java.util.EmptyStackException;
+import java.util.Stack;
import org.eclipse.core.runtime.Path;
import fr.cnes.analysis.tools.analyzer.datas.AbstractChecker;
import fr.cnes.analysis.tools.analyzer.datas.CheckResult;
import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
+import fr.cnes.analysis.tools.shell.metrics.Function;
%%
@@ -57,12 +60,13 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
%type List
-%state COMMENT, NAMING
+%state COMMENT, NAMING, BEGINFUNC
COMMENT_WORD = \#
FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
-SPACE = [\ \r\t\f]
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
+SPACE = [\ \r\t\f]
VAR = [a-zA-Z][a-zA-Z0-9\_]*
STRING = \'[^\']*\' | \"[^\"]*\"
OPERATOR_RIGHT = [\>]|[\>][\&]|[\&][\>]|[\>][\>]|[\>][\>][\>]
@@ -73,14 +77,24 @@ REDIRECT_LEFT = ([a-zA-Z3-9\_\?\-\/\\\}]|{STRING})+{SPACE}*({OPERATOR_LEFT}|{OPE
REDIRECT_RL = ([a-zA-Z3-9\_\?\-\/\\\}]|{STRING})+{SPACE}*{OPERATOR_RL}{SPACE}*([a-zA-Z3-9\_\?\.\-\$\/\\]|{STRING})+
REDIRECT = {REDIRECT_RIGHT}|{REDIRECT_LEFT}|{REDIRECT_RL}
+FUNCSTART = \{ | \( | \(\( | \[\[ | "if" | "case" | "select" | "for" | "while" | "until"
+FUNCEND = \} | \) | \)\) | \]\] | "fi" | "esac" | "done"
%{
- String location = "MAIN PROGRAM";
+ /* MAINPROGRAM: constant for main program localisation */
+ private static final String MAINPROGRAM = "MAIN PROGRAM";
+
+ String location = MAINPROGRAM;
+ /* functionLine: the beginning line of the function */
+ int functionLine = 0;
+
private String parsedFileName;
List redirections = new ArrayList();
private boolean isLastLineCommented = false;
private boolean errorReported=false;
+ private Stack functionStack = new Stack<>();
+
public SHIORedirect() {
}
@@ -92,7 +106,24 @@ REDIRECT = {REDIRECT_RIGHT}|{REDIRECT_LEFT}|{REDIRECT_RL}
this.parsedFileName = file.toString();
this.zzReader = new FileReader(new Path(file.getAbsolutePath()).toOSString());
}
-
+
+ private void endLocation() throws JFlexException {
+ try{
+ Function functionFinished = functionStack.pop();
+ if (!functionStack.empty()) {
+ /* there is a current function: change location to this function */
+ location = functionStack.peek().getName();
+ } else {
+ /* we are in the main program: change location to main */
+ location = MAINPROGRAM;
+ }
+ }catch(EmptyStackException e){
+ final String errorMessage = e.getMessage();
+ throw new JFlexException(this.getClass().getName(), parsedFileName,
+ errorMessage, yytext(), yyline, yycolumn);
+ }
+ }
+
%}
%eofval{
@@ -124,8 +155,8 @@ REDIRECT = {REDIRECT_RIGHT}|{REDIRECT_LEFT}|{REDIRECT_RL}
/************************/
{
- {VAR} {
- location = yytext(); yybegin(YYINITIAL);}
+ {FNAME} {location = yytext(); functionLine = yyline+1; yybegin(BEGINFUNC);}
+
\n {
isLastLineCommented=false;
yybegin(YYINITIAL);}
@@ -147,13 +178,53 @@ REDIRECT = {REDIRECT_RIGHT}|{REDIRECT_LEFT}|{REDIRECT_RL}
}
}
{FUNCTION} {yybegin(NAMING);}
- {FUNCT} {location = yytext().substring(0,yytext().length()-2).trim(); }
- {STRING} {}
+ {FUNCT} {functionLine = yyline+1;
+ location = yytext().substring(0,yytext().length()-2).trim();
+ yybegin(BEGINFUNC);
+ }
+ {FUNCSTART} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().getFinisher().equals(Function.finisherOf(yytext()))){
+ functionStack.peek().addStarterRepetition();
+ }
+ }
+ }
+ {FUNCEND} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().isFinisher(yytext())){
+ if(functionStack.peek().getStarterRepetition()>0) {
+ functionStack.peek().removeStarterRepetition();
+ } else {
+ endLocation();
+ }
+ }
+ }
+ }
+ {STRING} {}
. {}
\n {isLastLineCommented=false;errorReported=false;}
}
-
+/************************/
+/* BEGINFUNC STATE */
+/************************/
+/*
+ * This state target is to retrieve the function starter. For more information on fonction starter, have a look on {@link Function} class.
+ * Pending this starter, the function ender can be defined.
+ *
+ */
+
+ {
+ \(\) {}
+ {FUNCSTART} {
+ Function function;
+ function = new Function(location, functionLine, yytext());
+ functionStack.push(function);
+ yybegin(YYINITIAL);
+ }
+ [^]|{SPACE} {}
+ }
+
/************************/
/* ERROR STATE */
/************************/
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/SHMETLimitAWK.lex b/fr.cnes.analysis.tools.shell.rules/lex/SHMETLimitAWK.lex
index 0fdffcaa..d53446e1 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/SHMETLimitAWK.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/SHMETLimitAWK.lex
@@ -43,7 +43,8 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
COMMENT_WORD = \#
FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
SPACE = [\ \r\t\f]
VAR = [a-zA-Z][a-zA-Z0-9\_\/]*
STRING = \'[^\']*\' | \"[^\"]*\"
@@ -97,7 +98,7 @@ STRING = \'[^\']*\' | \"[^\"]*\"
/************************/
{
- {VAR} {location = yytext(); yybegin(YYINITIAL);}
+ {FNAME} {location = yytext(); yybegin(YYINITIAL);}
\n {yybegin(YYINITIAL);}
. {}
}
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/SHMETLimitSed.lex b/fr.cnes.analysis.tools.shell.rules/lex/SHMETLimitSed.lex
index 623b5848..c0d93678 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/SHMETLimitSed.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/SHMETLimitSed.lex
@@ -42,7 +42,8 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
COMMENT_WORD = \#
FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
SPACE = [\ \r\t\f]
VAR = [a-zA-Z][a-zA-Z0-9\_\/]*
STRING = \'[^\']*\' | \"[^\"]*\"
@@ -100,7 +101,7 @@ OPTION = "-e" | "--expression" | "-f" | "--file" |
/************************/
{
- {VAR} {location = yytext(); yybegin(YYINITIAL);}
+ {FNAME} {location = yytext(); yybegin(YYINITIAL);}
\n {yybegin(YYINITIAL);}
. {}
}
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/SHMETPipeLine.lex b/fr.cnes.analysis.tools.shell.rules/lex/SHMETPipeLine.lex
index 0264c8bf..42cf46d3 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/SHMETPipeLine.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/SHMETPipeLine.lex
@@ -19,12 +19,15 @@ import java.io.FileReader;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
+import java.util.EmptyStackException;
+import java.util.Stack;
import org.eclipse.core.runtime.Path;
import fr.cnes.analysis.tools.analyzer.datas.AbstractChecker;
import fr.cnes.analysis.tools.analyzer.datas.CheckResult;
import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
+import fr.cnes.analysis.tools.shell.metrics.Function;
%%
@@ -40,18 +43,39 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
%type List
-%state COMMENT, NAMING, AVOID
+%state COMMENT, NAMING, AVOID, CONSUME_LINE, BEGINFUNC, STRING_SIMPLE, STRING_DOUBLE
COMMENT_WORD = \#
FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
SPACE = [\ \r\t\f]
+
VAR = [a-zA-Z][a-zA-Z0-9\_]*
PIPELINE = \|{SPACE} | \|\n | \|\&
+CASE_STMT = [^"\n""("" ""\r""\f""#"][^"\n""("]*\)
+
+FUNCSTART = \{ | \( | \(\( | \[\[ | "if" | "case" | "select" | "for" | "while" | "until"
+FUNCEND = \} | \) | \)\) | \]\] | "fi" | "esac" | "done"
+
+STRING_D = \"
+IGNORE_STRING_D = [\\][\"]
+STRING_S = \'
+IGNORE_STRING_S = [\\][\']
+
%{
- String location = "MAIN PROGRAM";
+ /* MAINPROGRAM: constant for main program localisation */
+ private static final String MAINPROGRAM = "MAIN PROGRAM";
+
+ private Stack functionStack = new Stack<>();
+
+ /* location: the current function name, or main program, that is the initial value */
+ private String location = MAINPROGRAM;
+ /* functionLine: the beginning line of the function */
+ int functionLine = 0;
+
private String parsedFileName;
int bracket = 0;
String type = "";
@@ -69,22 +93,7 @@ PIPELINE = \|{SPACE} | \|\n | \|\&
this.parsedFileName = file.toString();
this.zzReader = new FileReader(new Path(file.getAbsolutePath()).toOSString());
}
-
- /**
- * Check if the last not empty line is a comment or not
- * @throws JFlexException
- */
- private void checkPipelinesComments(int max) throws JFlexException {
- int index = 1;
- while(index <= max) {
- String current = linesType.get(index);
- if(current.equals("pipeline")){
- checkPrecedent(index, index+1);
- }
- index++;
- }
- }
-
+
/**
* Check the line before to the current line
* @param index
@@ -99,12 +108,26 @@ PIPELINE = \|{SPACE} | \|\n | \|\&
}
}
+ private void endLocation() throws JFlexException {
+ try{
+ Function functionFinished = functionStack.pop();
+ if (!functionStack.empty()) {
+ /* there is a current function: change location to this function */
+ location = functionStack.peek().getName();
+ } else {
+ /* we are in the main program: change location to main */
+ location = MAINPROGRAM;
+ }
+ }catch(EmptyStackException e){
+ final String errorMessage = e.getMessage();
+ throw new JFlexException(this.getClass().getName(), parsedFileName,
+ errorMessage, yytext(), yyline, yycolumn);
+ }
+ }
%}
%eofval{
- int index = linesType.size()-1;
- checkPipelinesComments(index);
return getCheckResults();
%eofval}
@@ -133,7 +156,7 @@ PIPELINE = \|{SPACE} | \|\n | \|\&
/************************/
{
- {VAR} {location = yytext(); yybegin(YYINITIAL);}
+ {FNAME} {location = yytext(); functionLine = yyline+1; yybegin(BEGINFUNC);}
\n {linesType.add("line"); type="empty"; yybegin(YYINITIAL);}
. {}
}
@@ -144,17 +167,112 @@ PIPELINE = \|{SPACE} | \|\n | \|\&
{
{COMMENT_WORD} {yybegin(COMMENT);}
+ {STRING_D} {yybegin(STRING_DOUBLE);}
+ {STRING_S} {yybegin(STRING_SIMPLE);}
{FUNCTION} {yybegin(NAMING);}
- {FUNCT} {location = yytext().substring(0,yytext().length()-2).trim(); if(type.equals("empty")) type="line";}
+ {FUNCT} {location = yytext().substring(0,yytext().length()-2).trim();
+ if(type.equals("empty")) type="line";
+ functionLine = yyline+1;
+ yybegin(BEGINFUNC);
+ }
+ {FUNCSTART} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().getFinisher().equals(Function.finisherOf(yytext()))){
+ functionStack.peek().addStarterRepetition();
+ }
+ }
+ }
+ {FUNCEND} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().isFinisher(yytext())){
+ if(functionStack.peek().getStarterRepetition()>0) {
+ functionStack.peek().removeStarterRepetition();
+ } else {
+ endLocation();
+ }
+ }
+ }
+ }
\|\| {} /** OR logique **/
+ {CASE_STMT} {} /* a case statement can contain multiple choices with | -> ignore */
{PIPELINE} {type="pipeline";
- if(yytext().contains("\n")) {linesType.add(type); type="empty";} }
+ linesType.add(type);
+ type="empty";
+ int index = linesType.size()-1;
+ checkPrecedent(index, yyline+1);
+ yybegin(CONSUME_LINE);
+ }
{SPACE} {}
\n {linesType.add(type); type="empty";}
\\{SPACE}*\n {}
. {if(type.equals("empty")) type="line";}
}
+
+/************************/
+/* CONSUME_LINE STATE */
+/************************/
+/* Consume characters till end of line */
+
+ {
+ {FUNCEND} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().isFinisher(yytext())){
+ if(functionStack.peek().getStarterRepetition()>0) {
+ functionStack.peek().removeStarterRepetition();
+ } else {
+ endLocation();
+ }
+ }
+ }
+ }
+ \n {yybegin(YYINITIAL);}
+ . {}
+ }
+
+/************************/
+/* BEGINFUNC STATE */
+/************************/
+/*
+ * This state target is to retrieve the function starter. For more information on fonction starter, have a look on {@link Function} class.
+ * Pending this starter, the function ender can be defined.
+ *
+ */
+
+ {
+ \(\) {}
+ {FUNCSTART} {
+ Function function;
+ function = new Function(location, functionLine, yytext());
+ functionStack.push(function);
+ yybegin(YYINITIAL);
+ }
+ [^]|{SPACE} {}
+ }
+
+/*
+ * The string states are designed to avoid problems due to patterns found in strings.
+ */
+/************************/
+/* STRING_SIMPLE STATE */
+/************************/
+
+ {
+ {IGNORE_STRING_S} {}
+ {STRING_S} {yybegin(YYINITIAL);}
+ [^]|{SPACE} {}
+ }
+
+/************************/
+/* STRING_DOUBLE STATE */
+/************************/
+
+ {
+ {IGNORE_STRING_D} {}
+ {STRING_D} {yybegin(YYINITIAL);}
+ [^]|{SPACE} {}
+ }
+
/************************/
/* ERROR STATE */
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/SHREFExport.lex b/fr.cnes.analysis.tools.shell.rules/lex/SHREFExport.lex
index f519e0d8..034ac80f 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/SHREFExport.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/SHREFExport.lex
@@ -18,12 +18,16 @@ import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.File;
import java.util.List;
+import java.util.EmptyStackException;
+import java.util.Stack;
+
import org.eclipse.core.runtime.Path;
import fr.cnes.analysis.tools.analyzer.datas.AbstractChecker;
import fr.cnes.analysis.tools.analyzer.datas.CheckResult;
import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
+import fr.cnes.analysis.tools.shell.metrics.Function;
%%
@@ -39,22 +43,39 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
%type List
-%state COMMENT, NAMING
+%state COMMENT, NAMING, BEGINFUNC, STRING_SIMPLE, STRING_DOUBLE
COMMENT_WORD = \#
FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
SPACE = [\ \r\t\f]
-VAR = [a-zA-Z][a-zA-Z0-9\_]*
-STRING = \'[^\']*\' | \"[^\"]*\"
+NAME = [a-zA-Z\_][a-zA-Z0-9\_]*
+SHELL_VAR = ([0-9]+|[\-\@\?\#\!\_\*\$])
+EXPANDED_VAR = [\$][\{](([\:]{SPACE}*[\-])|[a-zA-Z0-9\_\:\%\=\+\?\/\!\-\,\^\#\*\@]|([\[](([\:]{SPACE}*[\-])|[a-zA-Z0-9\_\/\:\%\=\+\?\!\$\-\,\^\#\*\@\[\]\{\}])+[\]]))+[\}]
+VAR = {NAME}|{EXPANDED_VAR}|([\$]({NAME}|{SHELL_VAR}))
-EXPORT = "export"{SPACE}+\-"f"{SPACE}+{VAR}
+FUNCSTART = \{ | \( | \(\( | \[\[ | "if" | "case" | "select" | "for" | "while" | "until"
+FUNCEND = \} | \) | \)\) | \]\] | "fi" | "esac" | "done"
+STRING_D = \"
+IGNORE_STRING_D = [\\][\"]
+STRING_S = \'
+IGNORE_STRING_S = [\\][\']
+EXPORT = "export"{SPACE}+\-"f"{SPACE}+{FNAME}
%{
- String location = "MAIN PROGRAM";
+ /* MAINPROGRAM: constant for main program localisation */
+ private static final String MAINPROGRAM = "MAIN PROGRAM";
+
+ String location = MAINPROGRAM;
+ /* functionLine: the beginning line of the function */
+ int functionLine = 0;
+
private String parsedFileName;
+ int length = 0;
+ private Stack functionStack = new Stack<>();
public SHREFExport() {
@@ -67,7 +88,24 @@ EXPORT = "export"{SPACE}+\-"f"{SPACE}+{VAR}
this.parsedFileName = file.toString();
this.zzReader = new FileReader(new Path(file.getAbsolutePath()).toOSString());
}
-
+
+ private void endLocation() throws JFlexException {
+ try{
+ Function functionFinished = functionStack.pop();
+ if (!functionStack.empty()) {
+ /* there is a current function: change location to this function */
+ location = functionStack.peek().getName();
+ } else {
+ /* we are in the main program: change location to main */
+ location = MAINPROGRAM;
+ }
+ }catch(EmptyStackException e){
+ final String errorMessage = e.getMessage();
+ throw new JFlexException(this.getClass().getName(), parsedFileName,
+ errorMessage, yytext(), yyline, yycolumn);
+ }
+ }
+
%}
%eofval{
@@ -98,7 +136,9 @@ EXPORT = "export"{SPACE}+\-"f"{SPACE}+{VAR}
/************************/
{
- {VAR} {location = yytext(); yybegin(YYINITIAL);}
+ {FNAME} {location = yytext();
+ functionLine = yyline+1;
+ yybegin(BEGINFUNC);}
\n {yybegin(YYINITIAL);}
. {}
}
@@ -109,13 +149,88 @@ EXPORT = "export"{SPACE}+\-"f"{SPACE}+{VAR}
{
{COMMENT_WORD} {yybegin(COMMENT);}
+ {STRING_D} {
+ length+=yytext().length();
+ yybegin(STRING_DOUBLE);
+ }
+ {STRING_S} {
+ length+=yytext().length();
+ yybegin(STRING_SIMPLE);
+ }
{FUNCTION} {yybegin(NAMING);}
- {FUNCT} {location = yytext().substring(0,yytext().length()-2).trim(); }
- {STRING} {}
+ {FUNCT} {functionLine = yyline+1;
+ location = yytext().substring(0,yytext().length()-2).trim();
+ yybegin(BEGINFUNC);}
+ {FUNCSTART} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().getFinisher().equals(Function.finisherOf(yytext()))){
+ functionStack.peek().addStarterRepetition();
+ }
+ }
+ }
+ {FUNCEND} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().isFinisher(yytext())){
+ if(functionStack.peek().getStarterRepetition()>0) {
+ functionStack.peek().removeStarterRepetition();
+ } else {
+ endLocation();
+ }
+ }
+ }
+ }
{EXPORT} {setError(location,"It is forbidden to export functions.", yyline+1);}
[^] {}
}
+/************************/
+/* BEGINFUNC STATE */
+/************************/
+/*
+ * This state target is to retrieve the function starter. For more information on fonction starter, have a look on {@link Function} class.
+ * Pending this starter, the function ender can be defined.
+ *
+ */
+
+ {
+ \(\) {}
+ {FUNCSTART} {
+ Function function;
+ function = new Function(location, functionLine, yytext());
+ functionStack.push(function);
+ yybegin(YYINITIAL);
+ }
+ [^]|{SPACE} {}
+ }
+
+/*
+ * The string states are designed to avoid problems due to patterns found in strings.
+ */
+/************************/
+/* STRING_SIMPLE STATE */
+/************************/
+
+ {
+ {IGNORE_STRING_S} {length+=yytext().length();}
+ {STRING_S} {
+ length+=yytext().length();
+ yybegin(YYINITIAL);
+ }
+ [^]|{SPACE} {length+=yytext().length();}
+ }
+
+/************************/
+/* STRING_DOUBLE STATE */
+/************************/
+
+ {
+ {IGNORE_STRING_D} {length+=yytext().length();}
+ {STRING_D} {
+ length+=yytext().length();
+ yybegin(YYINITIAL);
+ }
+ [^]|{SPACE} {length+=yytext().length();}
+ }
/************************/
/* ERROR STATE */
diff --git a/fr.cnes.analysis.tools.shell.rules/lex/SHSYNCSignals.lex b/fr.cnes.analysis.tools.shell.rules/lex/SHSYNCSignals.lex
index 9b4d4ae2..5d44f8fa 100755
--- a/fr.cnes.analysis.tools.shell.rules/lex/SHSYNCSignals.lex
+++ b/fr.cnes.analysis.tools.shell.rules/lex/SHSYNCSignals.lex
@@ -18,12 +18,15 @@ import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.File;
import java.util.List;
+import java.util.EmptyStackException;
+import java.util.Stack;
import org.eclipse.core.runtime.Path;
import fr.cnes.analysis.tools.analyzer.datas.AbstractChecker;
import fr.cnes.analysis.tools.analyzer.datas.CheckResult;
import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
+import fr.cnes.analysis.tools.shell.metrics.Function;
%%
@@ -39,22 +42,38 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
%type List
-%state COMMENT, NAMING, TRAP
+%state COMMENT, NAMING, TRAP, BEGINFUNC, STRING_SIMPLE, STRING_DOUBLE
COMMENT_WORD = \#
FUNCTION = "function"
-FUNCT = {VAR}{SPACE}*\(\)
+FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)]
+FNAME = [a-zA-Z0-9\.\!\-\_\@\?\+]+
SPACE = [\ \r\t\f]
VAR = [a-zA-Z][a-zA-Z0-9\_]*
-STRING = \'[^\']*\' | \"[^\"]*\"
+
+STRING_D = \"
+IGNORE_STRING_D = [\\][\"]
+STRING_S = \'
+IGNORE_STRING_S = [\\][\']
TRAP = "trap"
+FUNCSTART = \{ | \( | \(\( | \[\[ | "if" | "case" | "select" | "for" | "while" | "until"
+FUNCEND = \} | \) | \)\) | \]\] | "fi" | "esac" | "done"
%{
- String location = "MAIN PROGRAM";
+ /* MAINPROGRAM: constant for main program localisation */
+ private static final String MAINPROGRAM = "MAIN PROGRAM";
+
+ String location = MAINPROGRAM;
+
private String parsedFileName;
+ /* functionLine: the beginning line of the function */
+ int functionLine = 0;
+
+ private Stack functionStack = new Stack<>();
+
public SHSYNCSignals() {
}
@@ -66,7 +85,25 @@ TRAP = "trap"
this.parsedFileName = file.toString();
this.zzReader = new FileReader(new Path(file.getAbsolutePath()).toOSString());
}
-
+
+ private void endLocation() throws JFlexException {
+ try{
+ Function functionFinished = functionStack.pop();
+ if (!functionStack.empty()) {
+ /* there is a current function: change location to this function */
+ location = functionStack.peek().getName();
+ } else {
+ /* we are in the main program: change location to main */
+ location = MAINPROGRAM;
+ }
+ }catch(EmptyStackException e){
+ final String errorMessage = e.getMessage();
+ throw new JFlexException(this.getClass().getName(), parsedFileName,
+ errorMessage, yytext(), yyline, yycolumn);
+ }
+ }
+
+
%}
%eofval{
@@ -97,7 +134,7 @@ TRAP = "trap"
/************************/
{
- {VAR} {location = yytext(); yybegin(YYINITIAL);}
+ {FNAME} {location = yytext(); functionLine = yyline+1; yybegin(BEGINFUNC);}
\n {yybegin(YYINITIAL);}
. {}
}
@@ -109,8 +146,30 @@ TRAP = "trap"
{
{COMMENT_WORD} {yybegin(COMMENT);}
{FUNCTION} {yybegin(NAMING);}
- {FUNCT} {location = yytext().substring(0,yytext().length()-2).trim(); }
- {STRING} {}
+ {FUNCT} {functionLine = yyline+1;
+ location = yytext().substring(0,yytext().length()-2).trim();
+ yybegin(BEGINFUNC);
+ }
+ {FUNCSTART} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().getFinisher().equals(Function.finisherOf(yytext()))){
+ functionStack.peek().addStarterRepetition();
+ }
+ }
+ }
+ {FUNCEND} {
+ if(!functionStack.empty()){
+ if(functionStack.peek().isFinisher(yytext())){
+ if(functionStack.peek().getStarterRepetition()>0) {
+ functionStack.peek().removeStarterRepetition();
+ } else {
+ endLocation();
+ }
+ }
+ }
+ }
+ {STRING_D} {yybegin(STRING_DOUBLE);}
+ {STRING_S} {yybegin(STRING_SIMPLE);}
{TRAP} {yybegin(TRAP);}
[^] {}
}
@@ -126,7 +185,50 @@ TRAP = "trap"
. {}
}
+/************************/
+/* BEGINFUNC STATE */
+/************************/
+/*
+ * This state target is to retrieve the function starter. For more information on fonction starter, have a look on {@link Function} class.
+ * Pending this starter, the function ender can be defined.
+ *
+ */
+
+ {
+ \(\) {}
+ {FUNCSTART} {
+ Function function;
+ function = new Function(location, functionLine, yytext());
+ functionStack.push(function);
+ yybegin(YYINITIAL);
+ }
+ [^]|{SPACE} {}
+ }
+
+/*
+ * The string states are designed to avoid problems due to patterns found in strings.
+ */
+/************************/
+/* STRING_SIMPLE STATE */
+/************************/
+
+ {
+ {IGNORE_STRING_S} {}
+ {STRING_S} {yybegin(YYINITIAL);}
+ [^]|{SPACE} {}
+ }
+/************************/
+/* STRING_DOUBLE STATE */
+/************************/
+
+ {
+ {IGNORE_STRING_D} {}
+ {STRING_D} {yybegin(YYINITIAL);}
+ [^]|{SPACE} {}
+ }
+
+
/************************/
/* ERROR STATE */
/************************/
diff --git a/fr.cnes.analysis.tools.shell.rules/plugin.xml b/fr.cnes.analysis.tools.shell.rules/plugin.xml
index 9a0e1018..9172ad3c 100755
--- a/fr.cnes.analysis.tools.shell.rules/plugin.xml
+++ b/fr.cnes.analysis.tools.shell.rules/plugin.xml
@@ -5,6 +5,16 @@
id="shell.rules"
name="Shell Rules"
point="fr.cnes.analysis.tools.analyzer.checks">
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/fr.cnes.analysis.tools.shell.rules/pom.xml b/fr.cnes.analysis.tools.shell.rules/pom.xml
index 40525123..435f866a 100644
--- a/fr.cnes.analysis.tools.shell.rules/pom.xml
+++ b/fr.cnes.analysis.tools.shell.rules/pom.xml
@@ -6,7 +6,7 @@
fr.cnes.icode
fr.cnes.icode.parent
- 3.0.1-SNAPSHOT
+ 3.1.0-SNAPSHOT
fr.cnes.analysis.tools.shell.rules
diff --git a/fr.cnes.analysis.tools.shell.rules/src/fr/cnes/analysis/tools/shell/rules/FunctionInvariant.java b/fr.cnes.analysis.tools.shell.rules/src/fr/cnes/analysis/tools/shell/rules/FunctionInvariant.java
new file mode 100644
index 00000000..5a2977fa
--- /dev/null
+++ b/fr.cnes.analysis.tools.shell.rules/src/fr/cnes/analysis/tools/shell/rules/FunctionInvariant.java
@@ -0,0 +1,58 @@
+package fr.cnes.analysis.tools.shell.rules;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This class is added to handle functions and their local and global variables for the COMDATAInvariant rule.
+ * The COMDATAInvariant rule uses a hash table per function of variables that should be constants, and
+ * a list per function of variables that are either declared as constants or have been assigned more than once.
+ */
+
+public class FunctionInvariant extends FunctionWithVariables {
+
+ /* okVariables: contains all variables that have either been declared as consts or */
+ /* should be variables. There should be no violation on them. */
+ private ArrayList okVariables;
+
+ /* okGlobalVariables: contains all global to the function variables that should be variables.
+ * There should be no violation on them. */
+ private ArrayList okGlobalVariables;
+
+ /* errVariables: contains all variables that for the moment should be consts */
+ /* String: variable name, Integer: variable line in code */
+ private HashMap errVariables;
+
+ public FunctionInvariant(String pName, int pBeginLine, String pStarter) {
+ super(pName, pBeginLine, pStarter);
+ this.okVariables = new ArrayList();
+ this.errVariables = new HashMap