Преглед изворни кода

Versão inicial do analisador sintático: Programa e Declarações globais

Lucas de Souza пре 5 година
родитељ
комит
0287f2ef5b
4 измењених фајлова са 380 додато и 65 уклоњено
  1. 221 62
      grammar/pt-br/ivprog.g4
  2. 6 0
      js/asa/SintaxError.js
  3. 147 0
      js/asa/analisadorSintatico.js
  4. 6 3
      js/main.js

+ 221 - 62
grammar/pt-br/ivprog.g4

@@ -1,76 +1,235 @@
 lexer grammar ivprog;
 
-PR_PROGRAMA     : 'programa'    ;
-PR_REAL       : 'real'    ;
-PR_VAZIO        : 'vazio'   ;
-PR_LOGICO       : 'logico'    ;
-PR_CADEIA       : 'cadeia'    ;
-PR_INTEIRO        : 'inteiro'   ;
-PR_CARACTER     : 'caracter'    ;    
-PR_ESCOLHA        : 'escolha'   ;
-PR_CASO       : 'caso'    ;
-PR_CONTRARIO      : 'contrario' ;
-PR_CONST        : 'const'   ;
-PR_FUNCAO       : 'funcao'    ;
-PR_RETORNE        : 'retorne'   ;  
-PR_PARA       : 'para'    ;
-PR_PARE       : 'pare'    ;
-PR_FACA       : 'faca'    ;
-PR_ENQUANTO     : 'enquanto'    ;
-PR_SE       : 'se'    ;
-PR_SENAO        : 'senao'   ;
-
-
-GAMBIARRA   : '.' |'á'| 'à'| 'ã'|'â'|'é'|'ê'|'í'|'ó'|'ô'|'õ'|'ú'|'ü'|'ç'|'Ä'|'À'|'Ã'|'Â'|'É'|'Ê'|'Ë'|'Ó'|'Ô'|'Õ'|'Ú'|'Ü'|'Ç'|'#'|'$'|'"'|'§'|'?'|'¹'|'²'|'³'|'£'|'¢'|'¬'|'ª'|'º'|'~'|'\''|'`'|'\\'|'@';
- 
-fragment PR_FALSO     : 'falso'   ;
-fragment PR_VERDADEIRO    : 'verdadeiro'    ;
-
-ABRE_PAR: '(';
-FECHA_PAR: ')';
-ABRE_COL: '[';
-FECHA_COL: ']';
-ABRE_CHA: '{';
-FECHA_CHA: '}';
-VIRGULA: ',';
-PONTO_VIRGULA: ';';
-ATRIBUICAO: '=';
-OPERADOR_ARITMETICO: ('+'|'-'|'*'|'/'|'%');
-OPERADOR_E: 'E';
-OPERADOR_OU: 'OU';
-OPERADOR_RELACIONAL: ('>='|'=='|'<='|'>'|'<');
-DPONTOS: ':';
-
-OPERADOR_NAO      : 'nao'   ;
-
-LOGICO        :   PR_VERDADEIRO | PR_FALSO  ;
-
-ID        : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*  ;
+PR_PROGRAMA
+  : 'programa'
+  ;
 
-// ID_BIBLIOTECA     : ID '.' ID;
+PR_REAL
+  : 'real'
+  ;
 
-INTEIRO         : '0'..'9'+ | ('0x'|'0X')(DIGIT_HEX)+ | ('0b'|'0B')('0'|'1')+;
+PR_VAZIO
+  : 'vazio'
+  ;
 
