用柠檬分析器(LALR)生成calulator,如何从EX pressions参数 [英] Use lemon parser(LALR) generate a calulator, how to get param from expressions

查看:145
本文介绍了用柠檬分析器(LALR)生成calulator,如何从EX pressions参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想从一个输入获得参数。例如:输入: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/lemo​​n/ 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 directive

The %extra_argument directive instructs Lemon to add a 4th parameter to the parameter list of the Parse() 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 type MyStruct* and all action routines will have access to a variable named pAbc that is the value of the 4th parameter in the most recent call to Parse().

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