YACC定义的结构

问题描述 投票:0回答:1

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

sample:

/* 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",$1, $3);
      }
      | _DIR EQUALS META {
            printf("%s is set to %s\n",$1, $3);
      }
%%

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;
}

我遇到的主要问题是,程序只在第一次解析时正确运行,然后返回一个语法错误,这是不正确的。这是否与我编写语法的方式有关?

例如从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文件中收到关于我的regex的警告。

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);
          ^

这是否是问题的根源,或者是另外一个问题?

c yacc lex
1个回答
1
投票

这是两个不同的问题。

  1. 你的语法如下,省去了动作。

    meta: PROD_TITL EQUALS META
        | _DIR EQUALS META 
    

    也就是说,你的语法接受两个序列中的一个, 两个序列都有三个标记。也就是说,它接受 "PROD_TITL EQUALS META "或"_DIR EQUALS META"。就是这样。一旦它找到了其中之一,它就已经解析了它知道如何解析的内容,并且它希望被告知输入已经完成。任何其他的输入都是一个错误。

  2. 编译器抱怨的是 yylval = strdup(yytext); 因为据说 yylval 属于 int. 这是 yaccbison 的默认语义类型;如果你不做任何改变,bison 就会假定是这样,并且它会插入 extern int yylval; 在它生成的头文件中,这样词法学家就知道语义类型是什么了。如果你在互联网上搜索,你可能会找到各种建议的宏黑客来改变这一点,但是用 "现代 "bison来做这件事的正确方法是在你的bison文件中插入以下声明,在序言的某个地方。

    %declare api.value.type { char* }
    

    以后,你可能会发现你想要一个联合类型,而不是把所有东西都变成字符串。在达到这一点之前,你应该阅读Bison手册中关于以下内容的章节 定义语义价值. (事实上,你最好从头到尾读一遍拜森手册,包括第2节的简单例子。它并不长,而且很容易读懂)。)

© www.soinside.com 2019 - 2024. All rights reserved.