-REAL          :   ('0'..'9')+ '.' ('0'..'9')+ ;
-    
-CADEIA        : '"' ( SEQ_ESC | ~('\\'|'"') )* '"'  ;
+PR_LOGICO
+  : 'logico'
+  ;
+
+PR_CADEIA
+  : 'cadeia'
+  ;
+
+PR_INTEIRO
+  : 'inteiro'
+  ;
+
+PR_CARACTER
+  : 'caractere'
+  ;    
+
+PR_ESCOLHA
+  : 'escolha'
+  ;
+
+PR_CASO
+  : 'caso'
+  ;
+
+PR_CONTRARIO
+  : 'contrario'
+  ;
+
+PR_CONST
+  : 'const'
+  ;
+
+PR_FUNCAO
+  : 'funcao'
+  ;
+
+PR_RETORNE
+  : 'retorne'
+  ;  
+
+PR_PARA
+  : 'para'
+  ;
+
+PR_PARE
+  : 'pare'
+  ;
+
+PR_FACA
+  : 'faca'
+  ;
+
+PR_ENQUANTO
+  : 'enquanto'
+  ;
+
+PR_SE
+  : 'se'
+  ;
+
+PR_SENAO
+  : 'senao'
+  ;
+
+fragment PR_FALSO
+  : 'falso'
+  ;
+
+fragment PR_VERDADEIRO
+  : 'verdadeiro'
+  ;
 
-CARACTER        :   '\'' ( SEQ_ESC | ~('\''|'\\') ) '\''  ;
+fragment PR_NAO_LOGICO
+  : 'nao'
+  ;
 
-ESPACO        : ( ' ' | '\t' | '\r' | '\n') -> skip  ;
+fragment PR_E_LOGICO
+  : 'E'
+  ;
 
+fragment PR_OU_LOGICO
+  : 'OU'
+  ;
 
-fragment DIGIT_HEX    :   ('0'..'9'|'a'..'f'|'A'..'F')  ;
+// GAMBIARRA   : '.' |'á'| 'à'| 'ã'|'â'|'é'|'ê'|'í'|'ó'|'ô'|'õ'|'ú'|'ü'|'ç'|'Ä'|'À'|'Ã'|'Â'|'É'|'Ê'|'Ë'|'Ó'|'Ô'|'Õ'|'Ú'|'Ü'|'Ç'|'#'|'$'|'"'|'§'|'?'|'¹'|'²'|'³'|'£'|'¢'|'¬'|'ª'|'º'|'~'|'\''|'`'|'\\'|'@';
 
-fragment SEQ_ESC      :  '\\' ('b'|'t'|'n'|'f'|'r'|'"'|'\''|'\\')  |   ESC_UNICODE  |   ESC_OCTAL   ;
+ABRE_PAR
+  : '('
+  ;
 
-fragment ESC_OCTAL    : '\\' ('0'..'3') ('0'..'7') ('0'..'7')  |   '\\' ('0'..'7') ('0'..'7')    |   '\\' ('0'..'7')    ;
+FECHA_PAR
+  : ')'
+  ;
 
-fragment ESC_UNICODE    : '\\' 'u' DIGIT_HEX DIGIT_HEX DIGIT_HEX DIGIT_HEX  ;
+ABRE_COL
+  : '['
+  ;
 
-COMENTARIO      :   
+FECHA_COL
+  : ']'
+  ;
 
