Pergunta

A nova linguagem do Google, "Go", diz em seu site:

a linguagem foi projetada para ser fácil de analisar e pode ser analisada sem uma tabela de símbolos

Certamente não sou especialista nesses assuntos, mas pensei que uma tabela de símbolos fosse uma construção básica comum a todos os compiladores de linguagens que usam variáveis, e Go claramente usa variáveis.O que não estou entendendo?

Foi útil?

Solução

Analisar significa apenas descobrir a estrutura do programa:separar o módulo em instruções/declarações, dividir expressões em subexpressões, etc.Você acaba com uma estrutura em árvore, conhecida como "árvore de análise" ou "árvore de sintaxe abstrata" (AST).

Aparentemente, C++ requer uma tabela de símbolos para fazer a análise.

Esta página discute alguns motivos por que C++ requer uma tabela de símbolos para análise.

É claro que a análise é apenas uma parte da compilação e você precisará de uma tabela de símbolos para fazer uma compilação completa.

No entanto, a análise em si pode ser útil na escrita de ferramentas de análise (por exemplo,qual módulo importa quais módulos).Portanto, simplificar o processo de análise significa que é mais fácil escrever ferramentas de análise de código.

Outras dicas

A interpretação e a compilação requerem absolutamente tabelas de símbolos ou similares.Isso é verdade para quase todos os idiomas.

Em C e C++, mesmo análise a linguagem requer uma tabela de símbolos.

@Justiça está certa.Para expandir um pouco isso, em C a única parte realmente complicada é diferenciar os tipos das variáveis.Especificamente quando você vê isto:

T t;

Você precisa saber disso T é um tipo para que seja uma análise legal.Isso é algo que você deve procurar em uma tabela de símbolos.Isso é relativamente simples de descobrir, desde que os tipos sejam adicionados à tabela de símbolos à medida que a análise continua.Você não precisa fazer muito trabalho extra no compilador:qualquer T está presente na tabela ou não.

Em C++ as coisas são muitas, muito mais complicado.Há um enorme número de construções ambíguas ou potencialmente ambíguas.O mais óbvio é este:

B::C (c);

Além do fato de que não está claro se B é um class, a typedef, ou um namespace, também não está claro se C é um tipo e c um objeto desse tipo, ou se C é uma função (ou construtor) que toma c como argumento (ou mesmo se C for um objeto com operator() sobrecarregado).Você precisa da tabela de símbolos para continuar a análise, embora ainda seja possível continuar com rapidez suficiente, pois o tipo do símbolo está na tabela de símbolos.

As coisas ficam muito, muito, muito piores do que isso quando os modelos entram na mistura.Se C (c) está em um modelo, talvez você não saiba na definição real do modelo se C é um tipo ou uma função/objeto.Isso porque o modelo pode declarar C ser um tipo ou uma variável.O que isto significa é que você precisa da tabela de símbolos, mas não ter um - e você não pode tenha um até que o modelo seja realmente declarado.Pior ainda, não é necessariamente suficiente ter apenas o tipo do símbolo:você pode criar situações que exijam informações completas do tipo que o símbolo representa, incluindo tamanho, alinhamento e outras informações específicas da máquina.

Tudo isto tem vários efeitos práticos.Os dois mais significativos que eu diria são:

  • A compilação é muito mais rápida.Presumo que Go seja mais rápido de compilar que C, e C++ tem tempos de compilação notoriamente lentos para situações que envolvem muitos modelos.
  • Você pode escrever analisadores que não dependam de um compilador completo.Isso é muito útil para fazer análise de código e refatoração.

Para analisar a maioria das linguagens você precisa saber quando os nomes são variáveis, tipos ou funções para desambiguar certas construções.Go não tem construções tão ambíguas.

Por exemplo:

int x = Foo(barra);

Foo pode ser um tipo ou uma função e são representados por diferentes tipos AST.Basicamente, o analisador nunca precisa pesquisar símbolos para saber como construir o AST.A gramática e o AST são mais simples que a maioria dos idiomas.Muito legal, realmente.

As tabelas de símbolos são lentas e geralmente desnecessárias.Então escolha ir embora com isso.Outras linguagens funcionais também não precisam de nenhuma.A pesquisa rápida requer um hash, mas para oferecer suporte a escopos aninhados, você precisa enviar/colocar nomes em uma pilha.Symtabs simples são implementados como pilha linear pesquisada, melhores symtabs como hash com uma pilha por símbolo.Mesmo assim, a pesquisa deve ser feita em tempo de execução.

A interpretação e compilação para linguagens com escopo lexical não requerem absolutamente nenhuma tabela de símbolos ou similar.Somente símbolos com escopo dinamicamente precisam de tabelas de símbolos, e alguns compiladores com idiomas estritamente digitados precisam de algum tipo de tabela de símbolos internos para manter as anotações do tipo.

Em C e C++, até mesmo a análise da linguagem requer uma tabela de símbolos, porque você precisa armazenar os tipos e declarações de globais e funções.

Símbolos com escopo lexical não são armazenados em symtab, mas como listas indexadas de nomes em quadros de bloco, como em linguagens funcionais.Esses índices são calculados em tempo de compilação.Portanto, o acesso em tempo de execução é imediato.Sair do escopo torna esses vars inacessíveis automaticamente, então você não precisa enviar/retirar nomes de namespaces/symtabs.

Linguagens não tão funcionais sem funções de primeira classe geralmente precisam armazenar seus nomes de funções em tabelas de símbolos.Como designer de linguagem, você tenta vincular funções a léxicos, para poder se livrar da pesquisa dinâmica de nomes em symtabs.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top