【问题标题】:How to use "literal string tokens" in Bison如何在 Bison 中使用“文字字符串标记”
【发布时间】:2017-03-29 13:51:57
【问题描述】:

我正在学习 Flex/Bison。野牛手册说:

文字字符串记号的写法类似于 C 字符串常量;为了 例如,“

但我不知道如何使用它,也没有找到示例。

我有以下测试代码:

example.l

%option noyywrap nodefault

%{
#include "example.tab.h"
%}

%%

[ \t\n] {;}
[0-9] { return NUMBER; }
. { return yytext[0]; }

%%

example.y

%{
#include <stdio.h>
#define YYSTYPE char *
%}

%token NUMBER

%%

start: %empty | start tokens

tokens:
       NUMBER "<=" NUMBER { printf("<="); }
     | NUMBER "=>" NUMBER { printf("=>\n"); }
     | NUMBER '>' NUMBER { printf(">\n"); }
     | NUMBER '<' NUMBER { printf("<\n"); }

%%

main(int argc, char **argv) {
   yyparse();
}

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

生成文件

#!/usr/bin/make
# by RAM

all: example

example.tab.c example.tab.h: example.y
    bison -d $<

lex.yy.c: example.l example.tab.h
    flex $<

example: lex.yy.c example.tab.c
    cc -o $@ example.tab.c lex.yy.c -lfl

clean:
    rm -fr example.tab.c example.tab.h lex.yy.c example

当我运行它时:

$ ./example 
3<4
<
6>9
>
6=>9
error: syntax error

有什么想法吗?


更新:我想澄清一下,我知道解决它的其他方法,但我想使用 文字字符串标记

一种选择:使用多个“文字字符标记”:

tokens:
       NUMBER '<' '=' NUMBER { printf("<="); }
     | NUMBER '=' '>' NUMBER { printf("=>\n"); }
     | NUMBER '>' NUMBER { printf(">\n"); }
     | NUMBER '<' NUMBER { printf("<\n"); }

当我运行它时:

$ ./example 
3<=9
<=

其他选择:

example.l中:

"<="  { return LE; }
"=>"  { return GE; }

example.y中:

...
%token NUMBER
%token LE "<="
%token GE "=>"

%%

start: %empty | start tokens

tokens:
       NUMBER "<=" NUMBER { printf("<="); }
     | NUMBER "=>" NUMBER { printf("=>\n"); }
     | NUMBER '>' NUMBER { printf(">\n"); }
     | NUMBER '<' NUMBER { printf("<\n"); }
...

当我运行它时:

$ ./example 
3<=4
<=

但是说明书上说:

除非您需要,否则不需要声明文字字符串标记 指定其语义值数据类型

【问题讨论】:

  • 您确定. 匹配多个字符而不是单个字符吗?
  • 还有yytext[0]?
  • . 只匹配一个字符,可以,但我认为不是问题。

标签: token bison


【解决方案1】:

引用的手册段落是正确的,但您也需要阅读下一段:

您可以使用 %token 声明将文字字符串标记与作为别名的符号名称相关联(请参阅标记声明)。如果不这样做,词法分析器必须从 yytname 表中检索文字字符串标记的标记号。

所以你不需要声明文字字符串token,但你仍然需要安排词法分析器发送正确的token编号,如果你不声明关联的token名称,唯一的方法是找到正确的值是在yytname表中搜索代码。

简而言之,您将LEGE 定义为别名的最后一个示例是迄今为止最常见的方法。将标记分成单独的字符不是一个好主意;它可能会产生 shift-reduce 冲突,并且肯定会允许无效输入,例如在字符之间放置空格。

如果您想尝试yytname 解决方案,有sample code in the bison manual。但请注意,此代码会发现 bison 的 internal 令牌编号,这不是需要从扫描仪返回的编号。无法获得简单、便携和记录的外部令牌编号;简单且未记录的方法是在yytoknum 中查找令牌编号,但由于该数组未记录并以预处理器宏为条件,因此无法保证它会起作用。另请注意,这些表被声明为static,因此依赖它们的函数必须包含在野牛输入文件中。 (当然,这些函数可以有外部链接,以便从词法分析器中调用它们。但你不能直接在词法分析器中使用yytname。)

【讨论】:

  • 太棒了!我更喜欢别名解决方案。我尝试了单个角色,正如你所说,我遇到了一些减少班次的冲突。谢谢。
【解决方案2】:

我有一段时间没有使用 flex/bison,但有两件事:

. 据我记得只匹配一个字符。 yytext 是指向以空结尾的字符串 char* 的指针,因此 yytext[0] 是 char,这意味着您不能以这种方式匹配字符串。您可能需要将其更改为return yytext。否则 . 可能会创建一个令牌 PER 字符,您可能必须编写 NUMBER '&lt;' '=' NUMBER

【讨论】:

  • 是的,. 只匹配单个字符。我无法返回 yytex: warning: return makes integer from pointer without a cast 并在执行时失败。我知道我可以做一些链接"&lt;=" { return LE;} 但不是这个想法。我想使用“文字字符串标记”。
  • 啊,是的。您需要为此使用 yylval。您可以定义一个联合 %union { uint8_t byte_value; uint32_t uint_value; int32_t int_value; char* str_value; },然后使用 yylval.str_value = strdup(yytext); return STRING;(如果您也有 %token &lt;str_value&gt; STRING;)。我过去就是这样做的。
  • 参见 bitbucket.org/mroman_/emulathor/src/…bitbucket.org/mroman_/emulathor/src/… 示例,如果你定义这样的标记,你可以有一个包含 int、double、string 的联合,具体取决于它是什么类型的标记。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-15
  • 2023-03-14
  • 2010-09-08
  • 1970-01-01
相关资源
最近更新 更多