views:

318

answers:

5

Now I'm getting other things. When I do a bison -d calc.y I'm getting many source codes in the console (with many m4_define), but it doesn't generate any file. Now my code is like this:

%{
#define YYSTYPE double
#include <math.h>
%}
%token NUM
%%
input:    /* empty */
        | input line
;

line:     '\n'
        | exp '\n'  { printf ("\t%.10g\n", $1); }
;

exp:      NUM             { $$ = $1;         }
        | exp exp '+'     { $$ = $1 + $2;    }
        | exp exp '-'     { $$ = $1 - $2;    }
        | exp exp '*'     { $$ = $1 * $2;    }
        | exp exp '/'     { $$ = $1 / $2;    }
      /* Exponentiation */
        | exp exp '^'     { $$ = pow ($1, $2); }
      /* Unary minus    */
        | exp 'n'         { $$ = -$1;        }
;
%%

/* Lexical analyzer returns a double floating point 
   number on the stack and the token NUM, or the ASCII
   character read if not a number.  Skips all blanks
   and tabs, returns 0 for EOF. */

#include <ctype.h>
#include <stdio.h>

yylex ()
{
  int c;

  /* skip white space  */
  while ((c = getchar ()) == ' ' || c == '\t')  
    ;
  /* process numbers   */
  if (c == '.' || isdigit (c))                
    {
      ungetc (c, stdin);
      scanf ("%lf", &yylval);
      return NUM;
    }
  /* return end-of-file  */
  if (c == EOF)                            
    return 0;
  /* return single chars */
  return c;                                
}

yyerror (s)  /* Called by yyparse on error */
     char *s;
{
  printf ("%s\n", s);
}

main ()
{
  yyparse ();
}


Original Question

I'm trying to create my own development language, but it's so hard to start and as I'm starting, I'm getting many errors and I don't know how to solve the. This is my code:

#include <ctype.h>
#include <stdio.h>

yylex ()
{
  int c;

  /* skip white space  */
  while ((c = getchar ()) == ' ' || c == '\t')  
    ;
  /* process numbers   */
  if (c == '.' || isdigit (c))                
    {
      ungetc (c, stdin);
      scanf ("%lf", &yylval);
      return NUM;
    }
  /* return end-of-file  */
  if (c == EOF)                            
    return 0;
  /* return single chars */
  return c;                                
}

main ()
{
  yyparse ();
}

The calc.y source code file:

%token NUM
%%
input:
        | input line
;

line:     '\n'
        | exp '\n'  { printf ("\t%.10g\n", $1); }
;

exp:      NUM             { $$ = $1;         }
        | exp exp '+'     { $$ = $1 + $2;    }
        | exp exp '-'     { $$ = $1 - $2;    }
        | exp exp '*'     { $$ = $1 * $2;    }
        | exp exp '/'     { $$ = $1 / $2;    }
      /* Exponentiation */
        | exp exp '^'     { $$ = pow ($1, $2); }
      /* Unary minus    */
        | exp 'n'         { $$ = -$1;        }
;
%%

And now the compiler log:

