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

Simple Lex/Yacc syntax error matching a single question mark?

我正在尝试使用 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 = ->name;
        if (strcmp(name, "PI") != 0 && strcmp(name, "PHI") != 0) {
            ->value = ; 
        } else {
            yyerror("assign to const"); 
        }
    }
    | expression { printf("= %g\n", ); }
    ;

expression
    : expression '+' expression { $$ =  + ; }
    | expression '-' expression { $$ =  - ; }
    | expression '*' expression { $$ =  * ; }
    | expression '/' expression { 
        if ( == 0) {
            yyerror("divide by zero");
        } else { 
            $$ =  / ; 
        }
    }
    | '-' expression %prec UMINUS { $$ = -; }
    | '(' expression ')' { $$ = ; }
    | NUMBER
    | NAME { $$ = ->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;
    }
}

问题

您的语法无法将空行识别为有效输入。当您键入 ? 后跟一个换行符时,将返回换行符,这在语法上是无效的,因此会出现 'syntax error' 报告。

例如,您可以通过键入 ?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:

那个?后跟一个作为字符标记返回的换行符,但您的语法只接受语句后的换行符,该语句始终以 NAME 开头。