Bison/Yacc语法中的无意串联

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带有一个前导冒号,意图是当与statement规则的第一个模式结合使用时,与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个回答

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
>

请注意,在读取初始ID时,令牌正好符合您的预期。但是,由于您没有保存令牌,在解析args后返回打印它的字符串时,该字符串已被修改。

0

我认为参数和语句产生式之间存在结合性冲突。这一点可以从bison -v解析器输出文件的(部分)输出中得到证实:

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标记;这将使重新同步解析错误更容易。

更好地解释你的意图将是有帮助的。


我不确定如何更好地解释我的意图,除了交互部分。 我试图构建一个以行为导向的REPL,将第一个ID标识为非参数,而其余所有内容均为参数。 目标是输出第一个交互,而不是第二个。 - troutwine

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接