使用柠檬解析器(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)