[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Flex-Bison string processing
From: |
Hans Aberg |
Subject: |
Re: Flex-Bison string processing |
Date: |
Tue, 5 Dec 2000 11:35:20 +0100 |
At 18:34 +0300 0-12-04, Vladimir Rykov wrote:
>Actually my problem is to parse and convert into XML file a Math notations
>like this:
>
> k <= n implies k <= n +m
>
>or
>
> (for x holds x c- X iff x c- Y ) implies X = Y
>
> ("iff" - if and only if - to and
>back and "c-" means membership)
You could write "x in X" for set membership...
For such a problem, it could be worth checking out the Internet if not
already has done the stuff you are about to embark on:
You could check MathML and XML mailing lists at http://www.w3.org/. The
comp.tex something newsgroups may provide inputs as well. There is a
package HaXml at http://www.cs.york.ac.uk/fp/HaXml/icfp99.html
for processing XML using Haskell http://haskell.org,
http://haskell.org/hugs. For use with Haskell there are parser generators
(happy)
and scanner generators (alex) available. -- Such a high level language may
be simpler to use for string processing.
For use with Flex/Bison, it might be better to use C++ instead of C,
because one can use the std::string and std::stringstream classes, which
are very convenient for handling strings.
When I used Flex with C++, I had to do some editing of the files
FlexLexer.h, flex.skl, and skel.c: Prefixing "std::" to the names
istream ostream cin cout cerr exit
(Possibly some more chasnges; I do not recall.)
Below is an example of a simple calculator for use with the Flex C++ option
& Bison. Bison outputs a .c file which should be compiled as C++; or tweak
the Bison as I suggested here or in bugs-bison, to make Bison output the
same file but with a .cc suffix.
-- Calculator.lm, flex -PCalculator ---------------------------------------
%{
#include "Calculator.h"
#define yylval Calculatorlval
#include "Calculator.tab.h"
#include <iostream>
#include <string>
#include <strstream>
%}
%option noyywrap
%option c++
digit [0-9]
number {digit}+\.?|{digit}*\.{digit}+
identifier [a-zA-Z]+
%%
[ ] { /* Skip blanks. */ }
{number} { /* sscanf(yytext, "%lf", &yylval.value); */
std::istrstream(yytext, yyleng) >> 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|\r { return '\n'; }
. { return yytext[0]; }
<<EOF>> { return Eof; }
%%
-- Calculator.y, bison --defines --name-prefix=Calculator -------------------
%{
/* Creating C++ syntax for a Bison and Flex calculator. */
#include <iostream>
#include "Calculator.h"
#define yyFlexLexer CalculatorFlexLexer
#include "FlexLexer.h"
FlexLexer* flexLexer;
inline int yylex() { return flexLexer->yylex(); }
double parse_value = 0;
%}
%token NUMBER
%token ELEMENTARY_FUNCTION
%token IDENTIFIER
%token Eof
%token EXIT
%left '+' '-'
%right ELEMENTARY_FUNCTION
%left '*' '/'
%right '^'
%right IDENTIFIER
%right UMINUS
%%
lines: lines expr '\n' { parse_value = $2.value; return 0; }
| lines expr Eof { parse_value = $2.value; return 0; }
| lines EXIT '\n' { throw Exit(0, "Exit: Bye, bye!"); }
| lines EXIT Eof { throw Exit(0, "Exit: Bye, bye!"); }
| lines '\n'
| lines Eof { throw Exit(0, "End of file."); }
|
| error '\n' { cout << "Please re-enter last line:\n";
yyerrok; }
| error Eof { throw Exit(1, "Exit: Error!"); }
;
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 }
| IDENTIFIER expr { $$.value = sqrt($2.value) }
| ELEMENTARY_FUNCTION expr { $$.value = (*$1.f)($2.value) }
| NUMBER
;
%%
Parser::Parser(std::istream* ip, std::ostream* op)
: isp(ip), osp(op)
{ lex = new yyFlexLexer(isp, osp); }
Parser::~Parser() { delete lex; }
std::istream& Parser::operator>>(double& val) {
lex->yyrestart(isp);
flexLexer = lex;
yyparse();
val = parse_value;
return *isp;
}
#if 0
#include <ctype.h>
#include <stdio.h>
#if __MWERKS__ && macintosh
#include <SIOUX.h>
#endif
int main() {
#if __MWERKS__ && macintosh
SIOUXSettings.asktosaveonclose = 0;
SIOUXSettings.autocloseonquit = 1;
#endif
return yyparse();
}
#endif
int yyerror(char* errstr) {
cerr << "Error: " << errstr << endl;
return EXIT_FAILURE;
}
-- Calculator.h --------------------------------------------------------
#ifndef Calculator_h
#define Calculator_h
#include <math.h>
#include <iostream>
#include <string>
class FlexLexer;
#if __MWERKS__ && macintosh
#include <unix.h>
#endif
typedef union calc_type {
double value;
const char* name;
double (*f)(double);
} calc_type;
#define YYSTYPE calc_type
int yyerror(char* errstr);
class Parser {
std::istream* isp; // istream being parsed
std::ostream* osp; // ostream being output to
FlexLexer* lex; // Lexical analyzer to use;
public:
Parser(std::istream* ip = 0, std::ostream* op = 0);
~Parser();
std::istream& operator>>(double&);
std::ostream& operator<<(double&);
Parser& operator>>(Parser& (*manipulator)(Parser&))
{ return manipulator(*this); }
Parser& operator<<(Parser& (*manipulator)(Parser&))
{ return manipulator(*this); }
friend Parser& operator<<(ostream& ost, Parser& parser);
friend Parser& operator>>(std::istream& ist, Parser& parser);
};
#if 0
inline std::istream& Parser::operator>>(double& val) {
val = sentence(*isp);
return *isp;
}
#endif
#if 0
inline std::ostream& Parser::operator<<(double& val) {
return (*osp) << val;
}
#endif
inline Parser& operator<<(ostream& ost, Parser& parser) {
parser.osp = &ost;
return parser;
}
inline Parser& operator>>(std::istream& ist, Parser& parser) {
parser.isp = &ist;
return parser;
}
Parser& inprompt(Parser& syn);
Parser& outprompt(Parser& syn);
class Exit {
int error;
string message;
public:
Exit(int err, string mess) : error(err), message(mess) { }
int status() { return error; }
string what() { return message; }
};
#endif
-- main.cc ----------------------------------------------------------------
// Creating C++ syntax for a Bison and Flex calculator.
#include <cstdlib>
#include <fstream>
#include <iostream>
#include "Calculator.h"
#if __MWERKS__ && macintosh
#include <SIOUX.h>
#endif
int main() {
#if __MWERKS__ && macintosh
SIOUXSettings.asktosaveonclose = 0;
SIOUXSettings.autocloseonquit = 0;
#endif
Parser calc;
double d;
std::ifstream ifs("Input", ios_base::in | ios_base::binary);
if (!ifs)
cout << "Could not open input file." << endl;
else {
// ifs.exceptions(ios_base::eofbit);
// while (ifs && !ifs.eof())
try { for (;;) {
ifs >> calc >> d;
std::cout << d << endl;
}
}
catch (Exit& ex) {
std::cout << ex.what() << endl;
std::cout << "Status: " << ex.status() << endl;
}
catch (...) {
cout << "Exception: ..." << endl;
}
}
while (cin) {
try {
std::cin >> calc >> d;
std::cout << d << endl;
}
catch (Exit& ex) {
std::cout << ex.what() << endl;
return ex.status();
}
}
return EXIT_SUCCESS;
}
--------------------------------------------------------------------------
Hans Aberg