用 C 语言对 LISP 子集进行 YACC 运算

发布于 2024-10-05 01:06:06 字数 874 浏览 4 评论 0原文

有没有办法使用 C 语言在 YACC 项目中添加 2 个或更多操作数来为 LISP 子集构建解析器,这是语法

符号也不敏感

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
    ;

“mod”和“let”不区分大小写,我正在寻找的 了解如何使用符号表、加、减、乘、除和取模、元素列表以及声明变量 我不知道如何在代码中使用符号表。

例如,这些句子对于该语言有效:

(+ 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

欢迎任何帮助。 提前致谢。

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:
    '+' 
    |'-'    
    |'*'    
    |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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

一生独一 2024-10-12 01:06:06

嗯,我看到几个问题。

其一,我认为非终端 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

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文