Bison/Yacc 语法中的无意串联

2023-12-25

我正在尝试 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); }
;

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


如果您希望令牌字符串保持有效,则必须在读取它们时保留它们。我修改了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已被解析。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Bison/Yacc 语法中的无意串联 的相关文章

随机推荐