Jelajahi Sumber

Expression Parser. English rework

Lucas de Souza 6 tahun lalu
induk
melakukan
9ed4bd5d88

+ 65 - 64
grammar/pt-br/ivprog.g4

@@ -1,166 +1,167 @@
 lexer grammar ivprog;
-
-PR_PROGRAMA
+// BEGIN i18n Lexical rules
+RK_PROGRAM
   : 'programa'
   ;
 
-PR_REAL
+RK_REAL
   : 'real'
   ;
 
-PR_VAZIO
+RK_VOID
   : 'vazio'
   ;
 
-PR_LOGICO
+RK_LOGIC
   : 'logico'
   ;
 
-PR_CADEIA
+RK_STRING
   : 'cadeia'
   ;
 
-PR_INTEIRO
+RK_INTEGER
   : 'inteiro'
   ;
 
-PR_CARACTER
+RK_CHARACTER
   : 'caractere'
   ;    
 
-PR_ESCOLHA
+RK_SWITCH
   : 'escolha'
   ;
 
-PR_CASO
+RK_CASE
   : 'caso'
   ;
 
-PR_CONTRARIO
+RK_DEFAULT
   : 'contrario'
   ;
 
-PR_CONST
+RK_CONST
   : 'const'
   ;
 
-PR_FUNCAO
+RK_FUNCTION
   : 'funcao'
   ;
 
-PR_RETORNE
+RK_RETURN
   : 'retorne'
   ;  
 
-PR_PARA
+RK_FOR
   : 'para'
   ;
 
-PR_PARE
+RK_BREAK
   : 'pare'
   ;
 
-PR_FACA
+RK_DO
   : 'faca'
   ;
 
-PR_ENQUANTO
+RK_WHILE
   : 'enquanto'
   ;
 
-PR_SE
+RK_IF
   : 'se'
   ;
 
-PR_SENAO
+RK_ELSE
   : 'senao'
   ;
 
-fragment PR_FALSO
+fragment RK_FALSE
   : 'falso'
   ;
 
-fragment PR_VERDADEIRO
+fragment RK_TRUE
   : 'verdadeiro'
   ;
 
-fragment PR_NAO_LOGICO
+fragment RK_LOGICAL_NOT
   : 'nao'
   ;
 
-fragment PR_E_LOGICO
+fragment RK_LOGICAL_AND
   : 'E'
   ;
 
-fragment PR_OU_LOGICO
+fragment RK_LOGICAL_OR
   : 'OU'
   ;
+// END i18n Lexical rules
 
 // GAMBIARRA   : '.' |'á'| 'à'| 'ã'|'â'|'é'|'ê'|'í'|'ó'|'ô'|'õ'|'ú'|'ü'|'ç'|'Ä'|'À'|'Ã'|'Â'|'É'|'Ê'|'Ë'|'Ó'|'Ô'|'Õ'|'Ú'|'Ü'|'Ç'|'#'|'$'|'"'|'§'|'?'|'¹'|'²'|'³'|'£'|'¢'|'¬'|'ª'|'º'|'~'|'\''|'`'|'\\'|'@';
 
-ABRE_PAR
+OPEN_PARENTHESIS
   : '('
   ;
 
-FECHA_PAR
+CLOSE_PARENTHESIS
   : ')'
   ;
 
-ABRE_COL
+OPEN_BRACE
   : '['
   ;
 
-FECHA_COL
+CLOSE_BRACE
   : ']'
   ;
 
-ABRE_CHA
+OPEN_CURLY
   : '{'
   ;
 
-FECHA_CHA
+CLOSE_CURLY
   : '}'
   ;
 
-VIRGULA
+COMMA
   : ','
   ;
 
-ATRIBUICAO
+EQUAL
   : '='
   ;
 
-OPERADOR_SOMA
+SUM_OP
   : ('+'|'-')
   ;
 
-OPERADOR_MULTIPLICATIVO
+MULTI_OP
   : ('*'|'/'|'%')
   ;
 
