ini.l
%option yylineno
%{
#include <stdio.h>
#include "ini.tab.h"
int yywrap(void) {
return 1;
}
void yyerror(const char* s) {
printf("%d: %s at %s\n", yylineno, s, yytext);
}
#if defined YYDEBUG
extern int yydebug;
#endif
#define CASE_RETURN(token) do { case token: return #token; } while(0)
char *get_tokenname(token) {
switch(token) {
CASE_RETURN( IDENTIFIER );
CASE_RETURN( BRACKETS_LEFT );
CASE_RETURN( BRACKETS_RIGHT );
CASE_RETURN( EQ );
default: return "Unknown";
}
}
int main(void) {
int token;
#if defined YYDEBUG
yydebug = 1;
while ((token = yylex()) != 0)
printf("Token: %d/%-20s (%s)\n", token, get_tokenname(token), yytext);
#else
yyparse();
#endif
return 0;
}
%}
%%
[_a-zA-Z0-9]+ { yylval.str = strdup(yytext); return IDENTIFIER; }
"[" { return BRACKETS_LEFT; }
"]" { return BRACKETS_RIGHT; }
"=" { return EQ; }
[ \t\r\n] { }
%%
ini.y
%{
#include <stdio.h>
#include <string.h>
%}
%union {
char* str;
}
%token <str> IDENTIFIER
%token BRACKETS_LEFT BRACKETS_RIGHT EQ
%%
input
: /* empty */
| input line
| line
;
line
: BRACKETS_LEFT section BRACKETS_RIGHT
| key EQ value
;
section : IDENTIFIER { printf("section: %s\n" , $1); } ;
key : IDENTIFIER { printf("key: %s, " , $1); } ;
value : IDENTIFIER { printf("value: %s\n" , $1); } ;
%%
生成文件
CC = gcc
LEX = flex
YACC = bison
TARGET = a.out
LEX_SRC = $(wildcard *.l)
YACC_SRC = $(wildcard *.y)
SRC = $(patsubst %.y,%.tab.c,$(YACC_SRC)) $(patsubst %.l,%.yy.c,$(LEX_SRC))
INC = $(patsubst %.y,%.tab.h,$(YACC_SRC)) $(patsubst %.l,%.yy.h,$(LEX_SRC))
DEBUG = -DYYDEBUG -DYYERROR_VERBOSE
LDFLAGS = -L/usr/local/opt/bison/lib \
-L/usr/local/opt/flex/lib \
-I/usr/local/opt/flex/include
all: $(SRC)
$(CC) $(FLAGS) $(SRC) -o $(TARGET)
debug: $(SRC)
$(CC) $(FLAGS) $(SRC) -o $(TARGET) $(DEBUG)
.PRECIOUS: %.yy.c
%.yy.c: %.l
$(LEX) -t $< > $@
.PRECIOUS: %.tab.c
%.tab.c:%.y
$(YACC) -o $@ -d $<
clean:
rm -rf $(TARGET) $(SRC) $(INC) *.output
sample.ini
[foobar]
foo=bar
$ make clean && make
$ ./a.out < sample.ini
section: foobar
key: foo, value: bar
一切都很好
$ make clean && make debug
$ ./a.out < sample.ini
Token: 259/BRACKETS_LEFT ([)
Token: 258/IDENTIFIER (foobar)
Token: 260/BRACKETS_RIGHT (])
Token: 258/IDENTIFIER (foo)
Token: 261/EQ (=)
Token: 258/IDENTIFIER (bar)
然后我将BRACKETS_LEFT
更改为'['
$ git diff -U0
diff --git a/ini.l b/ini.l
index 2538353..12b2524 100644
--- a/ini.l
+++ b/ini.l
@@ -24 +23,0 @@ char *get_tokenname(token) {
- CASE_RETURN( BRACKETS_LEFT );
@@ -47 +45,0 @@ int main(void) {
-"[" { return BRACKETS_LEFT; }
diff --git a/ini.y b/ini.y
index c605ea4..1498ff5 100644
--- a/ini.y
+++ b/ini.y
@@ -11 +11 @@
-%token BRACKETS_LEFT BRACKETS_RIGHT EQ
+%token BRACKETS_RIGHT EQ
@@ -22 +22 @@ line
- : BRACKETS_LEFT section BRACKETS_RIGHT
+ : '[' section BRACKETS_RIGHT
野牛给我一个错误
$ make clean && make debug
$ ./a.out < sample.ini
1: syntax error at [
$ make clean && make debug
$ ./a.out < sample.ini
[Token: 258/IDENTIFIER (foobar)
Token: 259/BRACKETS_RIGHT (])
Token: 258/IDENTIFIER (foo)
Token: 260/EQ (=)
Token: 258/IDENTIFIER (bar)
:(
答案 0 :(得分:1)
为了让野牛能够使用像'['这样的字符标记,扫描仪必须准确地返回'['。
您的扫描仪似乎没有返回任何未知字符的内容。您需要添加默认规则:
. { return yytext[0]; }
我建议始终使用flex nodefault
选项来捕获此类错误。此外,编译时gcc的-Wall
选项。并查看flex和bison的文档,了解如何使用他们的调试跟踪,而不是构建自己的调试跟踪。内置调试易于使用,并产生相当完整的输出。