C:\Documents and Settings\Nathan Campos\Desktop>gcc calc.tab.c -lm -o rpcalc
calc.tab.c: In function `yylex':
calc.tab.c:15: error: `yylval' undeclared (first use in this function)
calc.tab.c:15: error: (Each undeclared identifier is reported only once
calc.tab.c:15: error: for each function it appears in.)
calc.tab.c:16: error: `NUM' undeclared (first use in this function)

What is wrong?

A: 

You have not declared the variable yylval anywhere.

Chris Ballance
+1  A: 

In your .y file add these lines:

void yyerror(char *errorinfo);
int yylex(void);

You'll also need to define your token types as generated by flex:

%token NUM

and so on.

Edit: Flex and Bison (O'Reilly) is a great resource.

Jim Ferrans
I know that this is very simple(remember that i'm beginning), but where i need to add those lines and i need to have flex installed? Thanks.
Nathan Campos
There are quite a few examples out there, this one looks good: http://www.mail-archive.com/[email protected]/msg00156.html
Jim Ferrans
The error list didn't mention either of these - I don't think that's the (immediate) problem.
Steve314
You're right @Steve314: as you point out in your reply YYSTYPE solves the yylex() issue (though %token NUM solves the one on line 16).
Jim Ferrans
+4  A: 

Revised answer

The amended code you provide compiles almost cleanly - you should #include <stdio.h> so that printf() is declared before it is used. (You should also use prototypes for functions - such as yyerror(const char *str), and generally drag the code into the 21st Century.)

It even responds correctly to '1 2 +'.

With a single file, you don't need to use 'bison -d'.

If you are seeing garbage, you need to review your build commands and build environment.


Original answer

Where to begin?

Recommendation: get hold of the O'Reilly book on Lex and Yacc (from the library) or Flex and Bison (an August 2009 update/rewrite - probably not in the library yet). If you need a resource quicker, then I suggest the Unix Version 7 manuals or the GNU Bison manual - both of which are available online. In particular, read the 7th edition documents on Lex and Yacc; you're not trying to do what wasn't covered in the original decriptions (though the C code there pre-dates the C89 standard by a decade or more).

  • You need to use bison -d to generate a header containing the token numbers. For source file 'zzz.y', this will generate C code 'zzz.tab.c' and 'zzz.tab.h'.
  • You need to include 'zzz.tab.h' in the main program.
  • You need to use C99 and should, therefore, have a return type on yylex() and main().
  • You need to declare yylval. Fortunately, the Bison 'zzz.tab.h' file will do that correctly; it isn't quite as simple as it appears.
  • You may want to allow for negative numbers in your lexical analyzer (-3.1416). You may want to allow for explicitly positive numbers too (+3.1416).
  • You probably need to ensure that '$$' and friends are of type double rather than the default type of int (#define YYSTYPE double).
Jonathan Leffler
See the comments on @Steve314 post. Thanks.
Nathan Campos
Flex and Bison is an excellent book.
acidzombie24
+2  A: 

IIRC, yylval is declared by Bison, but you have to supply the type. Without that, the compiler gets confused and can give misleading errors.

You need to define YYSTYPE. In your case, you may get away with "#define YYSTYPE double". Do this in the grammar, in a %{ ... %} block near the top.

%union is also available for declaring YYSTYPE as a union.

This looks like the Bison manual standard rpcalc example, so I'll assume you can look up "YYSTYPE" and "%union" easily enough.

Steve314
Yes it's the rpcalc example :), but i declared this as in the rpcalc tutorial, but when i do a bison -d calc.y i only got many and many lines with codes and any new file. **What is wrong, it doesn't created the *.h file?**
Nathan Campos
OK - I see, you're compiling the main program and parser as separate .c files. I have to admit - it's a while since I used it, and I forgot how you do that.
Steve314
I suggest posting 'Part 2' to your question based on what you've got now. I'd probably put 'Part 2' at the top - and add a note that the original question 'Part 1' is below (I'd separate the two parts with a horizontal rule). But you should also take the time to read the manuals - it will end up being quicker than experimenting your way to a semi-workable solution.
Jonathan Leffler
A: 

It is not a good idea to #define YYSTYPE. It certainly doesn't work with the Bison I tried it with. What you should do is to tell Bison that the values you work with are doubles:

%union {
    double dval;
}

%type <dval> exp NUM

Bison will now generate an appropriate YYSTYPE for you.

But I recommend that you look at a tutorial or something. Thomas Niemann's A Compact Guide to Lex & Yacc is a good one, giving examples and step-by-step explanations. I teach a compiler course, and my experience is that Bison, and grammars, can be difficult to get started with by too much of trial-and-error.

Thomas Padron-McCarthy