home *** CD-ROM | disk | FTP | other *** search
- /*******************************************************
-
- The CalcPlus Class Library Version 1.0,
- Author: Vladimir Schipunov, Copyright (C) 1996
-
- This library is free software. Permission to use,
- copy, modify and redistribute the CalcPlus library
- for any purpose is hereby granted without fee,
- provided that the above copyright notice appear
- in all copies.
-
- *******************************************************/
-
- #include <iostream.h>
- #include <fstream.h>
- #include <string.h>
- #include <stdlib.h>
- #include <ctype.h>
- #if !defined(_MSC_VER) && !defined(__WIN32__)
- #include <strstream.h>
- #else
- #include <strstrea.h>
- #endif
- #include "calclex.h"
- #include "yytab.h"
-
- static KeyDef KeyData[] =
- {
- { "FUNCTION", lxFunc },
- { "PROCEDURE", lxProc },
- { "FUNC", lxFunc },
- { "PROC", lxProc },
- { "AND", lxAnd },
- { "OR", lxOr },
- { "VAR", lxVar },
- { "ECHO", lxEcho },
- { "IF", lxIf },
- { "THEN", lxThen },
- { "ELSE", lxElse },
- { "ENDL", lxEndl },
- { "TRUE", lxTrue },
- { "FALSE", lxFalse },
- { "BEGIN", lxBegin },
- { "END", lxEnd },
- { "WHILE", lxWhile },
- { "DO", lxDo },
- { "FOR", lxFor },
- { "TO", lxTo },
- { "LOOP", lxLoop },
- { "STEP", lxStep },
- { "RETURN", lxRet },
- { "EXIT", lxExit },
- { "CONST", lxConst },
- { "STRUCT", lxStruct },
- { "NIL", lxNil },
- { "NOT", lxNot },
- { "INCLUDE", lxInclude },
- { "DEFINE", lxDefine },
- { "UNDEF", lxUndef },
- { "IFDEF", lxIfdef },
- { "IFNDEF", lxIfndef },
- { "ENDIF", lxEndif }
- };
-
- Keywords Keywords::Dictionary;
- Keyword::~Keyword(){}
- Keywords::Keywords()
- {
- for( int i = 0; i < sizeof( KeyData )/sizeof( KeyData[0] ); i++ )
- {
- KeyDef& d = KeyData[i];
- Add( new Keyword( d.token, d.lex ));
- }
- }
-
- YLex::yylex()
- {
- if( !in && NextStream())
- return lxEof;
- __whitespace();
- c = GetChar();
- if( !in || in->eof()) return lxEof;
- if( isalpha(c) || c == '_' || c == '@' ) return __name();
- switch( c )
- {
- case '{': case '}': case '.':
- case '[': case ']': case ')':
- case '&': case '*': case '(': case '!':
- case ';': case ',': case '^': case '=':
-
- return *pyylval()=c;
- case '#': return __preprocessor();
- case '/': return __comment();
- case ':': return __assignment();
- case '-': return __implication();
- case '+': return __increment();
- case '<': case '>': return __comparison();
- case '"': case '\'': return __string();
-
- case '0':
- case '1': case '2': case '3':
- case '4': case '5': case '6':
- case '7': case '8': case '9': return __number();
- }
- return lxBadToken;
- }
-
- void YLex::yyerror
- (
- const char* s1,
- const char* s2,
- const char* s3
- )
- {
- if( Skipping || errors->NumObj > 10 )
- return;
- if( errors->NumObj == 10 )
- {
- s1 = "too many errors";
- s2 = s3 = "";
- }
- ListIdx i( *errors );
- for( ; i; i++ )
- if(((SyntaxError*)i.obj)->line == (lexstr ? lexstr->line : 0 ))
- return;
- SyntaxError* p = new SyntaxError( s1, s2, s3 );
- p->line = lexstr ? lexstr->line : 0;
- errors->Add( p );
- }
-
- LStream* YLex::lexstr;
-
- YLex::YLex( const char *i ) :
- in( 0 ), input( 0 ), Macros( 1 ),
- IfDefSP( 0 ), Skipping( 0 )
- {
- errors = new LexList;
- defines = new LexList;
- if( i )
- File( i );
- }
-
- void YLex::File( const char* i, int Undef )
- {
- if( !input )
- input = new LexStack( 0 );
- input->Push( new LSFile( i, Undef ));
- }
-
- YLex::~YLex()
- {
- delete errors;
- delete input;
- delete defines;
- }
-
- YLex::NextStream()
- {
- if( !input )
- return 1;
- LStream* s = (LStream*)input->Last();
- if( !s )
- return 1;
- if( s->dirty && !s->in->eof() ||
- !s->dirty && !s->Open())
- {
- s->dirty = 1;
- in = s->in;
- lexstr = s;
- return 0;
- }
- if( s->UndefAll())
- {
- delete defines;
- defines = new LexList;
- }
- if( s->isFile() && IfDefSP )
- {
- Skipping = 0;
- yyerror("unclosed ifdef directive");
- }
- input->Pop();
- lexstr = 0;
- in = 0;
- return NextStream();
- }
-
- char YLex::GetChar()
- {
- if( !in && NextStream())
- return lxEof;
- char c;
- *in >> c;
- if( in->eof())
- return NextStream() ? (char)lxEof : GetChar();
- lexstr->pos++;
- lexstr->begline = lexstr->begline &&
- (c =='\n' || c=='\t' || c=='\v' || c==' ' || c=='#');
- return c;
- }
-
- void YLex::PutBack( char c )
- {
- in->putback(c);
- if( lexstr )
- lexstr->pos--;
- }
-
- void YLex::NextLine()
- {
- lexstr->pos = 0;
- lexstr->line++;
- lexstr->begline = 1;
- }
-
- YLex::TokenProc( int isProc )
- {
- return isProc ? yyProc : yyFunc;
- }
-
- Token YLex::__number()
- {
- int dot = 0, exp = 0, done = 0;
- for( int i = 0; i < sizeof(Lex); i++, c = GetChar() )
- {
- Lex[i] = c;
- switch(c)
- {
- case '0':
- case '1': case '2': case '3':
- case '4': case '5': case '6':
- case '7': case '8': case '9': break;
-
- case 'e':
- case 'E':
- {
- exp++;
- if( dot == 1 ) dot = 0;
- c = GetChar();
- if( c == '-' || c == '+' )
- Lex[++i] = c;
- else
- PutBack(c);
- break;
- }
- case '.': { dot++; break; }
-
- default:
- {
- PutBack(c);
- done = 1;
- Lex[i] = 0;
- if( i > MaxIdLength )
- return lxBadToken;
- break;
- }
- }
- if( done ) break;
- }
-
- if( dot > 1 || exp > 1 || dot && exp )
- return lxBadToken;
-
- double tmp = atof(Lex);
- if( exp || dot )
- {
- YYLVAL(tmp);
- return lxReal;
- }
- else
- {
- #define MAXLONG 0x7FFFFFFFL
- static long MaxInt = MAXLONG, MinInt = -MAXLONG;
- if( tmp > MaxInt || tmp < MinInt )
- return lxBadToken;
- long v = (long)tmp;
- YYLVAL(v);
- return lxInt;
- }
- }
-
- Token YLex::__name()
- {
- Lex[MaxIdLength] = 0;
- for( int i = 0; i <= MaxIdLength; i++, c = GetChar() )
- {
- if( i == MaxIdLength )
- return lxBadToken;
-
- if( isalpha(c) || isdigit(c) || c == '_' ||
- c == '@' && !i || i && *Lex=='@' && c=='.' )
- {
- Lex[i] = c;
- continue;
- }
- else
- {
- PutBack(c);
- Lex[i] = 0;
- break;
- }
- }
- LOOKUP( Keywords::Dictionary, Keyword );
- if( Macros && __macro( Lex ))
- return yylex();
- char *p = Lex;
- YYLVAL(p);
- return lxName;
- }
-
- Token YLex::__comparison()
- {
- char c1 = c, c2;
- c2 = GetChar();
- return c2 == '=' ? ( c1 == '<' ? lxLe : lxGe ) :
- c1 == '<' && c2 == '>' ? lxNe : ( PutBack(c2), c1 );
- }
-
- Token YLex::__assignment()
- {
- c = GetChar();
- if( c == '=' )
- return lxAssign;
- PutBack(c);
- return (Token)':';
- }
-
- Token YLex::__implication()
- {
- c = GetChar();
- if( c == '>' )
- return lxImp;
- if( c == '=' )
- return lxDec;
- PutBack(c);
- return (Token)'-';
- }
-
- Token YLex::__increment()
- {
- c = GetChar();
- if( c == '+' )
- return lxInc;
- PutBack(c);
- return (Token)'+';
- }
-
- Token YLex::__comment()
- {
- c = GetChar();
- if( c == '*' )
- {
- while( !in->eof() )
- {
- if( c = GetChar(), c == '*' )
- if( c = GetChar(), c == '/')
- break;
- if( c == '\n' )
- NextLine();
- }
- return (Token)yylex();
- }
- if( c == '/' )
- {
- while( !in->eof() )
- {
- c = GetChar();
- if( c != '\n' )
- continue;
- NextLine();
- return (Token)yylex();
- }
- }
- PutBack(c);
- return (Token)'/';
- }
-
- void YLex::__whitespace()
- {
- while( in && !in->eof() )
- {
- c = GetChar();
- if( c == '\n' ) NextLine();
- if( c != '\n' && c != '\t' && c != '\v' && c != ' ' )
- {
- if( c!=lxEof && (unsigned char)c!=0xFF )
- PutBack( c );
- break;
- }
- }
- }
-
- Token YLex::__string()
- {
- in->getline(Lex,sizeof(Lex)-1,c);
- #ifdef __ZTC__
- int n = strlen( Lex );
- if( n>0 )
- Lex[ n-1 ] = 0;
- #endif
- char *p = Lex;
- YYLVAL(p);
- return lxString;
- }
-
- #define DEFEXIT { yyerror("error in definition"); return; }
- void YLex::__definition()
- {
- Macros = 0; Token t = yylex(); Macros = 1;
- if( t==lxName && (*defines)( Lex ))
- {
- yyerror("redefinition of symbol ", Lex );
- return;
- }
- if( t!=lxName && t!=yyVar &&
- t!=yyConst && t!=yyStruct )
- DEFEXIT;
- for( *in >> c; c==' ' || c=='\t'; *in >> c ){}
- if( in->eof() || c=='\n' )
- {
- defines->Add( new LexDefine( Lex ));
- return;
- }
- if( c=='(' )
- {
- int i;
- for( i = strlen( Lex ); c!=')' &&
- i < sizeof( Lex ); *in >> c )
- {
- if( in->eof() || c=='\n' )
- DEFEXIT;
- Lex[i++] = c;
- }
- Lex[i++] = c;
- Lex[i] = 0;
- }
- else
- in->putback( c );
- LexDefine* def = new LexDefine( Lex );
- defines->Add( def );
- for( *in >> c; c==' ' || c=='\t'; *in >> c ){}
- in->putback( c );
- char prev = 0;
- int i;
- for( i = 0; i < sizeof( Lex ); i++ )
- {
- *in >> c;
- if( c==lxEof )
- break;
- if( c=='\n' )
- {
- NextLine();
- if( prev=='\\' )
- c = Lex[i-1] = ' ';
- else
- break;
- }
- Lex[i] = c;
- prev = c==' '||c=='\t'? prev : c;
- }
- Lex[i] = 0;
- def->Translate( Lex );
- }
-
- Token YLex::__preprocessor()
- {
- if( !lexstr->begline )
- return c;
- __whitespace();
- c = GetChar();
- Token t = __name();
- int not = 0;
- switch( t )
- {
- case lxInclude:
- {
- if( yylex()!=lxString )
- {
- yyerror();
- break;
- }
- File( Lex, 0 );
- in = 0;
- return yylex();
- }
- case lxDefine:
- {
- if( !Skipping )
- __definition();
- return yylex();
- }
- case lxUndef:
- {
- if( Skipping )
- return yylex();
- Macros = 0; t = yylex(); Macros = 1;
- if( t!=lxName )
- yyerror();
- LexDefine* def = (LexDefine*)(*defines)( Lex );
- if( def )
- defines->Remove( def );
- return yylex();
- }
- case lxIfndef: not = 1;
- case lxIfdef:
- {
- Macros = 0; t = yylex(); Macros = 1;
- if( t!=lxName )
- yyerror();
- LexDefine* def = (LexDefine*)(*defines)( Lex );
- IfDefStack[ IfDefSP++ ] = Skipping ? 2 :
- (!def && !not || def && not) ? 1 : 0;
- break;
- }
- case lxElse:
- {
- if( !IfDefSP )
- {
- yyerror("misplaced #else");
- return yylex();
- }
- int& c = IfDefStack[ IfDefSP-1 ];
- c = c==2 ? c : c==1 ? 0 : 1;
- break;
- }
- case lxEndif:
- {
- if( !IfDefSP )
- {
- yyerror("misplaced #endif");
- return yylex();
- }
- IfDefSP--;
- break;
- }
- default: return t;
- }
- Skipping = IfDefSP>0 && IfDefStack[ IfDefSP-1 ]>0;
- Token last = 0;
- while( Skipping )
- last = yylex();
- return last ? last : yylex();
- }
-
- YLex::__macro( const char* s )
- {
- LexDefine* def = (LexDefine*)(*defines)( s );
- if( !def || def->busy )
- return 0;
- __whitespace();
- c = GetChar();
- if( !in || in->eof() ||
- c=='(' && !def->argc ||
- c!='(' && def->argc )
- {
- yyerror("wrong number of arguments in macro ",
- def->StringValue());
- return 0;
- }
- if( !def->argc )
- PutBack( c );
- char *p = def->Generate( *in );
- if( !p )
- {
- yyerror("bad arguments for macro ", def->StringValue());
- return 0;
- }
- input->Push( new LSMacro( def, p ));
- in = 0;
- return 1;
- }
-
- void YLex::Errors( ostream& o ) const
- {
- if( !errors )
- return;
- for( LexObj* p = errors->FirstInList; p; p = p->NextInList )
- {
- SyntaxError& err = (SyntaxError&) *p;
- o << err.file << "\t" << err.line << ": " << err << endl;
- }
- }
-
- SyntaxError::SyntaxError
- (
- const char*s1,
- const char*s2,
- const char*s3
- ) :
- line( 0 ),
- str( new char
- [
- strlen( s1 )+
- strlen( s2 )+
- strlen( s3 )+1
- ]
- )
- {
- char *f = YLex::lexstr ? YLex::lexstr->file : "";
- strcpy( str, s1 );
- strcat( str, s2 );
- strcat( str, s3 );
- file = new char[ strlen( f )+1 ];
- strcpy( file, f );
- }
-
- LexDefine::LexDefine( const char* s ) :
- value( 0 ), busy( 0 ), argc( 0 )
- {
- name = new char[ strlen( s )+1 ];
- strcpy( name, s );
- }
-
- inline isA( char c ){ return c=='_' || isdigit( c ) || isalpha( c ); }
- static char *strtran
- (
- const char* str,
- const char* a,
- const char* b,
- int whole_word = 1
- )
- {
- int n1 = strlen( a );
- int n2 = strlen( b );
- char* s = new char[ strlen( str )+1 ];
- strcpy( s, str );
- for( const char* p = strstr( s, a );
- p && *p; p = strstr( p, a ))
- {
- if(( s!=p && isA( p[-1] ) ||
- isA( p[ n1 ])) && whole_word )
- {
- p += n1;
- continue;
- }
- int i = (int)(p - s);
- char *q = new char[ strlen( s )-n1+n2+1 ];
- memcpy( q, s, i );
- strcpy( q+i, b );
- strcat( q+i, p+n1 );
- delete[] s;
- s = q;
- p = q+i+n2;
- }
- return s;
- }
-
- void LexDefine::Translate( const char* str )
- {
- value = new char[ strlen( str )+1 ];
- strcpy( value, str );
-
- static char dummy[] = "~?";
- char* s = new char[ strlen( value )+1 ];
- strcpy( s, value );
- static char lex[256];
- dummy[1] = '0';
- for( char* p = strchr( name, '(' );
- p && *p; p = strchr( p, ',' ), dummy[1]++, argc++ )
- {
- int k = 0;
- for( int j = 1; p[j] && p[j]!=',' && p[j]!=')'; j++ )
- if( p[j]!=' ' && p[j]!='\t' )
- lex[k++] = p[j];
- char* q = strtran( s, lex, dummy );
- delete[] s;
- s = q;
- *p = 0;
- p++;
- }
- delete[] value;
- value = s;
- }
-
- #define GEN_ERROR { delete[] s; return 0; }
- #define GEN_ACCEPT { lex[j++] = c; break; }
- #define GEN_ARG { lex[j] = 0; j = -1; \
- char *q = strtran( s, dummy, lex ); \
- delete[] s; s = q; break; }
-
- char* LexDefine::Generate( istream& in )
- {
- static char dummy[] = "~?";
- char*s = new char[ strlen( value )+1 ];
- strcpy( s, value );
- dummy[1] = '0';
- for( int i = 0; i<argc; i++, dummy[1]++ )
- {
- char c;
- char lex[ 256 ];
- char string = 0;
- int level = 0;
- int j = 0;
- while( j >= 0 )
- {
- in >> c;
- if( in.eof() )
- GEN_ERROR;
- switch( c )
- {
- case '\'':
- case '"': string = string==c ? (char)0 :
- string ? string : c;
- GEN_ACCEPT;
-
- case '(': if( !string )
- level++;
- GEN_ACCEPT;
-
- case ')': if( string )
- GEN_ACCEPT;
- if( level )
- {
- level--;
- GEN_ACCEPT;
- }
- if( i!=argc-1 )
- GEN_ERROR;
- GEN_ARG;
-
- case ',': if( string || level )
- GEN_ACCEPT;
- if( i==argc-1 )
- GEN_ERROR;
- GEN_ARG;
-
- default: GEN_ACCEPT;
- }
- }
- }
- char *q = strtran( s, "##", "", 0 );
- delete[] s;
- return q;
- }
-
- LStream::~LStream()
- {
- delete[] file;
- delete in;
- }
-
- LSFile::LSFile( const char* s, int u ) :
- Undef( u )
- {
- begline = 1;
- line = 1;
- pos = 0;
- file = new char[ strlen( s )+1 ];
- strcpy( file, s );
- }
-
- LSFile::operator int() const
- {
- if( !in )
- return 1;
- return !in->good();
- }
-
- LSFile::Open()
- {
- YLex::lexstr = this;
- delete in;
- in = new ifstream( file, ios::in | ios::nocreate
- #ifdef __ZTC__
- | ios::translated
- #endif
- );
- if( in && in->good())
- in->flags( in->flags() & ~ios::skipws );
- else
- cerr << "Cannot open file " << file << endl;
- return *this;
- }
-
- LSMacro::LSMacro( LexDefine* p, char* s ) :
- def( p ), str( s )
- {
- LStream* y = YLex::lexstr;
- def->busy = 1;
- begline = y->begline;
- line = y->line;
- pos = y->pos;
- file = new char[ strlen( y->file )+1 ];
- strcpy( file, y->file );
- YLex::lexstr = this;
- in = new istrstream( str, strlen( str ));
- }
-
- LSMacro::~LSMacro()
- {
- def->busy = 0;
- delete[] str;
- }
-
- void LexObj::print( ostream& o ) const
- {
- o << StringValue();
- }
-
- LexObj::isEqual( const LexObj& o ) const
- {
- const char *p = StringValue();
- const char *q = o.StringValue();
- if( !p || !q )
- return 0;
- return !strcmp( p, q );
- }
-
- static theSame( const char* s1, const char *s2 )
- {
- for( int i = 0; s1[i] || s2[i]; i++ )
- if( !s1[i] || !s2[i] ||
- toupper( s1[i] ) !=
- toupper( s2[i] ))
- return 0;
- return 1;
- }
-
- LexObj* LexList::operator()( const char *s ) const
- {
- for( LexObj* p = FirstInList; p; p = p->NextInList )
- if( theSame( p->StringValue(), s ))
- return p;
- return 0;
- }
-
- LexList::~LexList()
- {
- for( LexObj *p = FirstInList; p; )
- {
- LexObj* q = p;
- p = p->NextInList;
- delete q;
- }
- }
-
- void LexList::Add( LexObj* o )
- {
- NumObj++;
- if( !FirstInList )
- {
- FirstInList = LastInList = o;
- return;
- }
- LastInList->NextInList = o;
- o->PrevInList = LastInList;
- LastInList = o;
- }
-
- void LexList::Remove( LexObj* o )
- {
- NumObj--;
- if( o == FirstInList )
- FirstInList = o->NextInList;
- if( o == LastInList )
- LastInList = o->PrevInList;
- if( o->NextInList )
- o->NextInList->PrevInList = o->PrevInList;
- if( o->PrevInList )
- o->PrevInList->NextInList = o->NextInList;
- delete o;
- }
-
- void LexList::print( ostream& o ) const
- {
- for( LexObj* p = FirstInList;
- p; p = p->NextInList )
- o << *p << endl;
- }
-
- void LexStack::Push( LexObj*o )
- {
- if( ref )
- o = new LexRef( o );
- Add( o );
- }
-
- void LexStack::Pop()
- {
- LexObj *p = LastInList;
- if( !p )
- return;
- NumObj--;
- if( p == FirstInList )
- {
- p->NextInList =
- p->PrevInList =
- FirstInList =
- LastInList = 0;
- delete p;
- return;
- }
- LastInList = LastInList->PrevInList;
- p->PrevInList = LastInList->NextInList = 0;
- delete p;
- }
-
- LexObj *LexStack::Last() const
- {
- if( !LastInList )
- return 0;
- return ref ? ((LexRef*)LastInList)->Obj() : LastInList;
- }
-
- Lexema::Lexema( const char *s, int t ) : token( t )
- {
- lex = new char[ strlen(s)+1 ];
- strcpy( lex, s );
- }
-
- Lexema::Lexema( const Lexema& l ) : token( l.token )
- {
- lex = new char[ strlen(l.lex)+1 ];
- strcpy( lex, l.lex );
- }
-
- void Lexema::print( ostream& o ) const
- {
- o << lex;
- }
-
- Lexema::setYyLval( void *yylvalPtr )
- {
- if( !yylvalPtr )
- {
- cerr << "Yylex error!" << endl;
- return lxBadToken;
- }
- memcpy( yylvalPtr, yyData(), yySize());
- return token;
- }
-
-