Josue Espinosa Josue Espinosa - 18 days ago 4
C Question

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

I'm trying to build a calculator using lex/yacc where you can create an unlimited amount of variables and use them in calculations by using a linked list.

When you type "?", it should print out the contents of the linked list, it does do this, except afterwards, it gives me a:

syntax error
and ends my program.

The rest of the calculator works as expected, am I missing something?

Sample Output

-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;
}
}

Answer

The problem

Your grammar doesn't recognize an empty line as a valid input. When you type ? followed by a newline, the newline is returned, and that isn't syntactically valid, hence the 'syntax error' report.

You could demonstrate by typing ?a + b as an input, for example.

Note that your lexical analyzer processes the ? without letting the parser know that it happened; the parser never sees the ?.

Prodding to get enough information to make the question answerable

This adaptation of your Lex code shows that the lexical analyzer recognizes ? as an input. Your question doesn't show how the code is used, so there's not enough information for us to know what you're doing wrong. You need to provide an MCVE (Minimal, Complete, Verifiable Example) so that you can get the relevant help.

%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;
}

Sample run (shell prompt is JL: rather than $ because one of the inputs is $):

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

?
Got a ?
Other: 

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

$
Dollar
JL: