我正在为一个个人项目编写一个标记语言的解析器。
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);
^
这是否是问题的根源,或者是另外一个问题?
这是两个不同的问题。
你的语法如下,省去了动作。
meta: PROD_TITL EQUALS META
| _DIR EQUALS META
也就是说,你的语法接受两个序列中的一个, 两个序列都有三个标记。也就是说,它接受 "PROD_TITL EQUALS META "或"_DIR EQUALS META"。就是这样。一旦它找到了其中之一,它就已经解析了它知道如何解析的内容,并且它希望被告知输入已经完成。任何其他的输入都是一个错误。
编译器抱怨的是 yylval = strdup(yytext);
因为据说 yylval
属于 int
. 这是 yaccbison 的默认语义类型;如果你不做任何改变,bison 就会假定是这样,并且它会插入 extern int yylval;
在它生成的头文件中,这样词法学家就知道语义类型是什么了。如果你在互联网上搜索,你可能会找到各种建议的宏黑客来改变这一点,但是用 "现代 "bison来做这件事的正确方法是在你的bison文件中插入以下声明,在序言的某个地方。
%declare api.value.type { char* }
以后,你可能会发现你想要一个联合类型,而不是把所有东西都变成字符串。在达到这一点之前,你应该阅读Bison手册中关于以下内容的章节 定义语义价值. (事实上,你最好从头到尾读一遍拜森手册,包括第2节的简单例子。它并不长,而且很容易读懂)。)