Pregunta

El nuevo idioma de Google "ir" dice en su sitio web:

El lenguaje ha sido diseñado para ser fácil de analizar y se puede analizar sin una tabla de símbolos

Ciertamente no soy un experto en estos asuntos, pero pensé que una tabla de símbolos era una construcción básica común para todos los compiladores para idiomas que usan variables, y GO usa claramente variables. ¿Qué no estoy entendiendo?

¿Fue útil?

Solución

El análisis significa simplemente descubrir la estructura del programa: separar el módulo en declaraciones/declaraciones, romper expresiones a subexpresiones, etc. Termina con una estructura de árbol, conocida como un "árbol de análisis" o "árbol de sintaxis abstracta" ( Ast).

Aparentemente, C ++ requiere una tabla de símbolos para analizar.

Esta página discute algunas razones Por qué C ++ requiere una tabla de símbolos para analizar.

Por supuesto, el análisis es solo una parte de la compilación, y necesitará una tabla de símbolos para hacer una compilación completa.

Sin embargo, el análisis en sí mismo puede ser útil para escribir herramientas de análisis (por ejemplo, qué módulo importa qué módulos). Por lo tanto, simplificar el proceso de análisis significa que es más fácil escribir herramientas de análisis de código.

Otros consejos

La interpretación y la compilación requieren absolutamente tablas de símbolos o similares. Esto es cierto para casi todos los idiomas.

En C y C ++, incluso analizador El lenguaje requiere una tabla de símbolos.

@Justice tiene razón. Para expandirse un poco, en C, la única parte difícil real es reveladores aparte de las variables. Específicamente cuando ves esto:

T t;

Necesitas saber que T es un tipo para que eso sea un análisis legal. Eso es algo que tienes que buscar en una mesa de símbolos. Esto es relativamente simple de averiguar siempre que los tipos se agregan a la tabla de símbolos a medida que continúa el análisis. Tampoco necesitas hacer mucho trabajo extra en el compilador: T está presente en la tabla o no lo es.

En c ++ las cosas son mucho mucho más complicado. Hay enormes números de construcciones ambiguas o potencialmente ambiguas. Lo más obvio es este:

B::C (c);

Aparte del hecho de que no está claro si B es un class, a typedef, o un namespace, tampoco está claro si C es un tipo y c un objeto de ese tipo, o si C es una función (o constructor) tomando c Como argumento (o incluso si C es un objeto con operator() sobrecargado). Necesita la tabla de símbolos para continuar el análisis, aunque aún es posible continuar lo suficientemente rápido, ya que el tipo de símbolo está en la tabla de símbolos.

Las cosas se ponen mucho, mucho, mucho peor que eso cuando las plantillas entran en la mezcla. Si C (c) está en una plantilla, es posible que no sepa en la definición real de la plantilla, si C es un tipo o una función/objeto. Eso es porque la plantilla puede declarar C ser - estar ya sea un tipo o una variable. Lo que esto significa es que necesitas la tabla de símbolos, pero no tener uno - y tu no poder Tenga uno hasta que la plantilla se declare realmente. Peor aún, no es necesariamente suficiente tener el tipo de símbolo: puede encontrar situaciones que requieren la información completa del tipo que representa el símbolo, incluido el tamaño, la alineación y otra información específica de la máquina.

Todo esto tiene varios efectos prácticos. Los dos más significativos que diría son:

  • La compilación es mucho más rápida. Supongo que Go es más rápido para compilar que C, y C ++ tiene tiempos de compilación famosos para situaciones que involucran muchas plantillas.
  • Puede escribir analizadores que no dependan de tener un compilador completo. Esto es muy útil para hacer análisis de código y para la refactorización.

Para analizar la mayoría de los idiomas, debe saber cuándo los nombres son variables, tipos o funciones para desambiguar ciertas construcciones. Go no tiene tales construcciones ambiguas.

Por ejemplo:

int x = foo (bar);

Foo podría ser un tipo o una función y están representados por diferentes tipos de AST. Básicamente, el analizador nunca tiene que hacer búsquedas en símbolos para saber cómo construir el AST. La gramática y el AST son más simples que la mayoría de los idiomas. Realmente genial.

Las tablas de símbolos son lentas y generalmente no necesarias. Así que ve a elegir irte con eso. Otros idiomas funcionales tampoco necesitan ninguno. La búsqueda rápida requiere un hash, pero para admitir ámbitos anidados necesita impulsar/explotar los nombres en una pila. Los symtabs simples se implementan como pila de búsqueda lineal, mejores symtabs como hash con una pila por símbolo. Pero aún así, la búsqueda debe hacerse en tiempo de ejecución.

La interpretación y la compilación de los idiomas de alcance léxico no requieren absolutamente ninguna tabla de símbolos o similares. Solo los símbolos de alcance dinámico necesitan tablas de símbolos, y algunos compiladores con lenguajes estrictamente escritos necesitan algún tipo de tabla de símbolos internos para contener las anotaciones de tipo.

En C y C ++, incluso analizar el lenguaje requiere una tabla de símbolos, porque necesita almacenar los tipos y declaraciones de globales y funciones.

Los símbolos de alcance léxico no se almacenan en Symtab's, sino como una lista indexada de nombres en marcos de bloque, como en los idiomas funcionales. Esos índices se calculan en tiempo de compilación. Entonces el acceso al tiempo de ejecución es inmediato. Dejar el alcance hace que esos VARS sean inaccesibles automáticamente, por lo que no necesita presionar/explotar los nombres de los espacios de nombres/Symtabs.

Los lenguajes no funcionales sin funciones de primera clase a menudo necesitan almacenar sus nombres de funciones en tablas de símbolos. Como diseñador de idiomas, intenta vincular las funciones a los lexicales, para poder deshacerse de la búsqueda de nombres dinámicos en SymTabs.

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