Операции с YACC в C для подмножества LISP - PullRequest
1 голос
/ 26 ноября 2010

Есть ли способ добавить к 2 или более операндам в проекте YACC, используя язык C для построения синтаксического анализатора для подмножества LISP, это грамматика

"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

Любая помощь приветствуется. Заранее спасибо.

1 Ответ

1 голос
/ 26 ноября 2010

Хм, вижу несколько проблем.

Во-первых, я полагаю, что нетерминал 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
...