Pergunta

Eu estou tentando usar bisonte flex e para criar um filtro, porque eu quero ficar certos elementos da gramática de uma linguagem complexa. Meu plano é usar Flex + bisonte reconhecer a gramática, e despejar a localização de elementos de interesse. (Em seguida, use um script para texto grab acordo com os locais despejado.)

Eu encontrei flexível pode suportar um recurso bisonte chamado bisonte-locais, mas como ele funciona exatamente. Eu tentei o exemplo no documento flexível, parece que o yylloc não é definida automaticamente pelo Flex, eu sempre chegar (1,0)-(1,0). Poderia flexionar calcular a localização de cada token automaticamente? Se não, qual função de interface é definida por mim para implementar? Existe algum exemplo?

Qualquer solução melhor em relação às ferramentas?

Atenciosamente, Kevin

Editar:

Agora, a interface para turn yylex a:

int yylex(YYSTYPE * yylval_param,YYLTYPE * yylloc_param );

manual do bisonte não especifica como lexer deve implementar para corretamente conjunto yylloc_param. Para mim é difícil de número de coluna trace manualmente de cada token.

Foi útil?

Solução

Dê uma olhada na seção 3.6 do o Bison Manual - que parece cobrir locais em algum detalhe. Combinado com o que você encontra no manual do Flex, que poderá ser suficiente.

Outras dicas

A declaração yylex provavelmente mudou porque você usou uma reentrada ou puro-parser. Parece que muitos documentos em toda a web sugerem que é necessário se você quiser locais bisonte para trabalhar, mas isso não é obrigatório.

Eu precisava de números de linha também e encontrou a documentação Bison confundir a esse respeito. A solução mais simples (usando o var yylloc global): Em seu arquivo Bison basta adicionar as localizações% directiva:

%{
...
%}
%locations
...
%%
...

no seu lexer:

%{
...
#include "yourprser.tab.h"  /* This is where it gets the definition for yylloc from */
#define YY_USER_ACTION yylloc.first_line = yylloc.last_line = yylineno;
%}
%option yylineno
...
%%
...

A macro YY_USER_ACTION é "chamado" antes de cada uma de suas ações simbólicas e yylloc atualizações. Agora você pode usar o @N / @ $ regras como esta:

statement : error ';'   { fprintf(stderr, "Line %d: Bad statement.\n", @1.first_line); }

, ou utilize o yylloc var mundial:

void yyerror(char *s)
{
  fprintf(stderr, "ERROR line %d: %s\n", yylloc.first_line, s);
}

Eu gosto de resposta de Shlomi.

Além disso, eu estava olhando para atualizar localização coluna também. Encontrado http://oreilly.com/linux/excerpts/9780596155971/error- reporte-recovery.html que fazia mais sentido depois de ler a resposta de Shlomi.

Infelizmente não há um erro de digitação na página para yylloc. Eu simplificado-lo abaixo um pouco.

Em seu analisador add:

%locations

no seu lexer:

%{

#include "parser.tab.h"

int yycolumn = 1;

#define YY_USER_ACTION yylloc.first_line = yylloc.last_line = yylineno; \
    yylloc.first_column = yycolumn; yylloc.last_column = yycolumn + yyleng - 1; \
    yycolumn += yyleng; \
    yylval.str = strdup(yytext);

%}

%option yylineno

Pode haver algo acontecendo com localização coluna que não mantém estritamente o controle de colunas mas apenas continua aumentando. Isso é apenas a minha ignorância e appologize se confunde ninguém. Atualmente estou usando coluna para manter a contagem de caracteres arquivo que no meu caso é mais benéfico do que a localização da coluna.

Espero que ajude.

Nem bison nem flex atualizações yylloc automaticamente, mas é, na verdade, não é difícil de fazê-lo sozinho, se você sabe o truque.

O truque para implementar o suporte yylloc é que, embora yyparse() declara yylloc, nunca muda. Isso significa que se você modificar yylloc em uma chamada para o lexer, você encontrará os mesmos valores em que na próxima chamada. Assim, yylloc conterá a posição do último token. Desde o final do último token é o mesmo que o atual token começar, você pode usar o valor yylloc de idade para ajudar a determinar o novo valor.

Em outras palavras, yylex() não deve calcular yylloc; deveria Atualização yylloc.

