yacc 定义的结构

stucture of yacc definitions

我正在为个人项目的标记语言编写解析器:

样本:

/* This is a comment */

production_title = "My Production"
director         = "Joe Smith"
DOP              = "John Blogs"
DIT              = "Random Name"
format           = "16:9"
camera           = "Arri Alexa"
codec            = "ProRes"
date             = _auto

Reel: A001
  Scene: 23/22a
    Slate: 001
      1-2, 50MM, T1.8, {ND.3}
      3AFS,   50MM, T1.8, {ND.3}
    Slate: 002:
      1,  65MM, T1.8, {ND.3 BPM1/2}
    Slate: 003:
      1-3, 24MM, T1.9 {ND.3}

Reel: A002
  Scene: 23/22a
    Slate: 004
      1-5, 32MM, T1.9, {ND.3}
  Scene: 23/21
    Slate: 005
      1, 100MM, T1.9, {ND.6}

END

我已经开始学习 lex 和 yacc,并且已经 运行 解决了一些关于语法定义结构的问题。

yacc.y

%{
#include <stdio.h>
int yylex();
void yyerror(char *s);
%}

%token PROD_TITL _DIR DOP DIT FORMAT CAMERA CODEC DATE EQUALS
%right META

%%

meta: PROD_TITL EQUALS META {
            printf("%s is set to %s\n",, );
      }
      | _DIR EQUALS META {
            printf("%s is set to %s\n",, );
      }
%%

int main(void) {
  return yyparse();
}

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

lex.l

%{
#include <stdio.h>
#include <string.h>
#include "y.tab.h"
%}

%%

"production_title"  {yylval = strdup(yytext); return PROD_TITL;}
"director"          {yylval = strdup(yytext); return _DIR;}
"DOP"               return DOP;
"DIT"               return DIT;
"format"            return FORMAT;
"camera"            return CAMERA;
"codec"             return CODEC;
"date"              return DATE;

"exit"              exit(EXIT_SUCCESS);

\"[^"\n]*["\n]      { yylval = strdup(yytext);
                      return META;
                    }

=                   return EQUALS;
[ \t\n]                     ;
"/*"([^*]|\*+[^*/])*\*+"/"  ;
.                   printf("unrecognized input\n");
%%

int yywrap(void) {
  return 1;
}

我遇到的主要问题是该程序仅 运行 在第一次解析时正确,然后它 returns 是一个不正确的语法错误。这和我写语法的方式有关吗?

来自 sample.txt 并输入命令的示例输出:

hc@linuxtower:~/Documents/CODE/parse> ./a.out < sample.txt
production_title is set to "My Production"
syntax error
hc@linuxtower:~/Documents/CODE/parse> ./a.out
production_title = "My Production"
production_title is set to "My Production"
director = "Joe Smith"
syntax error

编译时,我在 lex.l 文件中收到关于我的正则表达式的警告:

ca_mu.l: In function ‘yylex’:
ca_mu.l:9:9: warning: assignment makes integer from pointer without a cast [-Wint-conversion]
 "production_title"  {yylval = strdup(yytext); return PROD_TITL;}
         ^
ca_mu.l:10:9: warning: assignment makes integer from pointer without a cast [-Wint-conversion]
 "director"          {yylval = strdup(yytext); return _DIR;}
         ^
ca_mu.l:20:10: warning: assignment makes integer from pointer without a cast [-Wint-conversion]
 \"[^"\n]*["\n]      { yylval = strdup(yytext);
          ^

这可能是问题的根源还是其他问题?

这是两个不同的问题。

  1. 你的语法如下,省略了动作:

    meta: PROD_TITL EQUALS META
        | _DIR EQUALS META 
    

    这意味着您的语法接受两个序列之一,它们都恰好具有三个标记。也就是说,它接受 "PROD_TITL EQUALS META" 或“_DIR EQUALS META”。而已。一旦找到其中之一,它就会尽可能多地进行解析,并期望被告知输入已完成。任何其他输入都是错误的。

  2. 编译器抱怨 yylval = strdup(yytext); 因为它被告知 yylvalint 类型。那是 yacc/bison 的默认语义类型;如果你不做任何改变它,这就是 bison 会假设的,它会在它生成的头文件中插入 extern int yylval;,这样词法分析器就知道语义类型是什么。如果您在互联网上搜索,您可能会发现各种宏黑客建议来更改此设置,但使用 "modern" bison 的正确方法是在您的 bison 文件中插入以下声明,在序言的某处:

    %declare api.value.type { char* }
    

    稍后,您可能会发现您需要联合类型而不是将所有内容都设为字符串。在达到这一点之前,您应该阅读 Bison 手册中关于 Defining Semantic Values 的部分。 (事实上​​ ,建议您从头到尾阅读 Bison 手册,包括第 2 节中的简单示例。它不长,而且非常容易阅读。)