-OPERADOR_E
-  : PR_E_LOGICO
+AND_OPERATOR
+  : RK_LOGICAL_AND
   ;
 
-OPERADOR_OU
-  : PR_OU_LOGICO
+OR_OPERATOR
+  : RK_LOGICAL_OR
   ;
 
-OPERADOR_RELACIONAL
+RELATIONAL_OPERATOR
   : ('>='|'=='|'<='|'>'|'<')
   ;
 
-DPONTOS
+COLON
   : ':'
   ;
 
-OPERADOR_NAO
-  : PR_NAO_LOGICO
+NOT_OPERATOR
+  : RK_LOGICAL_NOT
   ;
 
 LOGICO
-  : PR_VERDADEIRO
-  | PR_FALSO
+  : RK_TRUE
+  | RK_FALSE
   ;
 
 ID
@@ -169,9 +170,9 @@ ID
 
 // ID_BIBLIOTECA     : ID '.' ID;
 
-INTEIRO
+INTEGER
   : [0-9]+
-  | ('0x'|'0X')(DIGIT_HEX)+
+  | ('0x'|'0X')(HEX_DIGIT)+
   | ('0b'|'0B')[0-1]+
   ;
 
@@ -179,57 +180,57 @@ REAL
   : [0-9]+ '.' [0-9]+
   ;
 
-CADEIA
-  : '"' CADEIA_CARACTER* '"'
+STRING
+  : '"' STRING_CHARACTER* '"'
   ;
     
