有没有办法在YACC项目中使用C语言为LISP子集构建一个解析器来添加2个或更多的操作数,这是语法
“mod”和“let”不区分大小写,符号也不区分
P:
'('LET '('DEF_VARS')' BODY')'
|BODY
;
DEF_VARS:
DEF_VARS DEF
|DEF
;
DEF:
'('SYMBOL OPN')'
;
CUERPO:
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
;
我想知道如何使用符号表以及加、减、乘、除和模、元素列表以及声明变量 我不知道如何在代码中使用符号表。
例如,这些句子对语言有效:
(+ 30 -7 +3)
结果是26
(* (+ 3 4) (- -5 2))
结果是-49
( lEt ((x(+ 1 2))(y x))(/ (mod x y) 3))
结果为 0
欢迎任何帮助。 提前致谢。
最佳答案
嗯,我看到了几个问题。
首先,我想非终结符 CUERPO
实际上应该输入为 BODY
,对吧?
其次,该语法实际上不会解析任何这些测试用例。
所有的测试用例都需要一个运算符,然后是带有附加运算符的多个表达式,但唯一允许运算符的规则还需要新的括号。
现在,您的语法将解析:
(+1 2 3 a b fnorq bletch)
和类似的短语...
我建议在添加符号表和实际执行算术之前先获得语法和解析正确。有了工作框架,追寻符号实际值的要求将使符号表的理论、操作和开发变得更加明显。
我已经把你的语法变成了一个实际的“工作”程序:
$ 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
关于c - 在 C 中使用 YACC 对 LISP 子集进行操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4280927/