c - 在 C 中使用 YACC 对 LISP 子集进行操作

标签 c lisp yacc lex

有没有办法在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/

相关文章:

c - 如何将结构传递给 yacc 文件中的函数?

c - 为什么这个逻辑/按位运算返回 1?

c - GtkStack 段错误

list - Lisp 中的列表问题

正则表达式匹配 "not preceded by, unless followed by"

c++ - 在 lex/flex 代码中使用 STL

创建核心基础类

c - 绑定(bind)到选定的接口(interface)

lisp - 可以选择列表的第 n 个项的方案函数

bison - "$$ = 1"在 Bison/Yacc 中是什么意思?