Operations with YACC in C for a LISP subset
Is there any way to add to 2 or more operands in a YACC project using the C language to build a parser for a LISP subset, this is the grammar
"mod" and "let" are not case sensitive, neither the symbols
P:
'('LET '('DEF_VARS')' BODY')'
|BODY
;
DEF_VARS:
DEF_VARS DEF
|DEF
;
DEF:
'('SYMBOL OPN')'
;
CUERPO:
BODY EXPR
|EXPR
;
EXPR:
'('OPER OPNS')'
;
OPER:
'开发者_如何学Go+'
|'-'
|'*'
|MOD // %
|'/'
;
OPNS:
OPNS OPN
|OPN
;
OPN:
EXPR
|INT // [-+]?[0-9]+
|SYMBOL //[a-zA-Z][a-zA-Z0-9_]* //a variable
;
I am loooking to know how to use a symbol table and add, substract, multiply, divide and mod, a list of elements, and declare variables I have no idea how to use a symbol table in code.
for example, these sentences are valid for the language:
(+ 30 -7 +3)
result is 26
(* (+ 3 4) (- -5 2))
result is -49
( lEt ((x(+ 1 2))(y x))(/ (mod x y) 3))
result is 0
Any help is welcome. Thanks in advance.
Hmm, I see several problems.
For one, I suppose the non-terminal CUERPO
should actually have been typed in as BODY
, right?
Secondly, that grammar will not in fact parse any of those test cases.
All of the test cases require an operator and then multiple expressions with additional operators, yet the only rule that allows an operator also requires new parens.
Now, your grammar will parse:
(+1 2 3 a b fnorq bletch)
and similar phrases...
I would suggest getting the grammar and the parsing correct before adding a symbol table and actually executing the arithmetic. With a working framework, the requirement to hunt down the actual values of symbols will make the theory, operation, and development of a symbol table much more obvious.
I've made your grammar into an actual "working" program:
$ cat > lispg.y
%{
char *yylval;
int yylex(void);
void yyerror(char const *);
#define YYSTYPE char *
int yydebug = 1;
%}
%token LET
%token SYMBOL
%token INT
%token MOD
%token SYMBOL_TOO_LONG
%%
P: '('LET '('DEF_VARS')' BODY')'
|BODY
;
DEF_VARS:
DEF_VARS DEF
|DEF
;
DEF:
'('SYMBOL OPN')'
;
BODY:
BODY EXPR
|EXPR
;
EXPR:
'('OPER OPNS')'
;
OPER:
'+'
|'-'
|'*'
|MOD // %
|'/'
;
OPNS:
OPNS OPN
|OPN
;
OPN:
EXPR
|INT // [-+]?[0-9]+
|SYMBOL //[a-zA-Z][a-zA-Z0-9_]* //a variable
;
%%
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int parsesym(int c)
{
char *p;
static char sym[100];
for(p = sym; p < sym + sizeof sym - 1; ) {
*p++ = c;
c = getchar();
if ('a' <= c && c <= 'z')
c -= 'a' - 'A';
if ('A' <= c && c <= 'Z' || '0' <= c && c <= '9' || c == '_')
continue;
*p++ = '\0';
ungetc(c, stdin);
if (strcmp(sym,"LET") == 0)
return LET;
yylval = strdup(sym);
return SYMBOL;
}
return SYMBOL_TOO_LONG;
}
int parseint(int c) {
parsesym(c);
return INT;
}
int yylex() {
for(;;) {
int c;
switch(c = getchar()) {
case EOF:
return 0;
case ' ':
case '\n':
case '\t':
continue;
case '(':
case ')':
case '+':
case '-':
case '*':
case '/':
return c;
case '%':
return MOD;
default:
if('0' <= c && c <= '9')
return parseint(c);
if('a' <= c && c <= 'z')
c -= 'a' - 'A';
if('A' <= c && c <= 'Z') {
return parsesym(c);
}
}
}
}
$ yacc lispg.y && cc -Wall -Wextra -Wno-parentheses y.tab.c -ly
$ echo '(+1 2 3 a b fnorq bletch)' | ./a.out
精彩评论