3

我正在试验 lex 和 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;
}

一种非常简单的语言,仅由字符串和整数以及一个基本的 REPL 组成。现在,您将在解析器中注意到args 以前导冒号输出,其目的是,当与语句规则的第一个模式结合时,与 REPL 的交互将如下所示:

> aaa aa a
:aa :a aaa>

但是,交互是这样的:

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

为什么以下规则中的token ID

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

有总输入字符串的语义值,包括换行符?如何修改我的语法以实现我想要的交互?

4

2 回答 2

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
>

Note that at the time the initial ID is read, the token is exactly what you expected. But, because you did not preserve the token, the string has been modified by the time you get back to printing it after the args have been parsed.

于 2010-04-26T13:52:40.880 回答
0

我认为 args 和语句产生之间存在关联性冲突。bison -vparser.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 令牌移入词法分析器;这将使重新同步解析错误更容易。

更好地解释您的意图会有所帮助。

于 2010-04-23T06:18:54.893 回答