Token devuelve valores en ANTLR 3 C

Soy nuevo en ANTLR, y estoy intentando escribir un analizador simple usando el objective de lenguaje C (antler3C). La gramática es tan simple que me gustaría que cada regla devuelva un valor, por ejemplo:

number returns [long value] : ( INT {$value = $INT.ivalue;} | HEX {$value = $HEX.hvalue;} ) ; HEX returns [long hvalue] : '0' 'x' ('0'..'9'|'a'..'f'|'A'..'F')+ {$hvalue = strtol((char*)$text->chars,NULL,16);} ; INT returns [long ivalue] : '0'..'9'+ {$ivalue = strtol((char*)$text->chars,NULL,10);} ; 

Cada regla recostack el valor de retorno de sus reglas secundarias hasta que la regla superior devuelve una estructura agradable llena de mis datos.

Por lo que puedo decir, ANTLR permite que las reglas del lexer (tokens, por ejemplo, ‘INT’ y ‘HEX’) devuelvan valores al igual que las reglas del analizador (por ejemplo, ‘número’). Sin embargo, el código C generado no se comstackrá:

 error C2228: left of '.ivalue' must have class/struct/union error C2228: left of '.hvalue' must have class/struct/union 

Hice algunos hurones y los errores tienen sentido: los tokens terminan como ANTLR3_COMMON_TOKEN_struct generics, lo que no permite un valor de retorno. Así que tal vez el objective C simplemente no es compatible con esta función. Pero como dije, soy nuevo en esto, y antes de ir a buscar otro enfoque, quiero confirmar que no puedo hacerlo de esta manera.

Entonces la pregunta es esta: ‘¿Antler3C admite valores de retorno para las reglas de lexer, y si es así, ¿cuál es la forma correcta de usarlos?’

Realmente no es información nueva, solo algunos detalles sobre lo que @bemace ya mencionó.

No, las reglas de lexer no pueden tener valores de retorno. Ver 4.3 Reglas de la referencia definitiva de ANTLR :


Argumentos de la regla y valores de retorno

Al igual que las llamadas a funciones, las reglas del analizador ANTLR y del analizador de árbol pueden tener argumentos y valores de retorno. Las reglas del lexer de ANTLR no pueden tener valores de retorno […]


Hay dos opciones:

Opción 1

Puede hacer la transformación a un long en el number regla del analizador:

 number returns [long value] : INT {$value = Long.parseLong($INT.text);} | HEX {$value = Long.parseLong($HEX.text.substring(2), 16);} ; 

opcion 2

O cree su propio token que tenga, digamos, un toLong(): long :

 import org.antlr.runtime.*; public class YourToken extends CommonToken { public YourToken(CharStream input, int type, int channel, int start, int stop) { super(input, type, channel, start, stop); } // your custom method public long toLong() { String text = super.getText(); int radix = text.startsWith("0x") ? 16 : 10; if(radix == 16) text = text.substring(2); return Long.parseLong(text, radix); } } 

y defina en las options {...} encabezado en su gramática para usar este token y anular el método emit emit(): Token en su clase lexer:

 grammar Foo; options{ TokenLabelType=YourToken; } @lexer::members { public Token emit() { YourToken t = new YourToken(input, state.type, state.channel, state.tokenStartCharIndex, getCharIndex()-1); t.setLine(state.tokenStartLine); t.setText(state.text); t.setCharPositionInLine(state.tokenStartCharPositionInLine); emit(t); return t; } } parse : number {System.out.println("parsed: "+$number.value);} EOF ; number returns [long value] : INT {$value = $INT.toLong();} | HEX {$value = $HEX.toLong();} ; HEX : '0' 'x' ('0'..'9'|'a'..'f'|'A'..'F')+ ; INT : '0'..'9'+ ; 

Cuando genera un analizador y un lexer, y ejecuta esta clase de prueba:

 import org.antlr.runtime.*; import java.io.*; public class Main { public static void main(String[] args) throws Exception { ANTLRStringStream in = new ANTLRStringStream("0xCafE"); FooLexer lexer = new FooLexer(in); CommonTokenStream tokens = new CommonTokenStream(lexer); FooParser parser = new FooParser(tokens); parser.parse(); } } 

producirá la siguiente salida:

 parsed: 51966 

Las primeras opciones parecen las más prácticas en su caso.

Tenga en cuenta que, como puede ver, los ejemplos dados están en Java. No tengo idea si la opción 2 es compatible con C target / runtime. Decidí seguir publicándolo para poder usarlo como futura referencia aquí en SO.

Las reglas de Lexer deben devolver objetos Token, porque eso es con lo que el analizador espera trabajar. Puede haber una manera de personalizar el tipo de objeto de token utilizado, pero es más fácil simplemente convertir tokens a valores en las reglas del analizador de nivel más bajo.

 social_title returns [Name.Title title] : SIR { title = Name.Title.SIR; } | 'Dame' { title = Name.Title.DAME; } | MR { title = Name.Title.MR; } | MS { title = Name.Title.MS; } | 'Miss' { title = Name.Title.MISS; } | MRS { title = Name.Title.MRS; }; 

Hay una tercera opción: puede pasar un objeto como argumento a la regla de lexer. Este objeto contiene un miembro que representa el valor de retorno del lexer. Dentro de la regla de lexer, puede establecer el miembro. Fuera de la regla de lexer, en el punto en que lo llame, puede obtener el miembro y hacer lo que quiera con este “valor de retorno”. Esta forma de pasar parámetros corresponde a los parámetros ‘var’ en Pascal o los parámetros ‘out’ en C ++ y otros lenguajes de progtwigción.

    Intereting Posts