用柠檬分析器(LALR)生成calulator,如何从EX pressions参数 [英] Use lemon parser(LALR) generate a calulator, how to get param from expressions
问题描述
我想从一个输入获得参数。例如:输入:12 + 10
。
运行我的计算器了。
我希望得到12和10我知道,我不得不使用解析(pParser,hTokenID,sTokenData,PARG)第四参数;
,但如何?
parser.y
%syntax_error {fprintf中(标准错误,语法错误。\\ n);}
离开%加减。
离开%TIMES鸿沟。
节目:: = EXPR(A){printf的(结果=%d个\\ N,A);}。
EXPR(A):: = EXPR(B)PLUS EXPR(C){A = B + C。 }
EXPR(A):: = EXPR(B)减去EXPR(C)。 {A = B - C型}
EXPR(A):: = EXPR(B)倍EXPR(C)。 {A = B * C; }
EXPR(A):: = EXPR(B)DIVIDE EXPR(C)。 {如果(C!= 0)A = B / C;否则fprintf中(标准错误,由0鸿沟);}
EXPR(A):: = LPAR EXPR(B)RPAR。 {A =(B);}
。EXPR(A):: = INTEGER(B){A = B;}
calc.c
INT主(INT ARGC,字符** argv的){
pParser =(无效*)ParseAlloc(malloc的);
为(C =的argv [1]; * C; C ++){
开关(* C){
情况下0:案件1:案件'2':案例3:案4:
案5:案6:案件'7':案例'8':案例'9':
对于(值= 0; * C&放大器;&放大器; * c基='0'和;&放大器; * C< =9; C ++)
值=值* 10 +(* C - '0');
C - ;
解析(pParser,INTEGER,值);
打破;
案例'+':
解析(pParser,PLUS,0);
打破;
案件 '-':
解析(pParser,减,0);
打破;
案件 '*':
解析(pParser,时间,0);
打破;
...(其余的情况下,我不写了,和以前一样)
}
}
解析(pParser,0,0);
ParseFree(pParser,免费);
}
如果您希望将一些数据传递到柠檬
通过4个参数的块,你有添加到您的 .Y
文件中有如下一行:
%extra_argument {为const char * ARG}
请参阅柠檬的文档( http://www.hwaci.com/sw/lemon/ lemon.html ):
的
%extra_argument
指令
的
%extra_argument
指令指示柠檬到第四个参数添加到解析()
函数的参数列表它产生。柠檬并不做任何事情本身这个额外的参数,但它确实提供给C- code动作套路,析构函数,等等的说法。例如,如果该语法文件包含:%extra_argument {MYSTRUCT * PABC}
然后生成的
解析()
功能将有类型的MYSTRUCT *
的第四个参数,所有的动作程序将有机会获得名为PABC
的变量是在最近一次调用第4个参数的值解析()
块引用>但是请注意,这是第四个参数的在最近通话的值
解析()
所以,我认为,要准确地传递令牌值。在这种情况下,你必须包装令牌值到结构:
结构SToken
{
int值;
为const char *记号。
};您计划这样修改:
parse.y
%包括
{
#包括types.h中#包括ASSERT.H
}
%syntax_error {fprintf中(标准错误,语法错误。\\ n); }
%token_type {结构SToken *}
%型EXPR {} INT
离开%加减。
离开%TIMES鸿沟。
节目:: = EXPR(A)。 {printf的(结果=%d个\\ N,A); }
EXPR(A):: = EXPR(B)PLUS EXPR(C)。 {A = B + C; }
EXPR(A):: = EXPR(B)减去EXPR(C)。 {A = B - C型}
EXPR(A):: = EXPR(B)倍EXPR(C)。 {A = B * C; }
EXPR(A):: = EXPR(B)DIVIDE EXPR(C)。
{
如果(C!= 0)
{
A = B / C;
}
其他
{
fprintf中(标准错误,除以0);
}
}
EXPR(A):: = LPAR EXPR(B)RPAR。 {A = B; }
EXPR(A):: = INTEGER(B)。
{
A = B->价值;
的printf(传递的参数:%S \\ n,B>令牌);
}的main.c
的#includetypes.h中
#包括parse.h中#包括LT&;&stdlib.h中GT;
#包括LT&;&stdio.h中GT;INT主(INT ARGC,字符** argv的)
{
int值;
无效* pParser;
为const char * C;
为size_t I = 0;
结构SToken v [ARGC] 如果(2 - ; argc个)
{
的printf(用法:%S<前pression> \\ N的argv [0]);
返回1;
} pParser =(无效*)ParseAlloc(malloc的);
对于(i = 1; I< ARGC ++ I)
{
C =的argv [I]
v [I] .token = C;
开关(* C)
{
情况下0:案件1:案件'2':案例3:案4:
案5:案6:案件'7':案例'8':案例'9':
对于(值= 0; * C&放大器;&放大器; * c基='0'和;&放大器; * C< =9; C ++)
值=值* 10 +(* C - '0');
v [I]。价值=价值;
解析(pParser,INTEGER,和放大器; v [I]);
打破; 案例'+':
解析(pParser,PLUS,NULL);
打破; 案件 '-':
解析(pParser,减,NULL);
打破; 案件 '*':
解析(pParser,时间,NULL);
打破; 案件 '/':
解析(pParser,DIVIDE,NULL);
打破; 案件 '(':
解析(pParser,LPAR,NULL);
打破; 案件 ')':
解析(pParser,RPAR,NULL);
打破; 默认:
fprintf中(标准错误,意外令牌%S \\ n,C);
}
}
解析(pParser,0,NULL);
ParseFree(pParser,免费); 返回0;
}types.h中
的#ifndef __TYPES_H__
#定义__TYPES_H__#包括LT&;&stdlib.h中GT;结构SToken
{
int值;
为const char *记号。
};的extern void *的ParseAlloc(无效*()(为size_t));
EXTERN无效解析(无效*,INT,结构SToken *);
无效ParseFree(void *的,无效(*)(无效*));#万一示例输出:
veei @索伦:〜/ tmp目录/编译$ ./test.it
用法:./test.it<前pression>
veei @索伦:〜/ tmp目录/建造$ ./test.it 12
传入的参数:12
结果= 12
veei @索伦:〜/ tmp目录/建造$ ./test.it 12 + 12
传入的参数:12
传入的参数:12
结果= 24
veei @索伦:〜/ tmp目录/建造$ ./test.it 12 - 12
传入的参数:12
传入的参数:12
结果= 0
veei @索伦:〜/ tmp目录/建造$ ./test.it 12*12
传入的参数:12
传入的参数:12
结果= 144
veei @索伦:〜/ tmp目录/编译$ ./test.it(12 + 12)*2
传入的参数:12
传入的参数:12
传入的参数:2
结果= 48
veei @索伦:〜/ tmp目录/编译$ ./test.it(12*12)+2
传入的参数:12
传入的参数:12
传入的参数:2
结果= 146
veei @索伦:〜/ tmp目录/建造$ ./test.it 12月12日
传入的参数:12
传入的参数:12
结果= 1
veei @索伦:〜/ tmp目录/编译$和为了以防万一,CMake的脚本来编译此示例:
的CMakeLists.txt
cmake_minimum_required(3.0版)项目(lemon.test)add_executable(test.it main.c中parse.c)add_custom_target(分析器DEPENDS $ {} CMAKE_SOURCE_DIR /parse.c)
add_custom_command(OUTPUT $ {} CMAKE_SOURCE_DIR COMMAND /parse.c柠檬-s $ {} CMAKE_SOURCE_DIR /parse.y DEPENDS $ {} CMAKE_SOURCE_DIR /parse.y)
add_dependencies(test.it解析器)I want to get param from a input. For example:
Input:12+10
. After running my calculator.I want to get 12 and 10. I know, I have to use the fourth param in
Parse(pParser, hTokenID, sTokenData, pArg);
, but how?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); }
解决方案If you want to pass some data into
lemon
's blocks through 4-th parameter, you have to add into your.y
file the following line:%extra_argument { const char* arg }
See lemon's documentation (http://www.hwaci.com/sw/lemon/lemon.html):
The
%extra_argument
directiveThe
%extra_argument
directive instructs Lemon to add a 4th parameter to the parameter list of theParse()
function it generates. Lemon doesn't do anything itself with this extra argument, but it does make the argument available to C-code action routines, destructors, and so forth. For example, if the grammar file contains:%extra_argument { MyStruct *pAbc }
Then the
Parse()
function generated will have an 4th parameter of typeMyStruct*
and all action routines will have access to a variable namedpAbc
that is the value of the 4th parameter in the most recent call toParse()
.But notice that "that is the value of the 4th parameter in the most recent call to
Parse()
"So, I believe that you want to pass exactly token value. In this case you have to wrap token value into structure:
struct SToken { int value; const char* token; };
Your program modified in this way:
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 <stdlib.h> #include <stdio.h> 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 <expression>\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 <stdlib.h> 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
Sample output:
veei@sauron:~/tmp/build$ ./test.it Usage: ./test.it <expression> 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$
And just in case, CMake script to compile this sample:
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)
这篇关于用柠檬分析器(LALR)生成calulator,如何从EX pressions参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!