-  ('//' ~('\n'|'\r')* '\r'? '\n' |  
-  
-  '/*' .*? '*/') -> channel(HIDDEN)
- ;
+ABRE_CHA
+  : '{'
+  ;
+
+FECHA_CHA
+  : '}'
+  ;
+
+VIRGULA
+  : ','
+  ;
+
+ATRIBUICAO
+  : '='
+  ;
+
+OPERADOR_SOMA
+  : ('+'|'-')
+  ;
+
+OPERADOR_MULTIPLICATIVO
+  : ('*'|'/'|'%')
+  ;
+
+OPERADOR_E
+  : PR_E_LOGICO
+  ;
+
+OPERADOR_OU
+  : PR_OU_LOGICO
+  ;
+
+OPERADOR_RELACIONAL
+  : ('>='|'=='|'<='|'>'|'<')
+  ;
+
+DPONTOS
+  : ':'
+  ;
+
+OPERADOR_NAO
+  : PR_NAO_LOGICO
+  ;
+
+LOGICO
+  : PR_VERDADEIRO
+  | PR_FALSO
+  ;
+
+ID
+  : [a-zA-Z_] [a-zA-Z0-9_]*
+  ;
+
+// ID_BIBLIOTECA     : ID '.' ID;
+
+INTEIRO
+  : [0-9]+
+  | ('0x'|'0X')(DIGIT_HEX)+
+  | ('0b'|'0B')[0-1]+
+  ;
+
+REAL
+  : [0-9]+ '.' [0-9]+
+  ;
+
+CADEIA
+  : '"' CADEIA_CARACTER* '"'
+  ;
+    
+fragment CADEIA_CARACTER //String como definido em https://github.com/antlr/grammars-v4/blob/master/java8/Java8.g4
+  : ~["\\\r\n]
+  | SEQ_ESC
+  ;
+
+CARACTER //Caracter como definido em https://github.com/antlr/grammars-v4/blob/master/java8/Java8.g4
+  : '\'' ( SEQ_ESC | ~['\\\r\n]) '\''
+  ;
+
+ESPACO 
+  : ( ' ' | '\t') -> skip
+  ;
+
+fragment PONTO_VIRGULA
+  : ';'
+  ;
+
+EOS
+  : [\r\n]+
+  | PONTO_VIRGULA
+  ;
+
+fragment DIGIT_HEX
+  : [0-9a-fA-F]
+  ;
+
+fragment DIGIT_OCTAL
+  : [0-7]
+  ;
+
+fragment SEQ_ESC
+  : '\\' ('b'|'t'|'n'|'f'|'r'|'"'|'\''|'\\')
+  | ESC_UNICODE
+  | ESC_OCTAL
+  ;
+
+fragment ESC_OCTAL
+  : '\\' [0-3] DIGIT_OCTAL DIGIT_OCTAL
+  | '\\' DIGIT_OCTAL DIGIT_OCTAL
+  | '\\' DIGIT_OCTAL
+  ;
+
+fragment ESC_UNICODE
+  : '\\' 'u' DIGIT_HEX DIGIT_HEX DIGIT_HEX DIGIT_HEX
+  ;
+
+COMENTARIO
+  : ('//' ~('\n'|'\r')* '\r'? '\n'
+    | '/*' .*? '*/') -> channel(HIDDEN)
+  ;

+ 6 - 0
js/asa/SintaxError.js

@@ -0,0 +1,6 @@
+export class SintaxError extends Error{
+  constructor(...msg) {
+    super(...msg);
+    Error.captureStackTrace(this, SintaxError);
+  }
+}

+ 147 - 0
js/asa/analisadorSintatico.js

@@ -0,0 +1,147 @@
+import { CommonTokenStream } from 'antlr4/index';
+import { SintaxError } from './SintaxError';
+class AnalisadorSintatico {
+  constructor (lexer) {
+    this.lexer = lexer;
+    this.tokenStream = new CommonTokenStream(lexer);
+    this.tokenStream.fill();
+    this.pos = 1;
+    this.variableTypes = [this.lexer.PR_INTEIRO, this.lexer.PR_REAL, this.lexer.PR_LOGICO, this.lexer.PR_CADEIA];
+
+  }
+
+  parseTree () {
+    return {};
+  }
+
+  getToken (index=null) {
+    if(index === null)
+      index = this.pos;
+    return this.tokenStream.LT(index);
+  }
+
+  parseProgram () {
+    let token = null;
+
+    if(this.lexer.PR_PROGRAMA === (token = this.getToken()).type) {
+      try {
+        this.pos++;
+        this.consumeNewLines();
+        parseOpenCurly();
+        this.pos++;
+        this.consumeNewLines();
+        const globalVars = parseGlobalVariables();
+        this.consumeNewLines();
+        const functions = parseFunctions();
+        this.consumeNewLines();
+        parseCloseCurly();
+        this.pos++;
+        this.consumeNewLines();
+        if(this.lexer.EOF !== (token = this.getToken()).type) {
+          console.log("No extra characters are allowed after program {...}");
+        }
+        return {global: globalVars, functions: functions};
+
+      } catch(SintaxError err) {
+        console.log(err.message);
+      }
+    } else {
+      console.log(this.getErrorString(this.lexer.literalNames(this.lexer.PR_PROGRAMA), token));
+    }
+    return null;
+  }
+
+  parseOpenCurly () {
+    let token = null;
+    if(this.lexer.ABRE_CHA !== (token = this.getToken()).type){
+      throw new SintaxError(this.getErrorString('{', token));
+    }
+  }
+
+  parseCloseCurly () {
+    let token = null;
+    if(this.lexer.FECHA_CHA !== (token = this.getToken()).type){
+      throw new SintaxError(this.getErrorString('}', token));
+    }
+  }
+
+  parseGlobalVariables () {
+    let vars = [];
+    while(true) {
+      const decl = this.parseHasConst();
+      const eosToken = this.getToken();
+      if(eosToken.type !== this.lexer.EOS) {
+        throw new SintaxError('new line or \';\'', eosToken);
+      }
+      this.pos++;
+      if ( decl === null)
+        break;
+      else
+        vars.push(decl);
+    }
+    return vars;
+  }
+
+  /*
+  * Checks if the next token is PR_CONST. It's only available
+  * at global variables declaration level
+  * @returns Declararion(const, type, id, initVal?)
+  **/
+  parseHasConst () {
+    const token = this.getToken();
+    if(token.type === this.lexer.PR_CONST) {
+      this.pos++
+      return parseDeclararion(true);
+    } else if(isVariableType(token)) {
+      return parseDeclararion();
+    } else {
+      return null;
+    }
+
+  }
+
+  /*
+  * Parses a declarion of the form: type --- id --- (= --- EAnd)?
+  * @returns Declararion(const, type, id, initVal?)
+  **/
+  parseDeclararion (isConst = false) {
+    const typeToken = this.getToken();
+    if(!this.isVariableType(typeToken)) {
+      throw new SintaxError(this.variableTypes.map( x => this.lexer.literalNames[x])
+        .reduce((o, n) => {
+        if (o.length <= 0)
+          return n;
+        else
+          return o + ", " + n;
+      }, ''), typeToken);
+    }
+    this.pos++;
+    const idToken = this.getToken();
+    if(idToken.type !== this.lexer.ID) {
+      throw new SintaxError('ID', idToken);
+    }
+    this.pos++;
+    const equalsToken = this.getToken();
+    if(equalsToken.type === this.lexer.ATRIBUICAO) {
+      //process Expression
+    } else {
+      return {isConst: isConst, tipo: typeToken.text, id: idToken.text};
+    }
+  }
+
+  consumeNewLines () {
+    token = this.getToken();
+    while(token.type === this.lexer.EOS && token.text.match('[\r\n]')) {
+      this.pos++;
+      token = this.getToken();
+    }
+  }
+
+  getErrorString (symbol, token) {
+    return `Sintax error! Expecting '${symbol}' but found ${token.text} at line:${token.line}, column:${token.column}`;
+  }
+
+  isVariableType (token) {
+    return this.variableTypes.find(v => v === token.type);
+  }
+}

+ 6 - 3
js/main.js

@@ -1,7 +1,9 @@
 import { InputStream, CommonTokenStream } from 'antlr4/index';
 import Parsers from '../grammar/';
 
-const ivprogParser = Parsers['pt_br'];
+const lang = 'pt_br';
+
+const ivprogParser = Parsers[lang];
 
 const input = `programa {
   const real PI = 0x25ff
@@ -10,7 +12,8 @@ const input = `programa {
     escreva(s)
     se (a <= 5) {
       a = 10;
-    } senao se (a > 5 E a < 10) {
+    }
+    senao se (a > 5 E a < 10) {
       a = 15
     } senao {
       a = 20
@@ -22,7 +25,7 @@ const parser = new CommonTokenStream(lexer);
 parser.fill();
 let i = 1;
 let token = null;
-while((token = parser.LT(i)).type !== ivprogParser.EOF) {
+while((token = parser.LT(i)).type !== ivprogParser.EOF && token.type !== ivprogParser.ESPACO) {
   console.log(`${token.type}-${token.text}`);
   console.log('\n')
   i++;