Versión Regular
Creación del Parser
Esta segunda solución aprovechará el código opcional que genera automáticamente VGen, el cual añade automáticamente la información de línea y columna a los nodos.
Para ello, hay que cambiar la forma en la que se pasan algunos argumentos a los constructores de los nodos. Cuando se vaya a pasar un terminal, en vez de pasar $TOKEN.text
(sólo el lexema), se pasará el propio $TOKEN
(el token entero). De esta forma, el nodo tendrá la información de la posición en el fichero.
Por ejemplo, donde antes aparecía varDefinition como:
varDefinition ...
: type IDENT ';' { $ast = new VarDefinition($type.ast, $IDENT.text); }
Ahora se haría de la siguiente manera:
varDefinition ...
: type IDENT ';' { $ast = new VarDefinition($type.ast, $IDENT); }
Haciendo este cambio en todas las reglas necesarias, se obtendría la nueva versión de la gramática en la que las líneas resaltadas destacan dónde se ha eliminado el .text
.
program returns[Program ast]
: 'DATA' varDefinitions 'CODE' statements EOF { $ast = new Program($varDefinitions.list, $statements.list); }
;
varDefinitions returns[List<VarDefinition> list = new ArrayList<VarDefinition>()]
: (varDefinition { $list.add($varDefinition.ast); })*
;
statements returns[List<Statement> list = new ArrayList<Statement>()]
: (statement { $list.add($statement.ast); })*
;
varDefinition returns[VarDefinition ast]
: type IDENT ';' { $ast = new VarDefinition($type.ast, $IDENT); }
;
type returns[Type ast]
: 'int' { $ast = new IntType(); }
| 'float' { $ast = new FloatType(); }
;
statement returns[Statement ast]
: 'print' expression ';' { $ast = new Print($expression.ast); }
| left=expression '=' right=expression ';' { $ast = new Assignment($left.ast, $right.ast); }
;
expression returns[Expression ast]
: left=expression op=('*' | '/') right=expression { $ast = new Arithmetic($left.ast, $op, $right.ast); }
| left=expression op=('+' | '-') right=expression { $ast = new Arithmetic($left.ast, $op, $right.ast); }
| '(' expression ')' { $ast = $expression.ast; }
| IDENT { $ast = new Variable($IDENT); }
| INT_LITERAL { $ast = new IntLiteral($INT_LITERAL); }
| FLOAT_LITERAL { $ast = new FloatLiteral($FLOAT_LITERAL); }
;
Esto no solo hace que los nodos terminales tengan la posición del fichero, sino que VGen hace que los nodos intermedios también obtengan sus posiciones a partir de sus hijos, quedando así todos los nodos con esta información.
Ejecución
Si ahora se vuelve a usar antlr.bat
y se ejecuta el programa, se obtiene la nueva versión del árbol con las posiciones del fichero:
En la columna central, entre corchetes, puede verse la posición inicial y final de cada nodo. Y, en cada posición, se ve la línea y columna separadas por dos puntos. A la derecha de las posiciones se muestra además, resaltado en verde, el texto contenido entre dichas posiciones del fichero.
Debido a que se consigue más funcionalidad y, además, escribiendo menos, se recomienda esta versión en vez de la versión básica.