help-bison
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Changing input and capturing output


From: Hans Aberg
Subject: Re: Changing input and capturing output
Date: Mon, 5 Aug 2002 19:51:36 +0200

At 12:47 -0400 2002/08/05, Donges, William E.,, III wrote:
>Well after a weekend of pounding my head against the keyboard I do not
>feel I am any closer to solving this problem.

>What I need to do:
>1. Take this string literals find the mathematics.
>2. Evaluate the resultant mathematical expression.
>3. Then return the resulting float the int portion of which can be reused.
>  (Or else it should do int math to begin with).

Your problem sounds pretty straight-forward. Solutions in C++ and C are the
essentially the same, except that one can do fewer things in C, for
example, there is a problem with cleanup in C (but later versions of Bison
is supposed t support that).

I include a full example below, which is in C++, but it should be easy to
modify to C. There are three files Calculator.h header, Bison Calculator.y
(compiled with --defines --name-prefix=Calculator), and Flex Calculator.l
(compiled with -PCalculator -a -I). I include the Flex code, in case you
would later want to use it. Flex support at
  Help-flex mailing list
  address@hidden
  http://mail.gnu.org/mailman/listinfo/help-flex

You have otherwise fixed the problem of reading the string.

This is a calculator that merely prints the value, just as in the Bison
manual. If you instead want to keep the value internally, modify the .y
file:

%{
...
double value;
...
%}

%token NUMBER
...
%%
lines:  lines expr '\n'   { value = $2.value; }
...

As you see, this rule now merely writes the value into the global variable
"value". So you can later use that in any file:
    extern double value;
As set up, this value will only be modifed when there has been a successful
parse.

As for the problem of deflecting the output, have a look in the file
bison.simple, or the output parser file: There it conditionally (#ifndef)
defines macros which it uses for the output. For example, YYFPRINTF. Thus,
you can merely define that to something else. There is otherwise a nice
Bison option --verbose that produces more detailed error messages.

If you have hooked up yylex to only read from a string, then there should
be no input reading, as the Bison generated parser itself does not read in
any streams, but only parses the token numbers that yylex hands over to it..

--- Calculator.h: -------------------------------------------------------

#ifndef Calculator_h
#define Calculator_h

#include <math.h>
#include <string>

typedef union calc_type {
        double value;
        const char* name;
        double (*f)(double);
} calc_type;

#define YYSTYPE calc_type

int yyerror(char* errstr);
int yylex();

#endif


--- Calculator.y: -----------------------------------------------------

%{
  /* A C++ Bison and Flex calculator. */

#include "Calculator.h"

#include <iostream>


%}

%token NUMBER
%token ELEMENTARY_FUNCTION
%token IDENTIFIER
%token EXIT

%left '+' '-'
%right ELEMENTARY_FUNCTION
%left '*' '/'
%right '^'
%right UMINUS

%%
lines:  lines expr '\n'   { printf("%.12g\n", $2.value) }
  | lines '\n'
  | lines EXIT '\n'   { return EXIT_SUCCESS; }
  | /* empty */
  | error '\n'    { printf("Please re-enter last line: ");
                      yyerrok; }
  ;

expr: expr '+' expr { $$.value = $1.value + $3.value }
  | expr '-' expr { $$.value = $1.value - $3.value }
  | expr '*' expr { $$.value = $1.value * $3.value }
  | expr '/' expr { $$.value = $1.value / $3.value }
  | expr '^' expr { $$.value = pow($1.value, $3.value) }
  | '(' expr ')'  { $$.value = $2.value }
  | '-' expr  %prec UMINUS { $$.value = -$2.value }
  | ELEMENTARY_FUNCTION expr  { $$.value = (*$1.f)($2.value) }
  | NUMBER
  ;

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

int main() {
#if __MWERKS__ && macintosh
  SIOUXSettings.asktosaveonclose = 0;
  SIOUXSettings.autocloseonquit = 1;
#endif
  std::ios::sync_with_stdio();
  return yyparse();
}

int yyerror(char* errstr) {
  printf("Error: %s\n", errstr);
  return EXIT_FAILURE;
}

--- Calculator.l: ------------------------------------------------------------


%{

#include "Calculator.h"

#define yylval Calculatorlval

#include "Calculator.tab.h"

%}

%option noyywrap

digit   [0-9]
number    {digit}+\.?|{digit}*\.{digit}+
identifier  [a-zA-Z]+

%%

[ ]      { /* Skip blanks. */ }
{number}   { sscanf(yytext, "%lf", &yylval.value);
         return NUMBER; }
"sqrt"     { yylval.f = &sqrt; return ELEMENTARY_FUNCTION; }
"exp"    { yylval.f = &exp; return ELEMENTARY_FUNCTION; }
"log"    { yylval.f = &log; return ELEMENTARY_FUNCTION; }
"exp2"     { yylval.f = &exp2; return ELEMENTARY_FUNCTION; }
"log2"     { yylval.f = &log2; return ELEMENTARY_FUNCTION; }
"exit"     { return EXIT; }
{identifier} { yylval.name = std::string(yytext, yyleng).c_str(); return
IDENTIFIER; }
\n|.     { return yytext[0]; }

%%


----------------------------------------------------------------

  Hans Aberg





reply via email to

[Prev in Thread] Current Thread [Next in Thread]