Para atualizar yylloc, é preciso primeiro copiar os valores last_ para first_, e depois atualizar os valores last_ para refletir a duração do token just-correspondido. (Este não é o strlen() do token, é o comprimento linhas-e-colunas.) Podemos fazer isso na macro YY_USER_ACTION, que é chamado pouco antes é realizada qualquer ação lexer; que garante que, se um jogos de regras, mas ele não retorna um valor (por exemplo, uma regra ignorar espaços em branco ou comentários), a localização do que é não-simbólicos ignorados, em vez de ser incluído no início do token real, ou perdido em uma maneira que faz o rastreamento de localização imprecisa.

Aqui está uma versão significou para um analisador de reentrada; você pode modificá-lo para um analisador não reentrante trocando os operadores -> para .:

#define YY_USER_ACTION \
    yylloc->first_line = yylloc->last_line; \
    yylloc->first_column = yylloc->last_column; \
    for(int i = 0; yytext[i] != '\0'; i++) { \
        if(yytext[i] == '\n') { \
            yylloc->last_line++; \
            yylloc->last_column = 0; \
        } \
        else { \
            yylloc->last_column++; \
        } \
    }

Se você preferir, você poderia, em vez colocar esse código em uma função e fazer a chamada macro a função, mas as duas técnicas são equivalentes.

A resposta de Shomi é a solução mais simples se você só se preocupam com mantendo o número da linha. No entanto, se você também quiser números de coluna, então você precisa manter o controle deles.

Uma maneira de fazer isso é adicionar regras yycolumn = 1 em todos os lugares uma nova linha aparece (como sugerido na resposta de David Elson), mas se você não quiser manter o controle de todos os lugares uma nova linha poderia mostrar-se (espaços em branco, comentários, etc. ..) uma alternativa está a inspeccionar o tampão yytext no início de cada acção:

static void update_loc(){
  static int curr_line = 1;
  static int curr_col  = 1;

  yylloc.first_line   = curr_line;
  yylloc.first_column = curr_col;

  {char * s; for(s = yytext; *s != '\0'; s++){
    if(*s == '\n'){
      curr_line++;
      curr_col = 1;
    }else{
      curr_col++;
    }
  }}

  yylloc.last_line   = curr_line;
  yylloc.last_column = curr_col-1;
}

#define YY_USER_ACTION update_loc();

Finalmente, uma coisa a notar é que quando você começar a manter o controle de números de coluna com a mão assim como você pode também acompanhar os números de linha no mesmo lugar e não se preocupar com o uso de opção yylineno do Flex.

Então, eu tenho essa a "trabalhar", mas com um par de medidas adicionais (I pode ter negligenciado-los aqui ... desculpas nesse caso):

  1. Em parser.y , eu tinha a dizer:

    #define YYLEX_PARAM &yylval, &yylloc
    

    mesmo com %locations e bison --locations, para obtê-lo para passar os dados.

  2. Em lexer.l eu tive que usar -> vez de . para yylloc

  3. Também em lexer.l , eu redefinir a coluna na ação:

    [\n] { yycolumn = 1; }
    

Obviamente um pouco mais complexa, por \r etc, mas pelo menos eu tenho que trabalhar.

Eu acho que eu consegui fazê-lo funcionar (crédito vai para o escritor do manual bisonte ltcalc lexical analisador ). Por padrão, bisontes cria yylloc que contém

{ first_line, first_column , last_line , last_column }

Nós só precisa atualizar esses valores em nossa analisador léxico. Ex:

[ \t]     { ++yylloc.last_column; }
[\n]      { yyloc.last_column = 0; return EOL; }
[a-zA-Z]+ { 
            yylloc.last_column += strlen(yytext);
            return IDENTIFIER;
          }

Agora, bisonte, para recuperar esses campos:

statement : IDENTIFIER '=' expression 
            { printf("%d - %d\n", @1.last_line, @1.last_column); }

Por padrão, esses campos são inicializados para um, devemos inicializar os campos da coluna para zero caso contrário eles vão relatar a coluna errada.

Uma adição à resposta de Shlomi:

Se você estiver usando% definir api.pure em bisões para criar um analisador de reentrada, você também precisa especificar a opção% bisonte-locais em flex. Isto porque, em um yylloc analisador de reentrada não é uma variável global, e precisa de ser passado para o lexer.

Assim, no analisador:

%define api.pure
%locations

no lexer:

#include "yourprser.tab.h"
#define YY_USER_ACTION yylloc.first_line = yylloc.last_line = yylineno;
%option bison-locations
%option yylineno
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top