2009-07-23 7 views
8

G'day!¿Cómo puedo construir una gramática limpia similar a Python en ANTLR?

¿Cómo puedo construir una gramática ANTLR simple que maneje expresiones de varias líneas sin la necesidad de punto y coma o barras diagonales inversas?

estoy tratando de escribir un simple DSL para las expresiones:

# sh style comments 
ThisValue = 1 
ThatValue = ThisValue * 2 
ThisOtherValue = (1 + 2 + ThisValue * ThatValue) 
YetAnotherValue = MAX(ThisOtherValue, ThatValue) 

En general, yo quiero que mi aplicación para proporcionar el guión con unos valores iniciales nombre y sacar el resultado final. Sin embargo, estoy colgado de la sintaxis. Me gustaría dar soporte a múltiples expresiones línea como la siguiente:

# Note: no backslashes required to continue expression, as we're in brackets 
# Note: no semicolon required at end of expression, either 
ThisValueWithAReallyLongName = (ThisOtherValueWithASimilarlyLongName 
           +AnotherValueWithAGratuitouslyLongName) 

Me comenzó con una gramática antlr así:

exprlist 
    : (assignment_statement | empty_line)* EOF! 
    ; 
assignment_statement 
    : assignment NL!? 
    ; 
empty_line 
    : NL; 
assignment 
    : ID '=' expr 
    ; 

// ... and so on 

Parece sencillo, pero ya estoy en problemas con la saltos de línea:

warning(200): StackOverflowQuestion.g:11:20: Decision can match input such as "NL" using multiple alternatives: 1, 2 
As a result, alternative(s) 2 were disabled for that input 

Gráficamente, en org.antlr.works.IDE:

Decision Can Match NL Using Multiple Alternatives http://img.skitch.com/20090723-ghpss46833si9f9ebk48x28b82.png

me he pateado la gramática alrededor, pero siempre termino con violaciónes de comportamiento esperado:

  • Una nueva línea no es necesario en el final del archivo
  • líneas vacías son aceptables
  • Todo en una línea desde un signo de libra en adelante se descarta como un comentario
  • Las asignaciones finalizan con el final de línea, no en puntos y comas
  • Las expresiones pueden abarcar varias líneas si se envuelven en línea ets

Puedo encontrar ejemplos de gramáticas ANTLR con muchas de estas características. Me parece que cuando los corto para limitar su expresividad a lo que necesito, termino rompiendo algo. Otros son demasiado simples, y los rompo cuando agrego expresividad.

¿Qué ángulo debo tomar con esta gramática? ¿Puedes señalar algún ejemplo que no sea trivial o completo en Turing-complete languages?

Respuesta

6

que iba a dejar su tokenizer haga el trabajo pesado en lugar de mezclar sus reglas de nueva línea en su gramática:

  • Count paréntesis, corchetes y llaves, y no generan fichas NL mientras que hay grupos sin cerrar . Eso te dará líneas continuas gratis sin que tu gramática sea más sabia.

  • Genere siempre una ficha NL al final del archivo ya sea que la última línea termine o no con un carácter '\n', entonces no tiene que preocuparse por un caso especial de una declaración sin una NL. Las declaraciones siempre terminan con una NL.

El segundo punto dejaría a simplificar su gramática a algo como esto:

exprlist 
    : (assignment_statement | empty_line)* EOF! 
    ; 
assignment_statement 
    : assignment NL 
    ; 
empty_line 
    : NL 
    ; 
assignment 
    : ID '=' expr 
    ; 
+0

ahora tengo que encontrar la manera de obtener el tokenizer hacer que el levantamiento pesado. De regreso a la documentación, supongo. :) –

+0

John, todavía me elude. ¿Cuál es la sintaxis gramatical de ANTLR para que el tokenizer inserte NL antes de EOF? –

+0

1 Para terminando siempre en una nueva línea, hace las cosas mucho más limpio. Gracias. – Craz

0

¿Qué tal esto?

exprlist 
    : (expr)? (NL+ expr)* NL!? EOF! 
    ; 
expr 
    : assignment | ... 
    ; 
assignment 
    : ID '=' expr 
    ; 
0

supongo que eligió para que NL opcional, ya que la última sentencia en el código de entrada no tiene que terminar en una línea.

pesar de que tiene mucho sentido, se están haciendo la vida mucho más difícil para su analizador. Los tokens separadores (como NL) deben ser apreciados, ya que eliminan la ambigüedad y reducen la posibilidad de conflictos.

En su caso, el analizador no se sabe si se debe analizar la "asignación NL" o "empty_line cesión". Hay muchas maneras de resolverlo, pero la mayoría de ellos son simplemente ataduras de banda para una elección de diseño imprudente.

Mi recomendación es un truco inocente: Hacer obligatoria NL, NL y siempre anexar al final de su flujo de entrada!

Puede parecer un poco desagradable, pero en realidad le ahorrará un montón de dolores de cabeza futuros.

Cuestiones relacionadas