-fragment CADEIA_CARACTER //String como definido em https://github.com/antlr/grammars-v4/blob/master/java8/Java8.g4
+fragment STRING_CHARACTER //String como definido em https://github.com/antlr/grammars-v4/blob/master/java8/Java8.g4
   : ~["\\\r\n]
-  | SEQ_ESC
+  | ESC_SEQ
   ;
 
-CARACTER //Caracter como definido em https://github.com/antlr/grammars-v4/blob/master/java8/Java8.g4
-  : '\'' ( SEQ_ESC | ~['\\\r\n]) '\''
+CHARACTER //Caracter como definido em https://github.com/antlr/grammars-v4/blob/master/java8/Java8.g4
+  : '\'' ( ESC_SEQ | ~['\\\r\n]) '\''
   ;
 
-ESPACO 
+WHITESPACE 
   : ( ' ' | '\t') -> skip
   ;
 
-fragment PONTO_VIRGULA
+fragment SEMICOLON
   : ';'
   ;
 
 EOS
   : [\r\n]+
-  | PONTO_VIRGULA
+  | SEMICOLON
   ;
 
-fragment DIGIT_HEX
+fragment HEX_DIGIT
   : [0-9a-fA-F]
   ;
 
-fragment DIGIT_OCTAL
+fragment OCTAL_DIGIT
   : [0-7]
   ;
 
-fragment SEQ_ESC
+fragment ESC_SEQ
   : '\\' ('b'|'t'|'n'|'f'|'r'|'"'|'\''|'\\')
   | ESC_UNICODE
   | ESC_OCTAL
   ;
 
 fragment ESC_OCTAL
-  : '\\' [0-3] DIGIT_OCTAL DIGIT_OCTAL
-  | '\\' DIGIT_OCTAL DIGIT_OCTAL
-  | '\\' DIGIT_OCTAL
+  : '\\' [0-3] OCTAL_DIGIT OCTAL_DIGIT
+  | '\\' OCTAL_DIGIT OCTAL_DIGIT
+  | '\\' OCTAL_DIGIT
   ;
 
 fragment ESC_UNICODE
-  : '\\' 'u' DIGIT_HEX DIGIT_HEX DIGIT_HEX DIGIT_HEX
+  : '\\' 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
   ;
 
-COMENTARIO
+COMMENTS
   : ('//' ~('\n'|'\r')* '\r'? '\n'
     | '/*' .*? '*/') -> channel(HIDDEN)
   ;

js/asa/ASA.js → js/ast/ASA.js


js/asa/NoDeclaracao.js → js/ast/NoDeclaracao.js


js/asa/NoGlobal.js → js/ast/NoGlobal.js


js/asa/SyntaxError.js → js/ast/SyntaxError.js


+ 1 - 0
js/ast/commands/break.js

@@ -0,0 +1 @@
+export class Break { }

+ 6 - 0
js/ast/commands/return.js

@@ -0,0 +1,6 @@
+export class Return {
+  constructor(expression) {
+    this.expression = expression;
+  }
+  
+}

js/asa/index.js → js/ast/index.js


+ 116 - 30
js/asa/analisadorSintatico.js

@@ -1,7 +1,7 @@
 import { CommonTokenStream, InputStream } from 'antlr4/index';
 import { SyntaxError } from './SyntaxError';
 
-export class AnalisadorSintatico {
+export class IVProgParser {
 
   constructor (input, lexerClass) {
     this.lexerClass = lexerClass;
@@ -9,12 +9,12 @@ export class AnalisadorSintatico {
     this.tokenStream = new CommonTokenStream(this.lexer);
     this.tokenStream.fill();
     this.pos = 1;
-    this.variableTypes = [this.lexerClass.PR_INTEIRO,
-      this.lexerClass.PR_REAL,
-      this.lexerClass.PR_LOGICO,
-      this.lexerClass.PR_CADEIA
+    this.variableTypes = [this.lexerClass.RK_INTEGER,
+      this.lexerClass.RK_REAL,
+      this.lexerClass.RK_LOGIC,
+      this.lexerClass.RK_STRING
     ];
-    this.functionTypes = this.variableTypes.push(this.lexerClass.PR_VAZIO);
+    this.functionTypes = this.variableTypes.concat(this.lexerClass.RK_VOID);
   }
 
   parseTree () {
@@ -37,7 +37,7 @@ export class AnalisadorSintatico {
     let globalVars = [];
     let functions = [];
 
-    if(this.lexerClass.PR_PROGRAMA === token.type) {
+    if(this.lexerClass.RK_PROGRAM === token.type) {
       this.pos++;
       this.consumeNewLines();
       this.checkOpenCurly();
@@ -45,9 +45,9 @@ export class AnalisadorSintatico {
       while(true) {
         this.consumeNewLines();
         const token = this.getToken();
-        if (token.type === this.lexerClass.PR_CONST || token.type === this.lexerClass.ID) {
+        if (token.type === this.lexerClass.RK_CONST || token.type === this.lexerClass.ID) {
           globalVars = globalVars.concat(this.parseGlobalVariables());
-        } else if (token.type === this.lexerClass.PR_FUNCAO) {
+        } else if (token.type === this.lexerClass.RK_FUNCTION) {
           functions = functions.concat([]);
         } else {
           break;
@@ -62,20 +62,20 @@ export class AnalisadorSintatico {
       }
       return {global: globalVars, functions: functions};
     } else {
-      throw SyntaxError.createError(this.lexer.literalNames[this.lexerClass.PR_PROGRAMA], token);
+      throw SyntaxError.createError(this.lexer.literalNames[this.lexerClass.RK_PROGRAM], token);
     }
   }
 
   checkOpenCurly () {
     const token = this.getToken();
-    if(this.lexerClass.ABRE_CHA !== token.type){
+    if(this.lexerClass.OPEN_CURLY !== token.type){
       throw SyntaxError.createError('{', token);
     }
   }
 
   checkCloseCurly () {
     const token = this.getToken();
-    if(this.lexerClass.FECHA_CHA !== token.type){
+    if(this.lexerClass.CLOSE_CURLY !== token.type){
       throw SyntaxError.createError('}', token);
     }
   }
@@ -90,7 +90,7 @@ export class AnalisadorSintatico {
   **/
   checkOpenBrace (attempt = false) {
     const token = this.getToken();
-    if(this.lexerClass.ABRE_COL !== token.type){
+    if(this.lexerClass.OPEN_BRACE !== token.type){
       if (!attempt) {
         throw SyntaxError.createError('[', token);
       } else {
@@ -102,7 +102,7 @@ export class AnalisadorSintatico {
 
   checkCloseBrace (attempt = false) {
     const token = this.getToken();
-    if(this.lexerClass.FECHA_COL !== token.type){
+    if(this.lexerClass.CLOSE_BRACE !== token.type){
       if (!attempt) {
         throw SyntaxError.createError(']', token);
       } else {
@@ -114,7 +114,7 @@ export class AnalisadorSintatico {
 
   checkOpenParenthesis (attempt = false) {
     const token = this.getToken();
-    if(this.lexerClass.ABRE_PAR !== token.type){
+    if(this.lexerClass.OPEN_PARENTHESIS !== token.type){
       if (!attempt) {
         throw SyntaxError.createError('(', token);
       } else {
@@ -126,7 +126,7 @@ export class AnalisadorSintatico {
 
   checkCloseParenthesis (attempt = false) {
     const token = this.getToken();
-    if(this.lexerClass.FECHA_PAR !== token.type){
+    if(this.lexerClass.CLOSE_PARENTHESIS !== token.type){
       if (!attempt) {
         throw SyntaxError.createError(')', token);
       } else {
@@ -162,7 +162,7 @@ export class AnalisadorSintatico {
   **/
   parseHasConst () {
     const constToken = this.getToken();
-    if(constToken.type === this.lexerClass.PR_CONST) {
+    if(constToken.type === this.lexerClass.RK_CONST) {
       this.pos++;
       const typeString = this.parseType();
       return this.parseDeclararion(typeString, true);
@@ -200,13 +200,13 @@ export class AnalisadorSintatico {
     }
 
     const equalsToken = this.getToken();
-    if(equalsToken.type === this.lexerClass.ATRIBUICAO) {
+    if(equalsToken.type === this.lexerClass.EQUAL) {
       //process Expression(EAnd) => initial != null
       console.log("= found");
     }
 
     const commaToken = this.getToken();
-    if(commaToken.type === this.lexerClass.VIRGULA) {
+    if(commaToken.type === this.lexerClass.COMMA) {
       console.log("comma found");
       this.pos++;
       return [{
@@ -248,7 +248,7 @@ export class AnalisadorSintatico {
   **/
   getArrayDimension () {
     const dimToken = this.getToken();
-    if(dimToken.type === this.lexerClass.INTEIRO) {
+    if(dimToken.type === this.lexerClass.INTEGER) {
       //parse as int literal
       this.pos++;
       return this.parseIntLiteral(dimToken);
@@ -311,7 +311,7 @@ export class AnalisadorSintatico {
   parseFunction () {
     let formalParams = [];
     const token = this.getToken();
-    if(token.type !== this.lexerClass.PR_FUNCAO) {
+    if(token.type !== this.lexerClass.RK_FUNCTION) {
       //throw SyntaxError.createError(this.lexer.literalNames[this.lexerClass.PR_FUNCAO], token);
       return null;
     }
@@ -367,7 +367,7 @@ export class AnalisadorSintatico {
       list.push({type: typeString, id: idString, dimensions: dimensions});
       this.consumeNewLines();
       const commaToken = this.getToken();
-      if (commaToken.type !== this.lexerClass.VIRGULA)
+      if (commaToken.type !== this.lexerClass.COMMA)
         break;
       this.pos++;
     }
@@ -387,19 +387,19 @@ export class AnalisadorSintatico {
     const token = this.getToken();
     if(token.type === this.lexerClass.ID && isFunction) {
       return 'void';
-    } else if (token.type === this.lexerClass.PR_VAZIO && isFunction) {
+    } else if (token.type === this.lexerClass.RK_VOID && isFunction) {
       this.pos++;
       return 'void';
     } else if (this.isVariableType(token)) {
       this.pos++;
       switch(token.type) {
-        case this.lexerClass.PR_INTEIRO:
+        case this.lexerClass.RK_INTEGER:
           return 'int';
-        case this.lexerClass.PR_LOGICO:
+        case this.lexerClass.RK_LOGIC:
           return 'logic';
-        case this.lexerClass.PR_REAL:
+        case this.lexerClass.RK_REAL:
           return 'real';
-        case this.lexerClass.PR_CADEIA:
+        case this.lexerClass.RK_STRING:
           return 'string';
         default:
           break;
@@ -411,6 +411,7 @@ export class AnalisadorSintatico {
 
   parseFunctionBody () {
     let variablesDecl = [];
+    let commands = [];
     this.checkOpenCurly();
     this.pos++;
     while(true) {
@@ -421,18 +422,103 @@ export class AnalisadorSintatico {
         variablesDecl = variablesDecl.concat(this.parseDeclararion(token));
       } else if (token.type === this.lexerClass.ID) {
         this.pos++;
+        this.consumeNewLines();
         const equalOrParenthesis = this.getToken();
-        if (equalOrParenthesis.type === this.lexerClass.ATRIBUICAO) {
-
-        } else if (equalOrParenthesis.type === this.lexerClass.ABRE_PAR) {
+        if (equalOrParenthesis.type === this.lexerClass.EQUAL) {
+          this.pos++
+          // parse Expression (EAnd)
 
+        } else if (equalOrParenthesis.type === this.lexerClass.OPEN_PARENTHESIS) {
+          // parse function call => ID '(' actual parameters list ')'
+          // actual parameter => EAnd
         } else {
           throw SyntaxError.createError("= or (", equalOrParenthesis);
         }
+      } else if (token.type === this.lexerClass.RK_RETURN) {
+        // parse EAnd
+      } else if (token.type === this.lexerClass.RK_WHILE) {
+
+      } else if (token.type === this.lexerClass.RK_FOR) {
+
+      } else if (token.type === this.lexerClass.RK_BREAK) {
+        
+      } else if (token.type === this.lexerClass.RK_SWITCH) {
+        
+      } else if (token.type === this.lexerClass.RK_DO) {
+        
+      } else if (token.type === this.lexerClass.RK_IF) {
+        
+      } else {
+        break;
       }
     }
+    this.consumeNewLines();
+    this.checkCloseCurly();
+    return {variables: variablesDecl, commands: commands};
+  }
+
+  /*
+  * Parses an Expression following the structure:
+  *
+  * EAnd  => EOR ( 'and' EAnd)? #expression and
+  *
+  * EOR   => ENot ('or' EAnd)? #expression or
+  *
+  * ENot  => 'not'? ER #expression not
+  *
+  * ER    => E ((>=, <=, ==, >, <) E)? #expression relational
+  *
+  * E     => factor ((+, -) E)? #expression
+  *
+  * factor=> term ((*, /, %) factor)?
+  *
+  * term  => literal || arrayAccess || FuncCall || ID || '('EAnd')'
+  **/
+  parseExpressionOR () {
+    const andEpxression1 = this.parseExpressionAND();
+    let andEpxression2 = null;
+    let or = null;
+    const maybeAnd = this.getToken();
+    if (maybeAnd.type === this.lexerClass.OR_OPERATOR) {
+      this.pos++;
+      or = 'or';
+      andEpxression2 = this.parseExpressionAND();
+    }
+
+    return {left: andEpxression1, op:or, right: andEpxression2};
   }
 
+  parseExpressionAND () {
+    const eNot1 = this.parseExpressionNot();
+    let and = null;
+    let eNot2 = null;
+    const andToken = this.getToken();
+    if (andToken.type === this.lexerClass.AND_OPERATOR) {
+      this.pos++;
+      and = 'and';
+      eNot2 = this.parseExpressionNot();
+    }
+
+    return {left: eNot1, op: or, right: eNot2};
+  }
+
+  parseExpressionNot () {
+    this.consumeNewLines();
+    let not = null;
+    const notToken = this.getToken();
+    if (notToken.type === this.lexerClass.NOT_OPERATOR) {
+      this.pos++;
+      not = 'not';
+    }
+    const eRel = this.parseExpressionRel();
+
+    return {left: null, op: not, right: eRel};
+  }
+
+
+
+
+
   getTypesAsString (isFunction = false) {
     const types = isFunction ? this.functionTypes : this.variableTypes;
     return types.map( x => this.lexer.literalNames[x])

+ 3 - 3
js/main.js

@@ -2,7 +2,7 @@ import {
     InputStream,
     CommonTokenStream
 } from 'antlr4/index';
-import { AnalisadorSintatico } from './asa/analisadorSintatico';
+import { IVProgParser } from './ast/ivprogParser';
 import Lexers from '../grammar/';
 
 const lang = 'pt_br';
@@ -18,12 +18,12 @@ const stream = new CommonTokenStream(lexer);
 stream.fill();
 let i = 1;
 let token = null;
-while ((token = stream.LT(i)).type !== ivprogLexer.EOF && token.type !== ivprogLexer.ESPACO) {
+while ((token = stream.LT(i)).type !== ivprogLexer.EOF && token.type !== ivprogLexer.WHITESPACE) {
     console.log(`${token.type}-${token.text}`);
     console.log('\n')
     i++;
 }
-const anaSin = new AnalisadorSintatico(input, ivprogLexer);
+const anaSin = new IVProgParser(input, ivprogLexer);
 try {
   console.log(anaSin.parseTree().global);
 } catch(a) {

+ 2 - 1
karma.conf.js

@@ -8,6 +8,7 @@ module.exports = function(config) {
     exclude: [],
     //files/patterns to load in the browser
     files: [
+      './node_modules/phantomjs-polyfill-find/find-polyfill.js',
       {pattern: 'tests/*.js',watched:true,served:true,included:true}
       /*parameters*/
           //watched: if autoWatch is true all files that have set watched to true will be watched for changes
@@ -31,7 +32,7 @@ module.exports = function(config) {
     //list of frameworks you want to use, only jasmine is installed automatically
     frameworks: ['jasmine'],
     //list of browsers to launch and capture
-    browsers: ['Firefox'/*,'PhantomJS','Firefox','Edge','ChromeCanary','Opera','IE','Safari'*/],
+    browsers: ['PhantomJS'/*,'PhantomJS','Firefox','Edge','ChromeCanary','Opera','IE','Safari'*/],
     //list of reporters to use
     reporters: ['mocha','kjhtml'/*,'dots','progress','spec'*/],
     

+ 5 - 0
package-lock.json

@@ -5548,6 +5548,11 @@
       "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
       "dev": true
     },
+    "phantomjs-polyfill-find": {
+      "version": "github:ptim/phantomjs-polyfill-find#026b69dcabe743265f5214775e42f8d1e8aabedc",
+      "from": "github:ptim/phantomjs-polyfill-find",
+      "dev": true
+    },
     "phantomjs-prebuilt": {
       "version": "2.1.16",
       "resolved": "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.16.tgz",

+ 1 - 0
package.json

@@ -39,6 +39,7 @@
     "karma-mocha-reporter": "^2.2.5",
     "karma-phantomjs-launcher": "^1.0.4",
     "karma-webpack": "^3.0.0",
+    "phantomjs-polyfill-find": "github:ptim/phantomjs-polyfill-find",
     "webpack": "^4.16.5",
     "webpack-cli": "^3.1.0"
   },

+ 3 - 3
tests/syntax.spec.js

@@ -1,7 +1,7 @@
 import Lexers from './../grammar/';
 import {
-    AnalisadorSintatico
-} from './../js/asa/analisadorSintatico';
+    IVProgParser
+} from './../js/ast/ivprogParser';
 describe("Testing Syntax Analysis for default", () => {
 
     var input;
@@ -40,7 +40,7 @@ describe("Testing Syntax Analysis for default", () => {
           }],
           functions: []
         };
-        const as = new AnalisadorSintatico(input, lexer);
+        const as = new IVProgParser(input, lexer);
         expect(as.parseTree()).toEqual(asa);
     });
 });