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..349d404b 100755 --- a/fr.cnes.analysis.tools.shell.metrics/META-INF/MANIFEST.MF +++ b/fr.cnes.analysis.tools.shell.metrics/META-INF/MANIFEST.MF @@ -9,3 +9,4 @@ Require-Bundle: org.eclipse.core.runtime, 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.rules/META-INF/MANIFEST.MF b/fr.cnes.analysis.tools.shell.rules/META-INF/MANIFEST.MF index 38a53b37..443f03ff 100755 --- a/fr.cnes.analysis.tools.shell.rules/META-INF/MANIFEST.MF +++ b/fr.cnes.analysis.tools.shell.rules/META-INF/MANIFEST.MF @@ -5,7 +5,8 @@ Bundle-SymbolicName: fr.cnes.analysis.tools.shell.rules;singleton:=true Bundle-Version: 3.0.1.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.0.1" 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..3035bb62 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,22 @@ 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\space] +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" | "select" | "for" | "while" | "until" +FUNCEND = \} | \) | \)\) | \]\] | "fi" | "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 +66,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 +90,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 +193,15 @@ OPTION = \- ("a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "k" | /************************/ { - {VAR} {location = location + yytext(); yybegin(YYINITIAL);} - \n {yybegin(YYINITIAL);} - . {} + {VAR} { + location = yytext(); + functionLine = yyline+1; + yybegin(BEGINFUNC); + } + \n { + yybegin(YYINITIAL); + } + . {} } /************************/ @@ -113,18 +210,41 @@ 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); + } + {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 +257,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 +267,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 +279,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 +289,32 @@ 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. + * + */ + + { + \(\) {} + {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/COMPRESLengthLine.lex b/fr.cnes.analysis.tools.shell.rules/lex/COMPRESLengthLine.lex index 2e4e0565..18101f8f 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\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})) +FUNCSTART = \{ | \( | \(\( | \[\[ | "if" | "select" | "for" | "while" | "until" +FUNCEND = \} | \) | \)\) | \]\] | "fi" | "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);} + {VAR} {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/SHREFExport.lex b/fr.cnes.analysis.tools.shell.rules/lex/SHREFExport.lex index f519e0d8..fd9916b3 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}*\(\) -SPACE = [\ \r\t\f] -VAR = [a-zA-Z][a-zA-Z0-9\_]* -STRING = \'[^\']*\' | \"[^\"]*\" - -EXPORT = "export"{SPACE}+\-"f"{SPACE}+{VAR} - - +FUNCT = {FNAME}{SPACE}*[\(]{SPACE}*[\)] +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})) + +FUNCSTART = \{ | \( | \(\( | \[\[ | "if" | "select" | "for" | "while" | "until" +FUNCEND = \} | \) | \)\) | \]\] | "fi" | "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);} + {VAR} {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/plugin.xml b/fr.cnes.analysis.tools.shell.rules/plugin.xml index 9a0e1018..dfa0d82d 100755 --- a/fr.cnes.analysis.tools.shell.rules/plugin.xml +++ b/fr.cnes.analysis.tools.shell.rules/plugin.xml @@ -5,6 +5,11 @@ id="shell.rules" name="Shell Rules" point="fr.cnes.analysis.tools.analyzer.checks"> + + + + + + + diff --git a/fr.cnes.analysis.tools.shell.rules/src/fr/cnes/analysis/tools/shell/rules/FunctionWithVariables.java b/fr.cnes.analysis.tools.shell.rules/src/fr/cnes/analysis/tools/shell/rules/FunctionWithVariables.java new file mode 100644 index 00000000..9860b6d5 --- /dev/null +++ b/fr.cnes.analysis.tools.shell.rules/src/fr/cnes/analysis/tools/shell/rules/FunctionWithVariables.java @@ -0,0 +1,45 @@ + +/************************************************************************************************/ +/* 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 */ +/************************************************************************************************/ +package fr.cnes.analysis.tools.shell.rules; + +import java.util.ArrayList; + +import fr.cnes.analysis.tools.shell.metrics.Function; + +/** + * This class can be used to handle functions and their local and global variables. + */ +public class FunctionWithVariables extends Function { + + /* localVariables: the list of local variables in the function */ + private ArrayList localVariables = null; + /* globalVariables: the list of global variables in the function */ + private ArrayList globalVariables = null; + + /** + * @param pName + * Function's name + * @param pBeginLine + * Function's line + * @param pStarter + * Function's starter. + */ + public FunctionWithVariables(String pName, int pBeginLine, String pStarter) { + super(pName, pBeginLine, pStarter); + this.localVariables = new ArrayList(); + this.globalVariables = new ArrayList(); + } + + public ArrayList getLocalVariables() { + return this.localVariables; + } + + public ArrayList getGlobalVariables() { + return this.globalVariables; + } + +} diff --git a/tests/fr.cnes.analysis.tools.shell.rules.test/src/fr/cnes/analysis/tools/shell/rules/COM/DATA/Initialisation/TestCOMDATAInitialisation.java b/tests/fr.cnes.analysis.tools.shell.rules.test/src/fr/cnes/analysis/tools/shell/rules/COM/DATA/Initialisation/TestCOMDATAInitialisation.java index 8ea696f8..9c047481 100755 --- a/tests/fr.cnes.analysis.tools.shell.rules.test/src/fr/cnes/analysis/tools/shell/rules/COM/DATA/Initialisation/TestCOMDATAInitialisation.java +++ b/tests/fr.cnes.analysis.tools.shell.rules.test/src/fr/cnes/analysis/tools/shell/rules/COM/DATA/Initialisation/TestCOMDATAInitialisation.java @@ -35,8 +35,8 @@ public class TestCOMDATAInitialisation { public final static String ERROR_FILE = "error.sh"; public final static String NO_ERROR_FILE = "noError.sh"; - public final static int[] LINES = { 9 }; - public final static String[] LOCATIONS = { "MAIN PROGRAM" }; + public final static int[] LINES = { 9, 15, 20, 25, 27, 32, 37 }; + public final static String[] LOCATIONS = { "MAIN PROGRAM", "function1", "MAIN PROGRAM", "function2", "function2", "function3", "MAIN PROGRAM" }; public final AbstractChecker rule = new COMDATAInitialisation(); /** diff --git a/tests/fr.cnes.analysis.tools.shell.rules.test/src/fr/cnes/analysis/tools/shell/rules/COM/DATA/Initialisation/error.sh b/tests/fr.cnes.analysis.tools.shell.rules.test/src/fr/cnes/analysis/tools/shell/rules/COM/DATA/Initialisation/error.sh index 4a64227b..2fa92aa3 100755 --- a/tests/fr.cnes.analysis.tools.shell.rules.test/src/fr/cnes/analysis/tools/shell/rules/COM/DATA/Initialisation/error.sh +++ b/tests/fr.cnes.analysis.tools.shell.rules.test/src/fr/cnes/analysis/tools/shell/rules/COM/DATA/Initialisation/error.sh @@ -5,5 +5,33 @@ echo "Fichier KO de TU" echo "------------------------------------------" x=1 -# la variable y n'est pas initiliaze +# the y variable is not initialized z=$x+$y + +function function1 () +{ + b = 2 + # the c variable is not initialized + a = $b+$c +} + +# main - the y variable is not initialized + +xx=$y + +function2 () +{ + # the b variable is not initialized + a = $b + # the y variable is not initialized + d = $y + + function function3 () + { + # the y variable is not initialized + e = $y + } +} + +# the y variable is not initialized +yy=$y diff --git a/tests/fr.cnes.analysis.tools.shell.rules.test/src/fr/cnes/analysis/tools/shell/rules/COM/DATA/Initialisation/noError.sh b/tests/fr.cnes.analysis.tools.shell.rules.test/src/fr/cnes/analysis/tools/shell/rules/COM/DATA/Initialisation/noError.sh index 218bc313..3e527bb7 100755 --- a/tests/fr.cnes.analysis.tools.shell.rules.test/src/fr/cnes/analysis/tools/shell/rules/COM/DATA/Initialisation/noError.sh +++ b/tests/fr.cnes.analysis.tools.shell.rules.test/src/fr/cnes/analysis/tools/shell/rules/COM/DATA/Initialisation/noError.sh @@ -6,4 +6,28 @@ echo "------------------------------------------" x=1 y=2 -z=$x+$y \ No newline at end of file +z=$x+$y + +function function1 () +{ + b = 2 + c = 3 + a = $b+$c +} + +# main +xx=y + +function2 () +{ + b = 2 + a = $b+$xx + function function3 () + { + e = $a + } + + +} + +yy=$xx \ No newline at end of file diff --git a/tests/fr.cnes.analysis.tools.shell.rules.test/src/fr/cnes/analysis/tools/shell/rules/COM/PRES/LengthLine/TestCOMPRESLengthLine.java b/tests/fr.cnes.analysis.tools.shell.rules.test/src/fr/cnes/analysis/tools/shell/rules/COM/PRES/LengthLine/TestCOMPRESLengthLine.java index e0994ba2..dc874937 100755 --- a/tests/fr.cnes.analysis.tools.shell.rules.test/src/fr/cnes/analysis/tools/shell/rules/COM/PRES/LengthLine/TestCOMPRESLengthLine.java +++ b/tests/fr.cnes.analysis.tools.shell.rules.test/src/fr/cnes/analysis/tools/shell/rules/COM/PRES/LengthLine/TestCOMPRESLengthLine.java @@ -35,8 +35,8 @@ public class TestCOMPRESLengthLine { public final static String ERROR_FILE = "error.sh"; public final static String NO_ERROR_FILE = "noError.sh"; - public final static int[] LINES = { 9, 45, 47 }; - public final static String[] LOCATIONS = { "MAIN PROGRAM", "affiche_resultat", "affiche_resultat" }; + public final static int[] LINES = { 9, 18, 48, 55, 57, 75}; + public final static String[] LOCATIONS = { "MAIN PROGRAM", "ma_fonction_affine", "affiche_resultat", "test_length", "affiche_resultat", "MAIN PROGRAM"}; public final AbstractChecker rule = new COMPRESLengthLine(); /** diff --git a/tests/fr.cnes.analysis.tools.shell.rules.test/src/fr/cnes/analysis/tools/shell/rules/COM/PRES/LengthLine/error.sh b/tests/fr.cnes.analysis.tools.shell.rules.test/src/fr/cnes/analysis/tools/shell/rules/COM/PRES/LengthLine/error.sh index 3f94d936..943a1092 100755 --- a/tests/fr.cnes.analysis.tools.shell.rules.test/src/fr/cnes/analysis/tools/shell/rules/COM/PRES/LengthLine/error.sh +++ b/tests/fr.cnes.analysis.tools.shell.rules.test/src/fr/cnes/analysis/tools/shell/rules/COM/PRES/LengthLine/error.sh @@ -6,7 +6,7 @@ echo "------------------------------------------" code_erreur_nbargs=-128 -# Dénition de la variable qui contiendra le code retour (en particulier pour les cas d'erreur avec valeurs negatives) +# Dénition de la variable qui contiendra le code retour (en particulier pour les cas d'erreur avec valeurs negatives) - function test r_ma_fonction_affine= # ------------------------------------------------------------------------------------ @@ -14,13 +14,14 @@ r_ma_fonction_affine= # ------------------------------------------------------------------------------------ ma_fonction_affine () { - if [ $# -ne 3 ] + + printf "This is a long line in the ma_fonction_affine function to test the line length maximum" + + if [ $# -ne 3 ] then r_ma_fonction_affine=$code_erreur_nbargs else -# printf "interface appel fonction ok : p1=%s p2=%s p3=%s\n" $1 $2 $3 - # calcul : y = ax + b let y=$1*$2+$3 # printf "y=%s\n" $y @@ -36,18 +37,25 @@ affiche_resultat () { if [ $# -ne 2 ] then - printf "Erreur grave dans affiche_resultat : nombre d'arguments incorrects\n" + printf "Erreur grave dans affiche_resultat : nombre d'arguments incorrects" else p1=$1 p2=$2 if [ $p2 -ge 0 ] then - printf "execution de 'ma_fonction_affine' avec chaine de calcul : %s resultat = %s \n" $p1 $2 + printf "execution de 'ma_fonction_affine' avec chaine de calcul : %s resultat = %s " $p1 $2 else - printf "erreur d'execution de 'ma_fonction_affine' avec chaine de calcul : %s code retour = %s\n" $p1 $p2 - printf " ===>Erreur grave dans ma_fonction_affine : nombre d'arguments incorrects<===\n" + printf "erreur d'execution de 'ma_fonction_affine' avec chaine de calcul : %s code retour = %s" $p1 $p2 + printf " ===>Erreur grave dans ma_fonction_affine : nombre d'arguments incorrects<===" fi fi + + function test_length () + { + printf "this too is a very very very very very very very very very very long line to test the length limit pb anti-n\n" + } + printf "this too is a very very very very long line to test the length limit while out of the included function pb anti-n\n" + } a_trouver=$(($RANDOM % 100)) @@ -64,6 +72,6 @@ do fi read i done -echo "bravo, le nombre etait en effet $a_trouver" +echo "bravo, le nombre etait en effet $a_trouver, vous avez gagne !!!!! Merci de relancer si vous voulez rejouer" diff --git a/tests/fr.cnes.analysis.tools.shell.rules.test/src/fr/cnes/analysis/tools/shell/rules/SH/REF/Export/TestSHREFExport.java b/tests/fr.cnes.analysis.tools.shell.rules.test/src/fr/cnes/analysis/tools/shell/rules/SH/REF/Export/TestSHREFExport.java index 38b3980e..4703c3b9 100755 --- a/tests/fr.cnes.analysis.tools.shell.rules.test/src/fr/cnes/analysis/tools/shell/rules/SH/REF/Export/TestSHREFExport.java +++ b/tests/fr.cnes.analysis.tools.shell.rules.test/src/fr/cnes/analysis/tools/shell/rules/SH/REF/Export/TestSHREFExport.java @@ -35,8 +35,8 @@ public class TestSHREFExport { public final static String ERROR_FILE = "error.sh"; public final static String NO_ERROR_FILE = "noError.sh"; - public final static int[] LINES = { 18 }; - public final static String[] LOCATIONS = { "verifie_seuil_shell" }; + public final static int[] LINES = { 18, 27, 30 }; + public final static String[] LOCATIONS = { "MAIN PROGRAM", "testFunction","MAIN PROGRAM" }; public final AbstractChecker rule = new SHREFExport(); /** diff --git a/tests/fr.cnes.analysis.tools.shell.rules.test/src/fr/cnes/analysis/tools/shell/rules/SH/REF/Export/error.sh b/tests/fr.cnes.analysis.tools.shell.rules.test/src/fr/cnes/analysis/tools/shell/rules/SH/REF/Export/error.sh index fd419e20..d0376451 100755 --- a/tests/fr.cnes.analysis.tools.shell.rules.test/src/fr/cnes/analysis/tools/shell/rules/SH/REF/Export/error.sh +++ b/tests/fr.cnes.analysis.tools.shell.rules.test/src/fr/cnes/analysis/tools/shell/rules/SH/REF/Export/error.sh @@ -14,10 +14,17 @@ verifie_seuil_shell() # --- Export d'une constante typeset -r MAX_SHELL_LEVEL=2 export MAX_SHELL_LEVEL -# --- Export d'une certaine fonctions +# --- Export d'une certaine function export -f verifie_seuil_shell # --- Variables locales nom_script=$(basename $0) echo "Variable exportee au $nom_script s'appelle MAX_SHELL_LEVEL" -echo "Founction exportee au $nom_script s'appelle verifie_seuil_shell" \ No newline at end of file +echo "function exportee au $nom_script s'appelle verifie_seuil_shell" + +function testFunction () +{ + export -f verifie_seuil_shell +} + +export -f testFunction