如何使用"文字字符串代币"在野牛

时间:2017-03-29 13:51:58

标签: token bison

我正在学习Flex / Bison。 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

有什么想法吗?

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

一种选择:使用多个&#34;字面字符标记&#34;:

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
<=

但是手册说:

  

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

2 个答案:

答案 0 :(得分:1)

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

  

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

所以你不需要声明文字字符串标记,但你仍然需要安排lexer发送正确的标记号,如果你没有声明一个关联的标记名,那么找到它的唯一方法就是正确的值是在yytname表中搜索代码。

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

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

答案 1 :(得分:0)

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

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