Pregunta

Podría alguien por favor, dame algunos consejos / ideas sobre cómo hacer frente a las situaciones en las que es necesario para echar un vistazo a otras declaraciones que ser capaz de hacer que las acciones semánticas correctas relativas al momento actual? Por ejemplo, es un hecho bien conocido cuando alguien escribe un intérprete / compilador de algún lenguaje de programación que no soporta "declaraciones prospectivas". Vamos a echar un ejemplo:

foo(123);//<-- our parser targets here. we estimate we have a function 
         //    invocation, but we have no idea about foo declaration/prototype,
         //     so we can't be sure that "foo" takes one integer argument.   


void foo(int i){
//...
}

Es bastante claro que tenemos que tener al menos dos pases. En primer lugar, todas las declaraciones de funciones de análisis sintáctico y obtener toda la información necesaria, tales como: los argumentos de la función toma cantidad, sus tipos y entonces son capaces de hacer frente a invocaciones de funciones y resolver las dificultades que el anterior. Si nos vamos de esta manera tendremos que hacer todos estos pasos usando algunos AST que atraviesan mecanismos / visitantes. En este caso tenemos que hacer frente a AST de desplazamiento / visitantes que solicitan y debemos decir "adiós" a la de toda la belleza de las construcciones phoenix integrado directamente en nuestros programas de análisis.

¿Cómo hacer frente a esto?

¿Fue útil?

Solución

[segunda respuesta, en la semántica] Este ejemplo particular pasa a ser simple. Lo que puede hacer es grabar las llamadas a funciones realizadas a las funciones todavía no declarados, y los tipos de argumentos reales. Cuando llegas a tener una declaración de la función después, se comprobará si hay precedentes llamadas a funciones que son (mejor) adaptado a esta nueva función. Obviamente va a detectar errores sólo al final del análisis sintáctico, becuase la última línea podría introducir una función que falta. Pero después de esa línea, cualquier llamada a una función que no ha sido igualado en todo es un error.

Ahora, el problema es que esto funciona para la semántica simples. Si nos fijamos en los idiomas más complejas - por ejemplo, con C ++ - función como las plantillas - ya no resulta posible hacer tales operaciones de búsqueda en una tabla sencilla. Usted tendría que tabes especializados que responden estructuralmente sus construcciones del lenguaje. Un AST no es la mejor estructura para los que, por no hablar de la AST parcial durante el análisis.

Otros consejos

Si usted quiere hacer dos pasadas, en lugar de comprobación semántica al final de la primera pasada, puede tener funciones del te llamados por sus acciones saber que pasan el que están. Así que si había algunas acciones

[functionCall(name, args)]
[functionDef(name, args, body)]

Ellos se definirían algo como esto (sintaxis no apropiado espíritu, pero usted consigue el punto)

functionCall(string name, vector<string> args)
{
  if (!first_pass) {
    // check args for validity
    // whatever else you need to do
  }
} 

functionDef(string name, vector<string> args, ... body)
{
  if (first_pass)
    // Add function decleration to symbol table
  else
    // define function
}

Creo que estás haciendo suposiciones infundadas. Por ejemplo, "es bastante claro que tenemos que tener al menos dos pases". No, no lo es. Si la sintaxis es tal que foo(123) sólo puede ser analizado como function-name "(" expression ")", a continuación, una pasada es suficiente.

Por tanto, yo le aconsejaría a diseñar su sintaxis para el análisis inequívoco. Evitar constructos que no se puede analizar de forma aislada,, por ejemplo, evitar dependendencies en las declaraciones elesewhere.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top