yacc用法(未完成)

用 Yacc 编写语法

如同 Lex 一样, 一个 Yacc 程序也用双百分号分为三段。 它们是:声明、语法规则和 C 代码。 我们将解析一个格式为 姓名 = 年龄 的文件作为例子,来说明语法规则。 我们假设文件有多个姓名和年龄,它们以空格分隔。 在看 Yacc 程序的每一段时,我们将为我们的例子编写一个语法文件。

C 与 Yacc 的声明

C 声明可能会定义动作中使用的 类型 和 变量,以及 宏。 还可以包含头文件。每个 Yacc 声明段声明了终端符号和非终端符号(标记)的名称(终结符和非终结符),还可能描述操作符优先级和针对不同符号的数据类型。 lexer (Lex) 一般返回这些标记。所有这些标记都必须在 Yacc 声明中进行说明。
终端和非终端符号

终端符号 : 代表一类在语法结构上等效的标记。 终端符号有三种类型:
命名标记: 这些由 %token 标识符来定义。 按照惯例,它们都是大写。
字符标记 : 字符常量的写法与 C 相同。例如, – 就是一个字符标记。
字符串标记 : 写法与 C 的字符串常量相同。例如,”<<” 就是一个字符串标记。
lexer 返回命名标记。
非终端符号 : 是一组非终端符号和终端符号组成的符号。 按照惯例,它们都是小写。 在例子中,file 是一个非终端标记而 NAME 是一个终端标记。

在文件解析的例子中我们感兴趣的是这些标记:name, equal sign, 和 age。Name 是一个完全由字符组成的值。 Age 是数字。于是声明段就会像这样:

文件解析例子的声明

 %
       #typedef char* string; /* to specify token types as char* */
       #define YYSTYPE string /*a Yacc variable which has the value of returned token */
        %}
        %token NAME EQ AGE
        %%

YYSTYPE 定义了用来将值从 lexer 拷贝到解析器或者 Yacc 的 yylval (另一个 Yacc 变量)的类型。 默认的类型是 int。 由于字符串可以从 lexer 拷贝,类型被重定义为 char*
Yacc 语法规则
result: components { /action to be taken in C / } ;
在这个例子中,result 是规则描述的非终端符号。Components 是根据规则放在一起的不同的终端和非终端符号。 如果匹配特定序列的话 Components 后面可以跟随要执行的动作。

  param : NAME EQ NAME {
  printf("\tName:%s\tValue(name):%s\n", $1,$3);}
        | NAME EQ VALUE{
            printf("\tName:%s\tValue(value):%s\n",$1,$3);}
        ;

如果上例中序列 NAME EQ NAME 被匹配,将执行相应的 { } 括号中的动作。 这里另一个有用的就是 1 3 的使用, 它们引用了标记 NAME 和 NAME(或者第二行的 VALUE)的值。相当于switch语句
lexer 通过 Yacc 的变量 yylval 返回这些值。标记 NAME 的 Lex 代码是这样的:

  char [A-Za-z]
        name {char}+
        %%
        {name} { yylval = strdup(yytext);
        return NAME; }

文件解析例子的规则段是这样的:

文件解析的语法


       file : record file
              | record
            ;
      record: NAME EQ AGE {
        printf("%s is now %s years old!!!", $1, $3);}
        ;
        %%

附加 C 代码

(这一段是可选的)一个函数如 main() 调用 yyparse() 函数(Yacc 中 Lex 的 yylex() 等效函数)。 一般来说,Yacc 最好提供 yyerror(char msg) 函数的代码。 当解析器遇到错误时调用 yyerror(char msg)。错误消息作为参数来传递。 一个简单的 yyerror( char* ) 可能是这样的:

 int yyerror(char* msg)
        {
        printf("Error: %s
        encountered at line number:%d\n", msg, yylineno);
        }

要生成代码,可能用到以下命令:

   $ yacc _d <filename.y>

这生成了输出文件 y.tab.h 和 y.tab.c,它们可以用 UNIX 上的任何标准 C 编译器来编译(如 gcc)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值