问题
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);
}
回答1:
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)
来源:https://stackoverflow.com/questions/34918631/use-lemon-parserlalr-generate-a-calulator-how-to-get-param-from-expressions