Comment flex supporte-t-il bison-location exactement?

j'essaie d'utiliser flex et bison pour créer un filtre, parce que je veux obtenir certains éléments de grammaire à partir d'un langage complexe. Mon plan est d'utiliser flex + bison pour reconnaître la grammaire, et vider l'emplacement des éléments d'intérêt. (Puis utilisez un script pour saisir le texte en fonction des emplacements vidés.)

j'ai trouvé que flex peut supporter une caractéristique de bison appelée bison-localisations, mais comment cela fonctionne exactement. J'ai essayé l'exemple dans le document flex, il semble que le yylloc n'est pas défini automatiquement par flex, je reçois toujours (1,0)-(1,0). Flex pourrait-il calculer automatiquement l'emplacement de chaque token? Si ce n'est pas le cas, quelle fonction d'interface est définie pour que je puisse l'implémenter? Est-il un exemple?

meilleure solution en ce qui concerne les outils?

Meilleures Salutations, Kevin

Edit:

Maintenant, l'interface pour yylex tourner:

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

le manuel bison ne spécifie pas comment lexer devrait implémenter pour définir correctement yylloc_param. Pour me il est difficile de tracer manuellement le numéro de colonne de chaque token.

18
demandé sur James 2009-03-18 04:49:15

8 réponses

jetez un coup d'oeil à la section 3.6 du Bison manuel - cela semble couvrir les emplacements en détail. Combiné avec ce que vous avez trouvé dans le manuel Flex, cela peut être suffisant.

6
répondu Jonathan Leffler 2014-03-02 18:48:48

la déclaration yylex a probablement changé parce que vous avez utilisé un rentrant ou un pur-parser. Il semble que de nombreux documents sur le web suggèrent qu'il est nécessaire si vous voulez que l'emplacement des bisons fonctionne, mais ce n'est pas nécessaire.

j'avais aussi besoin de numéros de ligne et j'ai trouvé la documentation sur les bisons confuse à cet égard. La solution simple (en utilisant le var global yylloc): Dans votre fichier Bison il suffit d'ajouter la directive %locations:

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

dans votre 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
...
%%
...

le La macro yy_user_action est" appelée " avant chacune de vos actions et mises à jour yylloc. Maintenant vous pouvez utiliser les règles @n/@$ comme ceci:

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

, ou utilisez le yylloc global var:

void yyerror(char *s)
{
  fprintf(stderr, "ERROR line %d: %s\n", yylloc.first_line, s);
}
16
répondu Shlomi Loubaton 2011-04-27 23:18:10

de plus, je cherchais aussi à mettre à jour l'emplacement des colonnes. Found http://oreilly.com/linux/excerpts/9780596155971/error-reporting-recovery.html ce qui avait plus de sens après avoir lu la réponse de Shlomi.

malheureusement il y a une faute de frappe sur cette page pour yylloc. J'ai simplifié ci-dessous un peu.

%locations

dans votre 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

Il y a peut être quelque chose se passe avec l'emplacement de colonne qui ne garde pas strictement la trace des colonnes mais plutôt continue d'augmenter. C'est juste mon ignorance et mon apologisation si ça confond quelqu'un. Je suis en train d'utiliser la colonne pour garder un nombre de caractères de dossier qui dans mon cas est plus bénéfique que l'emplacement de colonne.

J'espère que ça aidera.

11
répondu ekeyser 2011-11-06 02:30:50

ni L'un ni l'autre bison ni flex mises à jour yylloc automatiquement, mais il n'est en fait pas difficile de le faire vous-même-si vous connaissez le truc.

L'astuce pour la mise en œuvre de yylloc support est que, même si yyparse() déclare yylloc, il ne change jamais. Cela signifie que si vous modifiez yylloc dans un appel à l'analyseur lexical, vous trouverez les mêmes valeurs, à l'appel suivant. Ainsi,yylloc contient la position du dernier jeton. Puisque la fin du dernier token est la même que le mot de démarrer, vous pouvez utiliser la vieille yylloc valeur pour vous aider à déterminer la nouvelle valeur.

