analisadorSintatico.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. import { CommonTokenStream } from 'antlr4/index';
  2. import { SintaxError } from './SintaxError';
  3. class AnalisadorSintatico {
  4. constructor (lexer) {
  5. this.lexer = lexer;
  6. this.tokenStream = new CommonTokenStream(lexer);
  7. this.tokenStream.fill();
  8. this.pos = 1;
  9. this.variableTypes = [this.lexer.PR_INTEIRO, this.lexer.PR_REAL, this.lexer.PR_LOGICO, this.lexer.PR_CADEIA];
  10. }
  11. parseTree () {
  12. return {};
  13. }
  14. getToken (index = null) {
  15. if(index === null)
  16. index = this.pos;
  17. return this.tokenStream.LT(index);
  18. }
  19. parseProgram () {
  20. let token = null;
  21. if(this.lexer.PR_PROGRAMA === (token = this.getToken()).type) {
  22. try {
  23. this.pos++;
  24. this.consumeNewLines();
  25. checkOpenCurly();
  26. this.pos++;
  27. this.consumeNewLines();
  28. const globalVars = parseGlobalVariables();
  29. this.consumeNewLines();
  30. const functions = parseFunctions();
  31. this.consumeNewLines();
  32. checkCloseCurly();
  33. this.pos++;
  34. this.consumeNewLines();
  35. if(this.lexer.EOF !== (token = this.getToken()).type) {
  36. console.log("No extra characters are allowed after program {...}");
  37. }
  38. return {global: globalVars, functions: functions};
  39. } catch(SintaxError err) {
  40. console.log(err.message);
  41. }
  42. } else {
  43. throw SintaxError.createError(this.lexer.literalNames(this.lexer.PR_PROGRAMA), token);
  44. }
  45. return null;
  46. }
  47. checkOpenCurly () {
  48. let token = null;
  49. if(this.lexer.ABRE_CHA !== (token = this.getToken()).type){
  50. throw SintaxError.createError(this.getErrorString('{', token));
  51. }
  52. }
  53. checkCloseCurly () {
  54. let token = null;
  55. if(this.lexer.FECHA_CHA !== (token = this.getToken()).type){
  56. throw SintaxError.createError(this.getErrorString('}', token));
  57. }
  58. }
  59. checkOpenBrace (attempt = false) {
  60. const token = this.getToken();
  61. if(this.lexer.ABRE_COL !== token.type){
  62. if (!attempt) {
  63. throw SintaxError.createError(this.getErrorString('[', token));
  64. } else {
  65. return false;
  66. }
  67. }
  68. return true;
  69. }
  70. checkCloseBrace (attempt = false) {
  71. const token = this.getToken();
  72. if(this.lexer.FECHA_COL !== token.type){
  73. if (!attempt) {
  74. throw SintaxError.createError(this.getErrorString(']', token));
  75. } else {
  76. return false;
  77. }
  78. }
  79. return true;
  80. }
  81. parseGlobalVariables () {
  82. let vars = [];
  83. while(true) {
  84. const decl = this.parseHasConst();
  85. const eosToken = this.getToken();
  86. if (eosToken.type !== this.lexer.EOS) {
  87. throw SintaxError.createError('new line or \';\'', eosToken);
  88. }
  89. this.pos++;
  90. if (decl === null)
  91. break;
  92. else
  93. vars.concat(decl);
  94. }
  95. return vars;
  96. }
  97. /*
  98. * Checks if the next token is PR_CONST. It's only available
  99. * at global variables declaration level
  100. * @returns Declararion(const, type, id, initVal?)
  101. **/
  102. parseHasConst () {
  103. const constToken = this.getToken();
  104. if(constToken.type === this.lexer.PR_CONST) {
  105. this.pos++;
  106. const typeToken = this.getToken();
  107. if(!this.isVariableType(typeToken)) {
  108. throw SintaxError.createError(this.getCommaTypeString(), typeToken);
  109. }
  110. this.pos++;;
  111. return parseDeclararion(typeToken, true);
  112. } else if(isVariableType(constToken)) {
  113. this.pos++;
  114. return parseDeclararion(constToken);
  115. } else {
  116. return null;
  117. }
  118. }
  119. /*
  120. * Parses a declarion of the form: type --- id --- (= --- EAnd)?
  121. * @returns Declararion(const, type, id, initVal?)
  122. **/
  123. parseDeclararion (typeToken, isConst = false) {
  124. const idToken = this.getToken();
  125. let initial = null;
  126. let dim1 = null;
  127. let dim2 = null;
  128. if(idToken.type !== this.lexer.ID) {
  129. throw SintaxError.createError('ID', idToken);
  130. }
  131. this.pos++;
  132. // Check for array or vector
  133. // ID[int/IDi][int/IDj]
  134. if (this.checkOpenBrace(true)) {
  135. this.pos++;
  136. dim1 = this.getArrayDimension();
  137. this.checkCloseBrace();
  138. this.pos++;
  139. if(this.checkOpenBrace(true)) {
  140. this.pos++;
  141. dim2 = this.getArrayDimension();
  142. this.checkCloseBrace();
  143. this.pos++;
  144. }
  145. }
  146. const equalsToken = this.getToken();
  147. if(equalsToken.type === this.lexer.ATRIBUICAO) {
  148. //process Expression(EAnd) => initial != null
  149. }
  150. const commaToken = this.getToken();
  151. if(commaToken.type === this.lexer.VIRGULA) {
  152. this.pos++;
  153. return [{
  154. isConst: isConst,
  155. tipo: typeToken.text,
  156. id: idToken.text,
  157. lines: dim1,
  158. columns: dim2,
  159. initial: initial
  160. }]
  161. .concat(this.parseDeclararion(typeToken, isConst));
  162. } else {
  163. return [{isConst: isConst, tipo: typeToken.text, id: idToken.text. initial: initial}];
  164. }
  165. }
  166. consumeNewLines () {
  167. token = this.getToken();
  168. while(token.type === this.lexer.EOS && token.text.match('[\r\n]')) {
  169. this.pos++;
  170. token = this.getToken();
  171. }
  172. }
  173. isVariableType (token) {
  174. return this.variableTypes.find(v => v === token.type);
  175. }
  176. /*
  177. * Reads the next token of the stream to check if it is a Integer or an ID.
  178. * @returns Integer | ID
  179. **/
  180. getArrayDimension () {
  181. const dimToken = this.getToken();
  182. if(dimToken.type !== this.lexer.PR_INTEIRO || dimToken.type !== this.lexer.ID) {
  183. throw SintaxError.createError('int or ID', dimToken);
  184. }
  185. return dimToken.text;
  186. }
  187. getCommaTypeString () {
  188. return this.variableTypes.map( x => this.lexer.literalNames[x])
  189. .reduce((o, n) => {
  190. if (o.length <= 0)
  191. return n;
  192. else
  193. return o + ", " + n;
  194. }, '');
  195. }
  196. }