简单的Lex / Yacc语法错误匹配单个问号?

时间:2016-11-22 02:47:15

标签: c bison flex-lexer yacc lex

我正在尝试使用lex / yacc构建计算器,您可以使用链接列表创建无限量的变量并在计算中使用它们。

当你输入“?”时,它应该打印出链表的内容,它会这样做,除了之后,它给我一个:syntax error并结束我的程序。

计算器的其余部分按预期工作,我错过了什么?

示例输出

-bash-4.1$ ./calc
a = 42
b = 21
c = a / b
?
num-syms: 5
    PHI => 1.61803
    PI => 3.14159
    a => 42
    b => 21
    c => 2
syntax error
-bash-4.1$ 

sym.h

#ifndef SYMTBL_H
#define SYMTBL_H

struct sym {
    int length;
    char * name;
    double value;
    struct sym *prev;
    struct sym *next;
};

struct sym * sym_p;
struct sym * sym_lookup(char *);
void sym_inventory();

#endif /* SYMTBL_H */

calc.l

%{
/*#include <math.h> */ 
#include "y.tab.h"
#include "sym.h"
%}

%%
"?" { sym_inventory(); }

([0-9]+|([0-9]*\.[0-9]+)([eE][+-]?[0-9]+)?) {
    yylval.dval = atof(yytext);
    return NUMBER;
    }

[ \t] ; /* ignore whitespace */

[A-Za-z][A-Za-z0-9]* {
    /* return symbol pointer */
    yylval.symptr = sym_lookup(yytext);
    return NAME;
    }

"$" { return 0; }
\n |
. { return yytext[0]; };
%%
int yywrap() { return 1; }

calc.y

%{
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "sym.h"
%}

%union {
    double dval;
    struct sym * symptr;
}

%token <symptr> NAME
%token <dval> NUMBER
%left '-' '+'
%left '*' '/'
%nonassoc UMINUS

%type <dval> expression
%%
statement_list
    : statement '\n'
    | statement_list statement '\n'
    ;

statement
    : NAME '=' expression { 
        char *name = $1->name;
        if (strcmp(name, "PI") != 0 && strcmp(name, "PHI") != 0) {
            $1->value = $3; 
        } else {
            yyerror("assign to const"); 
        }
    }
    | expression { printf("= %g\n", $1); }
    ;

expression
    : expression '+' expression { $$ = $1 + $3; }
    | expression '-' expression { $$ = $1 - $3; }
    | expression '*' expression { $$ = $1 * $3; }
    | expression '/' expression { 
        if ($3 == 0) {
            yyerror("divide by zero");
        } else { 
            $$ = $1 / $3; 
        }
    }
    | '-' expression %prec UMINUS { $$ = -$2; }
    | '(' expression ')' { $$ = $2; }
    | NUMBER
    | NAME { $$ = $1->value; }
    ;

%%

struct sym * sym_lookup(char * s)
{
    if (sym_p == NULL) {
        sym_p = (struct sym *)malloc(sizeof(struct sym));
    }

    struct sym *original = sym_p;
    struct sym * sp = sym_p;

    if (sp->name == NULL) {
        struct sym *n = (struct sym *)malloc(sizeof(struct sym));
        n->name = "PI";
        n->value = 3.14159;
        n->next = NULL;
        sp->name = "PHI";
        sp->value = 1.61803;
        sp->next = n;
        sp->length = 2;
    }

    while (1) {
        if (sp->name == NULL) {
            sp->name = strdup(s);
            sp->next = NULL;
            return sp;
        } else if (strcmp(sp->name, s) == 0) {
            return sp;
        } else if (sp->next != NULL) {
            sp = sp->next;
        } else {
            struct sym *n = (struct sym *)malloc(sizeof(struct sym));
            n->name = strdup(s);
            sp = original;
            struct sym *old = NULL;

            while (1) {
                if (strcmp(sp->name, s) > 0) {
                    // new variable name comes before in ascii table
                    if (old == NULL) {
                        // new node insert at beginning of sym_p
                        n->next = original;
                        n->length = original->length;
                        sym_p = n;
                        original = sym_p;
                        sp = original;
                    } else {
                        // insert in middle and update links
                        old->next = n;
                        n->next = sp;
                        sp = original;
                    }
                    break;
                } else {
                    if (sp->next != NULL) { 
                        old = sp;
                        sp = sp->next;
                    } else {
                        sp->next = n;
                        break;
                    }
                }
            }
            sp = original;
            sp->length++;
            return n;
        }
    }
}

void sym_inventory()
{
    struct sym * sp = sym_p;
    printf("num-syms: %d\n", sp->length);
    int i;
    int length = sp->length;
    for (i = 0; i < length; i++) {
        printf("\t%s => %g\n", sp->name, sp->value);
        sp = sp->next;
    }
}

2 个答案:

答案 0 :(得分:1)

问题

您的语法无法将空行识别为有效输入。当您键入?后跟换行符时,会返回换行符,这在语法上无效,因此会出现“语法错误”报告。

例如,您可以通过键入?a + b作为输入进行演示。

请注意,您的词法分析器会处理?,而不会让解析器知道它发生了;解析器永远不会看到?

努力获取足够的信息以使问题回答

Lex代码的这种改编表明词法分析器将?识别为输入。您的问题没有显示代码的使用方式,因此我们没有足够的信息来了解您的错误。您需要提供MCVE(Minimal, Complete, Verifiable Example),以便获得相关帮助。

%option noinput
%option nounput
%%
"?" { printf("Got a ?\n"); }

([0-9]+|([0-9]*\.[0-9]+)([eE][+-]?[0-9]+)?) {
    printf("Number: %s\n", yytext);
    }

[ \t] { printf("Space: [%s]\n", yytext); }

[A-Za-z][A-Za-z0-9]* {
    printf("Name: %s\n", yytext);
    }

"$" { printf("Dollar\n"); return 0; }
\n |
. { printf("Other: %c\n", yytext[0]); return yytext[0]; };
%%
int yywrap(void) { return 1; }

int main(void)
{
    while (yylex() != 0)
        ;
    return 0;
}

示例运行(shell提示符为JL:而非$,因为其中一个输入为$):

JL: ./xy73
a b 23
Name: a
Space: [ ]
Name: b
Space: [ ]
Number: 23
Other: 

?
Got a ?
Other: 

=@%
Other: =
Other: @
Other: %
Other: 

$
Dollar
JL:

答案 1 :(得分:1)

?后面跟一个换行符作为字符标记返回,但是你的语法只接受一个语句后的换行符,该语句总是以NAME开头。