使用柠檬解析器(LALR)生成一个calulator,如何从表达式中获取param

我想从输入中得到参数。 例如: Input:12+10 。 运行我的计算器后。

我想得到12和10.我知道,我必须使用Parse(pParser, hTokenID, sTokenData, pArg);的第四个参数Parse(pParser, hTokenID, sTokenData, pArg); ,但是怎么样?

parser.y

 %syntax_error{fprintf(stderr, "Syntax error\n");} %left PLUS MINUS. %left TIMES DIVIDE. program ::= expr(A).{printf("Result = %d\n", A);} expr(A) ::= expr(B) PLUS expr(C).{A = B + C; } expr(A) ::= expr(B) MINUS expr(C). {A = B - C; } expr(A) ::= expr(B) TIMES expr(C). {A = B * C; } expr(A) ::= expr(B) DIVIDE expr(C). {if (C != 0)A = B / C;else fprintf(stderr,"divide by 0");} expr(A) ::= LPAR expr(B) RPAR. {A = (B);} expr(A) ::= INTEGER(B).{A = B;} 

calc.c

 int main(int argc, char ** argv){ pParser = (void *)ParseAlloc(malloc); for (c = argv[1]; *c; c++){ switch (*c){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': for (value = 0; *c && *c >= '0' && *c <= '9'; c++) value = value * 10 + (*c - '0'); c--; Parse(pParser, INTEGER, value); break; case '+': Parse(pParser, PLUS, 0); break; case '-': Parse(pParser, MINUS, 0); break; case '*': Parse(pParser, TIMES, 0); break; ...(the rest case I dont write anymore,the same as before) } } Parse(pParser, 0, 0); ParseFree(pParser, free); } 

如果你想通过第4个参数将一些数据传递到lemon的块中,你必须在.y文件中添加以下行:

 %extra_argument { const char* arg } 

请参阅lemon的文档( http://www.hwaci.com/sw/lemon/lemon.html ):

%extra_argument指令

%extra_argument指令指示Lemon将第4个参数添加到它生成的Parse()函数的参数列表中。 Lemon没有对这个额外的参数做任何事情,但它确实使得参数可用于C代码动作例程,析构函数等等。 例如,如果语法文件包含:

 %extra_argument { MyStruct *pAbc } 

然后生成的Parse()函数将具有MyStruct*类型的第4个参数,并且所有动作例程都可以访问名为pAbc的变量,该变量是最近调用Parse()第4个参数的值。

但请注意“这是最近调用 Parse()第4个参数的值”

所以,我相信你想要传递完全令牌值。 在这种情况下,您必须将标记值包装到结构中:

 struct SToken { int value; const char* token; }; 

您的程序以这种方式修改:

parse.y

 %include { #include "types.h" #include "assert.h" } %syntax_error { fprintf(stderr, "Syntax error\n"); } %token_type { struct SToken* } %type expr { int } %left PLUS MINUS. %left TIMES DIVIDE. program ::= expr(A). { printf("Result = %d\n", A); } expr(A) ::= expr(B) PLUS expr(C). {A = B + C; } expr(A) ::= expr(B) MINUS expr(C). {A = B - C; } expr(A) ::= expr(B) TIMES expr(C). {A = B * C; } expr(A) ::= expr(B) DIVIDE expr(C). { if (C != 0) { A = B / C; } else { fprintf(stderr, "divide by 0"); } } expr(A) ::= LPAR expr(B) RPAR. { A = B; } expr(A) ::= INTEGER(B). { A = B->value; printf("Passed argument: %s\n", B->token); } 

main.c

 #include "types.h" #include "parse.h" #include  #include  int main(int argc, char ** argv) { int value; void* pParser; const char *c; size_t i = 0; struct SToken v[argc]; if (2 > argc) { printf("Usage: %s \n", argv[0]); return 1; } pParser = (void *) ParseAlloc(malloc); for (i = 1; i < argc; ++i) { c = argv[i]; v[i].token = c; switch (*c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': for (value = 0; *c && *c >= '0' && *c <= '9'; c++) value = value * 10 + (*c - '0'); v[i].value = value; Parse(pParser, INTEGER, &v[i]); break; case '+': Parse(pParser, PLUS, NULL); break; case '-': Parse(pParser, MINUS, NULL); break; case '*': Parse(pParser, TIMES, NULL); break; case '/': Parse(pParser, DIVIDE, NULL); break; case '(': Parse(pParser, LPAR, NULL); break; case ')': Parse(pParser, RPAR, NULL); break; default: fprintf(stderr, "Unexpected token %s\n", c); } } Parse(pParser, 0, NULL); ParseFree(pParser, free); return 0; } 

types.h

 #ifndef __TYPES_H__ #define __TYPES_H__ #include  struct SToken { int value; const char* token; }; extern void *ParseAlloc(void *(*)(size_t)); extern void Parse(void *, int, struct SToken*); void ParseFree(void *, void (*)(void*)); #endif 

样本输出:

 veei@sauron:~/tmp/build$ ./test.it Usage: ./test.it  veei@sauron:~/tmp/build$ ./test.it 12 Passed argument: 12 Result = 12 veei@sauron:~/tmp/build$ ./test.it 12 + 12 Passed argument: 12 Passed argument: 12 Result = 24 veei@sauron:~/tmp/build$ ./test.it 12 - 12 Passed argument: 12 Passed argument: 12 Result = 0 veei@sauron:~/tmp/build$ ./test.it 12 "*" 12 Passed argument: 12 Passed argument: 12 Result = 144 veei@sauron:~/tmp/build$ ./test.it "(" 12 + 12 ")" "*" 2 Passed argument: 12 Passed argument: 12 Passed argument: 2 Result = 48 veei@sauron:~/tmp/build$ ./test.it "(" 12 "*" 12 ")" "+" 2 Passed argument: 12 Passed argument: 12 Passed argument: 2 Result = 146 veei@sauron:~/tmp/build$ ./test.it 12 / 12 Passed argument: 12 Passed argument: 12 Result = 1 veei@sauron:~/tmp/build$ 

以防万一,CMake脚本编译此示例:

CMakeLists.txt

 cmake_minimum_required(VERSION 3.0) project(lemon.test) add_executable(test.it main.c parse.c) add_custom_target(parser DEPENDS ${CMAKE_SOURCE_DIR}/parse.c) add_custom_command(OUTPUT ${CMAKE_SOURCE_DIR}/parse.c COMMAND lemon -s ${CMAKE_SOURCE_DIR}/parse.y DEPENDS ${CMAKE_SOURCE_DIR}/parse.y) add_dependencies(test.it parser)