En d'autres termes, yylex() ne devrait pas calculeryylloc; il doit mise à jouryylloc.

à mettre à jour yylloc, il faut d'abord copier le last_ valeurs first_, puis mettre à jour le last_ valeurs pour refléter la longueur du jeton juste-assorti. (Ce n'est pas le strlen() du jeton; c'est la longueur des lignes et des colonnes.) Nous pouvez le faire dans le YY_USER_ACTION macro, qui est appelée juste avant que n'importe quelle action de lexer soit exécutée; cela garantit que si une règle correspond mais qu'elle ne renvoie pas de valeur (par exemple, une règle sautant un espace blanc ou des commentaires), l'emplacement de ce non-jeton est sauté, plutôt que d'être inclus au début du jeton réel, ou perdu d'une manière qui rend le suivi d'emplacement inexact.

Voici une version destinée à un analyseur de rentrant; vous pouvez la modifier pour un non-rentrant analyseur par le remplacement de l' -> les opérateurs .:

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

si vous préférez, vous pouvez à la place mettre ce code dans une fonction et faire en sorte que la macro appelle la fonction, mais les deux techniques sont équivalentes.

11
répondu Brent Royal-Gordon 2014-12-13 07:42:40

la réponse de Shomi est la solution la plus simple si vous vous souciez seulement de garder le numéro de ligne. Cependant, si vous voulez aussi des numéros de colonne, vous devez en tenir compte.

Une façon de le faire est d'ajouter yycolumn = 1 règle partout où une nouvelle ligne apparaît (comme suggéré dans la réponse de David Elson) mais si vous voulez garder une trace de tous les endroits où une nouvelle ligne pourrait apparaître (espace blanc, commentaires, etc...) une alternative est d'inspecter le yytext tampon au début de chaque action:

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 != ''; 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();

enfin, une chose à noter est qu'une fois que vous commencez à garder la trace des numéros de colonne à la main, vous pourriez aussi bien garder la trace des numéros de ligne au même endroit et ne pas prendre la peine d'utiliser Flex's yylineno option.

6
répondu hugomg 2013-10-03 00:58:19

Donc, j'ai eu ce "travail", mais avec quelques étapes supplémentaires (j'ai peut-être négligé ici ... toutes mes excuses dans ce cas):

  1. analyseur.y, que j'avais à dire:

    #define YYLEX_PARAM &yylval, &yylloc
    

    même %locations et bison --locations, pour faire passer les données.

  2. lexer.l j'ai eu à utiliser -> au lieu de .yylloc

  3. également en lexer.l, j'ai réinitialisé la colonne dans l'action:

    [\n] { yycolumn = 1; }
    

Évidemment un peu plus complexe, pour \r etc, mais au moins je l'ai eu à travailler.

4
répondu David Elson 2012-06-01 23:46:09

je pense que j'ai réussi à le faire fonctionner ( le crédit va à l'écrivain de bison manuel analyseur lexical ltcalc). Par défaut, bison crée yylloc qui contient

{ first_line, first_column , last_line , last_column }

Nous avons seulement besoin de mettre à jour ces valeurs dans notre analyseur lexical. Ex:

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

maintenant dans bison, pour récupérer ces champs:

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

par défaut ces champs sont initialisés à un, nous devrions initialiser les champs de la colonne à zéro sinon ils signaleront le mauvais colonne.

1
répondu Baroudi Safwen 2016-12-06 14:43:54

un ajout à la réponse de Shlomi:

si vous utilisez l'api %define.pur dans bison pour créer un parser de rentrée, vous devez également spécifier %option bison-emplacements dans flex. C'est parce que dans un réentrant analyseur yylloc n'est pas une variable globale, et doit être transmis dans l'analyseur lexical.

Donc, dans l'analyseur:

%define api.pure
%locations

dans le lexer:

#include "yourprser.tab.h"
#define YY_USER_ACTION yylloc.first_line = yylloc.last_line = yylineno;
%option bison-locations
%option yylineno
0
répondu King Kedama 2015-11-09 16:27:17