Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

基础用法

.y

每个 Bison 文件由 %% 分成三部分。

%{
##include <stdio.h>
/* 这里是序曲 */
/* 这部分代码会被原样拷贝到生成的 .c 文件的开头 */
int yylex(void);
void yyerror(const char *s);
%}

/* 这些地方可以输入一些 bison 指令 */
/* 比如用 %start 指令指定起始符号,用 %token 定义一个 token */
%start reimu
%token REIMU

%%
/* 从这里开始,下面是解析规则 */
reimu : marisa { /* 这里写与该规则对应的处理代码 */ puts("rule1"); }
      | REIMU  { /* 这里写与该规则对应的处理代码 */ puts("rule2"); }
      ; /* 规则最后不要忘了用分号结束哦~ */
      
/* 这种写法表示 ε —— 空输入 */
marisa : { puts("Hello!"); }

%%
/* 这里是尾声 */
/* 这部分代码会被原样拷贝到生成的 .c 文件的末尾 */

int yylex(void)
{
    int c = getchar(); // 从 stdin 获取下一个字符 
    switch (c) {
    case EOF: return YYEOF;
    case 'R': return REIMU;
    default:  return 0;     // 返回无效 token 值,迫使 bison 报错
    }
}

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

int main(void)
{
    yyparse(); // 启动解析
    return 0;
}

另外有一些值得注意的点:

  1. Bison 传统上将 token 用大写单词表示,将 symbol 用小写字母表示。
  2. Bison 能且只能生成解析器源代码(一个 .c 文件),并且入口是 yyparse,所以为了让程序能跑起来,你需要手动提供 main 函数(但不一定要在 .y 文件中——你懂“链接”是什么,对吧?)。
  3. Bison 不能检测你的 action code 是否正确——它只能检测文法的部分错误,其他代码都是原样粘贴到 .c 文件中。
  4. Bison 需要你提供一个 yylex 来获取下一个 token。
  5. Bison 需要你提供一个 yyerror 来提供合适的报错机制。

顺便提一嘴,上面这个 .y 是可以工作的——尽管它只能接受两个字符串。把上面这段代码保存为 reimu.y,执行如下命令来构建这个程序:

编译运行

$ bison reimu.y
$ gcc reimu.tab.c
$ ./a.out
R<-- 不要回车在这里按 Ctrl-D
rule2
$ ./a.out
<-- 不要回车在这里按 Ctrl-D
Hello!
rule1
$ ./a.out
blablabla <-- 回车或者 Ctrl-D
Hello!
rule1     <-- 匹配到了 rule1
syntax error <-- 发现了错误

于是我们验证了上述代码的确识别了该文法定义的语言 { "", "R" }

一个好教程:https://www.oreilly.com/library/view/flex-bison/9780596805418/ch01.html

评论