Pergunta

Alguém poderia me dar alguns conselhos/idéias sobre como lidar com as situações em que é necessário dar uma olhada em outras declarações para poder fazer ações semânticas corretas no momento atual? Por exemplo, é uma ocorrência bem conhecida quando alguém escreve um intérprete/compilador de alguma linguagem de programação que não suporta "declarações a seguir". Vamos ter um exemplo:

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){
//...
}

É bem claro que temos que ter pelo menos dois passes. Em primeiro lugar, analisamos todas as declarações da função e obtemos todas as informações necessárias, como: o valor argumentos que a função leva, seus tipos e, em seguida, somos capazes de lidar com invocações de função e resolver as dificuldades como acima. Se formos assim, devemos fazer todos esses passes usando alguns Ast mecanismos/visitantes de travessia. Nesse caso, temos que lidar com os visitantes da AST Traversing/Aplicando e devemos dizer "adeus" a toda a beleza das construções de Phoenix integradas diretamente em nossos analistas.

Como você lidaria com isso?

Foi útil?

Solução

2ª resposta, na semântica] Este exemplo em particular é simples. O que você pode fazer é registrar chamadas de função feitas para funções ainda não declaradas e os tipos de argumento reais. Quando você encontra uma declaração de função posteriormente, verifica se há chamadas de função precedentes que são (melhores) correspondidas a essa nova função. Obviamente, você detectará erros apenas no final da análise, porque a última linha pode introduzir uma função ausente. Mas depois dessa linha, qualquer chamada de função que não tenha sido correspondida é um erro.

Agora, o problema é que isso funciona para uma semântica simples. Se você olhar para idiomas mais complexos - por exemplo, com C ++ - como função modelos - Não se torna mais possível fazer essas pesquisas em uma tabela simples. Você precisaria de guias especializadas que correspondam estruturalmente às suas construções de idiomas. Um AST simplesmente não é a melhor estrutura para isso, muito menos a AST parcial durante a análise.

Outras dicas

Se você quiser fazer dois passes, em vez de verificação semântica no final da primeira passagem, você pode ter funções de TE chamadas por suas ações sabem em que passe elas estão. Então, se você teve algumas ações

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

Eles seriam definidos algo assim (não sintaxe de espírito adequado, mas você entendeu)

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
}

Eu acho que você está fazendo suposições infundadas. Por exemplo, "é bem claro que precisamos ter pelo menos dois passes". Não, não é. Se a sintaxe for tal que foo(123) só pode ser analisado como function-name "(" expression ")", então um passe é suficiente.

Portanto, eu aconselho projetar sua sintaxe para análise inequívoca. Evite construções que não possam ser analisadas isoladamente, por exemplo, evite dependências de declarações Elese em algum lugar.

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