2010-04-23 2 views
3

Я экспериментирую с lex и yacc и столкнулся с странной проблемой, но я думаю, что лучше всего показать вам мой код, прежде чем подробно рассказывать об этой проблеме. Это мой лексер:Непреднамеренная конкатенация в грамматике Bison/Yacc

%{ 
#include <stdlib.h> 
#include <string.h> 
#include "y.tab.h" 
void yyerror(char *); 
%} 

%% 

[a-zA-Z]+ { 
    yylval.strV = yytext; 
    return ID; 
} 

[0-9]+  { 
    yylval.intV = atoi(yytext); 
    return INTEGER; 
} 

[\n] { return *yytext; } 

[ \t]  ; 

. yyerror("invalid character"); 

%% 

int yywrap(void) { 
    return 1; 
} 

Это мой парсер:

%{ 
#include <stdio.h> 

int yydebug=1; 
void prompt(); 
void yyerror(char *); 
int yylex(void); 
%} 

%union { 
    int intV; 
    char *strV; 
} 

%token INTEGER ID 

%% 

program: program statement EOF { prompt(); } 
     | program EOF { prompt(); } 
     | { prompt(); } 
     ; 

args: /* empty */ 
    | args ID { printf(":%s ", $<strV>2); } 
    ; 

statement: ID args { printf("%s", $<strV>1); } 
     | INTEGER { printf("%d", $<intV>1); } 
; 

EOF: '\n' 

%% 

void yyerror(char *s) { 
    fprintf(stderr, "%s\n", s); 
} 

void prompt() { 
    printf("> "); 
} 

int main(void) { 
    yyparse(); 
    return 0; 
} 

очень простой язык, состоящий из не более строк и целых и основной РЕПЛ. Теперь вы заметите в синтаксическом анализаторе, что args выводятся с ведущим двоеточием, предполагая, что в сочетании с первым шаблоном правила заявление взаимодействие с REPL будет выглядеть примерно так:

> aaa aa a 
:aa :a aaa> 

Однако взаимодействие заключается в следующем:

> aaa aa a 
:aa :a aaa aa aa 
> 

Почему маркер ID в следующем правиле

statement: ID args { printf("%s", $<strV>1); } 
     | INTEGER { printf("%d", $<intV>1); } 
; 

имеют семантическое значение общей входной строки, включая новую строку строки? Как моя грамматика может быть переработана так, чтобы взаимодействие я намеревался?

ответ

2

Вы должны сохранять строки токенов по мере их чтения, если хотите, чтобы они оставались действительными. Я изменил statement правило следующим образом:

statement: ID { printf("<%s> ", $<strV>1); } args { printf("%s", $<strV>1); } 
     | INTEGER { printf("%d", $<intV>1); } 
; 

Затем, с входом, я получаю выход:

> aaa aa a 
<aaa> :aa :a aaa aa a 
> 

Обратите внимание, что в то время начальный идентификатор чтения, маркер именно то, что вы ожидается. Но, поскольку вы не сохранили токен, строка была изменена к тому времени, когда вы вернетесь к ее распечатке после анализа args.

+0

спасибо, очень много. – troutwine

0

Я думаю, что существует конфликт ассоциативности между произведениями args и statement. Это подтверждается (частичного) выхода из файла bison -v parser.output:

Nonterminals, with rules where they appear 

$accept (6) 
    on left: 0 
program (7) 
    on left: 1 2 3, on right: 0 1 2 
statement (8) 
    on left: 4 5, on right: 1 
args (9) 
    on left: 6 7, on right: 4 7 
EOF (10) 
    on left: 8, on right: 1 2 

В самом деле, я с трудом пытаясь выяснить, что ваша грамматика пытается принять. В качестве побочного примечания я, вероятно, переместил бы вашу EOF-продукцию в лексер как маркер EOL; это упростит повторную синхронизацию ошибок анализа.

Лучшее объяснение ваших намерений было бы полезно.

+0

Я не совсем уверен, как объяснить свое намерение лучше, чем раздел о взаимодействии. Я пытаюсь построить линейный REPL, который идентифицирует первый идентификатор как не-аргумент, а все остальные - как аргументы. Целью является выход первого взаимодействия, а не второго. – troutwine

Смежные вопросы