0
votes

I have this yacc file

%error-verbose
%token  END
%token  ID
%token  INT
%token  IF
%token  ELSE
%token  WHILE
%token  FOR
%token  BREAK
%token  CONTINUE
%token  RETURN
%token  SEM
%token  LPAR
%token  RPAR
%token  PLUS
%token  MINUS
%token  MULT
%token  DIV
%token  MOD
%token  GT
%token  LT
%token  GTE /* >= */
%token  LTE /* <= */
%token  EQUAL   /* == */
%token  NEQUAL  /* != */
%token  AND
%token  OR
%token  EQ
%token  COM
%token PRINT 
%token READ
%token FLOAT
%token LABR
%token RABR
%token NUM
%token STR


/*
 *  precedentce tabLTE
 */

%right  EQ PE ME TE DE RE
%left   OR
%left   AND
%left   EQUAL NEQUAL
%left   LT GT GTE LTE
%left   PLUS MINUS
%left   MULT DIV MOD
%right  PP MM
%{
#include<stdio.h>
extern char *yyname;
extern char *yytext;
extern int yylineno;
void yyerror(char const *msg)
{
fprintf(stderr,"%s:%d:%s\n", yyname,yylineno,msg);

}
%}
%%
program
    : definitions
    ;
definitions
    : definition
    | definitions definition
    ;
definition:
    | declaration
    ;
declarations
    : /* null */
    | declarations declaration
    ;
declaration
    : INT declarator_list SEM
    ;

declarator_list
    : ID
    | declarator_list COM ID
    ;
statements
    : /* null */
    | statements statement
    ;
statement
    : expression SEM
    | SEM   /* null statement */
    | if_prefix statement
    | if_prefix statement ELSE statement
    | loop_prefix statement
    ;
if_prefix
    : IF LPAR expression RPAR
    ;
loop_prefix
    : WHILE LPAR expression RPAR
    ;
expression
    : binary
    | expression COM binary
    ;
binary
    : ID
    | LPAR expression RPAR
    | ID LPAR optional_argument_list RPAR
    | binary PLUS binary
    | binary MINUS binary
    | binary MULT binary
    | binary DIV binary
    | binary MOD binary
    | binary GT binary
    | binary LT binary
    | binary GTE binary
    | binary LTE binary
    | binary EQUAL binary
    | binary NEQUAL binary
    | binary AND binary
    | binary OR binary
    | ID EQ binary
    | ID PE binary
    | ID ME binary
    | ID TE binary
    | ID DE binary
    | ID RE binary
    ;
optional_argument_list
    : /* no actual arguments */
    | argument_list
    ;
argument_list
    : binary
    | argument_list COM binary
    ;

%%

#include <stdlib.h>
extern FILE *yyin;
int main(int argc, char **argv)
{
    int ok;
    if (argc != 2) {
        fprintf(stderr, "%s: Wrong arguments\n", argv[0]);
        return EXIT_FAILURE;
    }
    yyname = argv[1];
    if ((yyin = fopen(yyname, "r")) == NULL) {
        fprintf(stderr, "%s: %s: Invalid file\n", argv[0], argv[1]);
        return EXIT_FAILURE;
    }
    return (yyparse() ? EXIT_SUCCESS : EXIT_FAILURE);
}

when the input is int x; everything works fine, but when the input is something other than "INT" lets say FOR it throws an error: unexpected FOR expecting INT or $end so it's actually reading only the first rule from the set of rules.. Besides, it keeps showing useless non terminals and terminals warning when bison command is applied.

What is wrong with this yacc file?

2
Your global edit of 'le' to 'LTE' did too much with /* * precedentce tabLTE */ (spread over 3 lines). 'Precedence' contains no 't', either.Jonathan Leffler

2 Answers

2
votes

The trouble is that the rules:

program
    : definitions
    ;
definitions
    : definition
    | definitions definition
    ;
definition:
    | declaration
    ;
declarations
    : /* null */
    | declarations declaration
    ;
declaration
    : INT declarator_list SEM
    ;

only allow declarations through; nothing allows statements as part of a program. Your FOR is not a declaration, so the grammar rejects it.

The 'useless non-terminals' warning is trying to tell you:

You have goofed big time; there is a bug in your grammar. You have tried to write rules for some production, but you never let it be recognized, so there was no point in adding it.

Or thereabouts...

Maybe you need:

program
    : definitions statements
    ;

Or maybe you need to allow functions as a definition too, and then the FOR statement will be part of the body of a function.

0
votes

Asking my LL oracle about your amended grammar:

Out of 15 non-terminals, 14 are reachable, 1 are unreachable:
'declarations'
Circular symbols:
definitions
definitions

The complaint about circular symbols means that 'definitions' can derive itself. For example, 'definitions' can produce 'definitions definition', but 'definition' is nullable, so 'definitions' can produce just itself, kinduva infinite loop few parser generators care to deal with in any sensible way. Looking at it another way, you've defined 'definitions' to be a list of nullable symbols, so how many epsilons would you like to match? How about infinity? :-)

This is a drawback of the yacc/bison style of trying to produce some parser even if there are problems in the grammar; quite convenient if you know exactly what you're doing, but quite confusing otherwise.

But, to the narrow point of what to do about the grammar circularity that's giving you a very unuseful (but by gum compilable!) parser. How about you allow 'definitions' be nullable but not 'definition'? IOW:

definitions : | definitions definition ;
definition : declaration ;

Try to not stack nullability on top of nullability. So when you later change to:

definition : declarations ;

Don't make 'declarations' nullable (that's already handled by 'definitions' being nullable). Instead, change it to:

declarations : declaration | declarations declaration ;

That should get you past the immediate problem and onto some new ones :-)