Непреднамеренная конкатенация в грамматике Bison / Yacc

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

%{ #include  #include  #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  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 ", $2); } ; statement: ID args { printf("%s", $1); } | INTEGER { printf("%d", $1); } ; EOF: '\n' %% void yyerror(char *s) { fprintf(stderr, "%s\n", s); } void prompt() { printf("> "); } int main(void) { yyparse(); return 0; } 

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

 > aaa aa a :aa :a aaa> 

Однако взаимодействие таково:

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

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

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

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

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

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

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

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

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

    Я думаю, что существует конфликт ассоциативности между постановками 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; это упростит повторную синхронизацию ошибок анализа.

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