Пример реализации на Си++ анализатора модельного языка
#include <iostream.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
enum type_of_lex
{
LEX_NULL, /*0*/
LEX_AND, LEX_BEGIN, LEX_BOOL, LEX_DO, LEX_ELSE, LEX_END, LEX_IF, LEX_FALSE, LEX_INT, /*9*/
LEX_NOT, LEX_OR, LEX_PROGRAM, LEX_READ, LEX_THEN, LEX_TRUE, LEX_VAR, LEX_WHILE, LEX_WRITE, /*18*/
LEX_FIN, /*19*/
LEX_SEMICOLON, LEX_COMMA, LEX_COLON, LEX_ASSIGN, LEX_LPAREN, LEX_RPAREN, LEX_EQ, LEX_LSS, /*27*/
LEX_GTR, LEX_PLUS, LEX_MINUS, LEX_TIMES, LEX_SLASH, LEX_LEQ, LEX_NEQ, LEX_GEQ, /*35*/
LEX_NUM, /*36*/
LEX_ID, /*37*/
POLIZ_LABEL, /*38*/
POLIZ_ADDRESS, /*39*/
POLIZ_GO, /*40*/
POLIZ_FGO}; /*41*/
///////////////////////// Класс Lex //////////////////////////
class Lex
{
type_of_lex t_lex;
int v_lex;
public:
Lex ( type_of_lex t = LEX_NULL, int v = 0): t_lex (t), v_lex (v) {}
type_of_lex get_type () { return t_lex; }
int get_value () { return v_lex; }
friend ostream & operator<< (ostream &s, Lex l)
{
s << '(' << l.t_lex << ',' << l.v_lex << ");" ;
return s;
}
};
///////////////////// Класс Ident ////////////////////////////
class Ident
{
char * name;
bool declare;
type_of_lex type;
bool assign;
int value;
public:
Ident() { declare = false; assign = false; }
char * get_name () { return name; }
void put_name (const char *n)
{
name = new char [ strlen(n)+1];
strcpy(name,n);
}
bool get_declare () { return declare; }
void put_declare () { declare = true; }
type_of_lex get_type () { return type; }
void put_type ( type_of_lex t ) { type = t; }
bool get_assign () { return assign; }
void put_assign (){ assign = true; }
int get_value () { return value; }
void put_value (int v){ value = v; }
};
////////////////////// Класс Tabl_ident ///////////////////////
class Tabl_ident
{
Ident * p;
int size;
int top;
public:
Tabl_ident ( int max_size )
{
p = new Ident [ size = max_size ];
top = 1;
}
~Tabl_ident () { delete [] p; }
Ident & operator[] ( int k ) { return p[k]; }
int put ( const char *buf );
};
int Tabl_ident::put ( const char *buf )
{
for ( int j = 1; j < top; j++ )
if ( !strcmp ( buf, p[j].get_name() ) )
return j;
p[top].put_name(buf);
++top;
return top-1;
}
/////////////////////////////////////////////////////////////////
template < class T, int max_size >
class Stack
{
T s [max_size];
int top;
public:
Stack () { top = 0; }
void reset () { top = 0; }
void push ( T i );
T pop ();
bool is_empty () { return top == 0; }
bool is_full () { return top == max_size; }
};
template < class T, int max_size >
void Stack < T, max_size > :: push (T i)
{
if ( !is_full() )
s [top++] = i;
else
throw "Stack_is_full";
}
template <class T, int max_size >
T Stack < T, max_size > :: pop ()
{
if ( !is_empty() )
return s[--top];
else
throw "stack_is_empty";
}
///////////////////////// Класс Poliz /////////////////////////////
class Poliz
{
Lex * p;
int size;
int free;
public:
Poliz (int max_size)
{
p = new Lex [size = max_size];
free = 0;
}
~Poliz() { delete [] p; }
void put_lex ( Lex l )
{
p [free] = l;
free++;
}
void put_lex ( Lex l, int place) { p [place] = l; }
void blank () { free++; }
int get_free () { return free; }
Lex & operator[] (int index)
{
if ( index > size )
throw "POLIZ:out of array";
else
if ( index > free )
throw "POLIZ:indefinite element of array";
else
return p[index];
}
void print ()
{
for ( int i = 0; i < free; ++i )
cout << p[i];
}
};
////////////////////////////////////////////////////////////////////
Tabl_ident TID ( 100 );
///////////////////// Класс Scanner //////////////////////////////
class Scanner
{
enum state { H, IDENT, NUMB, COM, ALE, DELIM, NEQ };
static char * TW [];
static type_of_lex words [];
static char * TD [];
static type_of_lex dlms [];
state CS;
FILE * fp;
char c;
char buf [ 80 ];
int buf_top;
void clear ()
{
buf_top = 0;
for ( int j = 0; j < 80; j++ )
buf[j] = '\0';
}
void add ()
{
buf [ buf_top++ ] = c;
}
int look ( const char *buf, char **list )
{
int i = 0;
while (list[i])
{
if ( !strcmp(buf, list[i]) )
return i;
++i;
}
return 0;
}
void gc ()
{
c = fgetc (fp);
}
public:
Scanner ( const char * program )
{
fp = fopen ( program, "r" );
CS = H;
clear();
gc();
}
Lex get_lex ();
};
char *
Scanner::TW [] = {"", "and", "begin", "bool", "do", "else", "end", "if", "false", "int", "not", "or", "program",
"read", "then", "true", "var", "while", "write", NULL};
type_of_lex
Scanner::words [] = {LEX_NULL, LEX_AND, LEX_BEGIN, LEX_BOOL, LEX_DO, LEX_ELSE, LEX_END, LEX_IF, LEX_FALSE, LEX_INT,
LEX_NOT, LEX_OR, LEX_PROGRAM, LEX_READ, LEX_THEN, LEX_TRUE, LEX_VAR, LEX_WHILE, LEX_WRITE, LEX_NULL};
char *
Scanner::TD [] = {"", "@", ";", ",", ":", ":=", "(", ")", "=", "<", ">", "+", "-", "*", "/", "<=", "!=", ">=", NULL};
type_of_lex
Scanner::dlms [] = {LEX_NULL, LEX_FIN, LEX_SEMICOLON, LEX_COMMA, LEX_COLON, LEX_ASSIGN, LEX_LPAREN, LEX_RPAREN, LEX_EQ,
LEX_LSS, LEX_GTR, LEX_PLUS, LEX_MINUS, LEX_TIMES, LEX_SLASH, LEX_LEQ, LEX_NEQ, LEX_GEQ, LEX_NULL};
Lex Scanner::get_lex ()
{
int d, j;
CS = H;
do
{
switch(CS)
{
case H:
if ( c==' ' || c == '\n' || c== '\r' || c == '\t' )
gc();
else if ( isalpha(c) )
{
clear();
add();
gc();
CS = IDENT;
}
else if ( isdigit(c) )
{
d = c - '0';
gc();
CS = NUMB;
}
else if ( c== '{' )
{
gc();
CS = COM;
}
else if ( c== ':' || c== '<' || c== '>' )
{
clear();
add();
gc();
CS = ALE;
}
else if (c == '@')
return Lex(LEX_FIN);
else if (c == '!')
{
clear();
add();
gc();
CS = NEQ;
}
else
CS = DELIM;
break;
case IDENT:
if ( isalpha(c) || isdigit(c) )
{
add();
gc();
}
else if ( j = look (buf, TW) )
return Lex (words[j], j);
else
{
j = TID.put(buf);
return Lex (LEX_ID, j);
}
break;
case NUMB:
if ( isdigit(c) )
{
d = d * 10 + (c - '0'); gc();
}
else
return Lex ( LEX_NUM, d);
break;
case COM:
if ( c == '}' )
{
gc();
CS = H;
}
else if (c == '@' || c == '{' )
throw c;
else
gc();
break;
case ALE:
if ( c== '=')
{
add();
gc();
j = look ( buf, TD );
return Lex ( dlms[j], j);
}
else
{
j = look ( buf, TD );
return Lex ( dlms[j], j );
}
break;
case NEQ:
if (c == '=')
{
add();
gc();
j = look ( buf, TD );
return Lex ( LEX_NEQ, j );
}
else
throw '!';
break;
case DELIM:
clear();
add();
if ( j = look ( buf, TD) )
{
gc();
return Lex ( dlms[j], j );
}
else
throw c;
break;
}//end switch
} while (true);
}
/////////////////////////// Класс Parser /////////////////////////////////
class Parser
{
Lex curr_lex;
type_of_lex c_type;
int c_val;
Scanner scan;
Stack < int, 100 > st_int;
Stack < type_of_lex, 100 > st_lex;
void P();
void D1();
void D();
void B();
void S();
void E();
void E1();
void T();
void F();
void dec ( type_of_lex type);
void check_id ();
void check_op ();
void check_not ();
void eq_type ();
void eq_bool ();
void check_id_in_read ();
void gl ()
{
curr_lex = scan.get_lex();
c_type = curr_lex.get_type();
c_val = curr_lex.get_value();
}
public:
Poliz prog;
Parser (const char *program ) : scan (program),prog (1000) {}
void analyze();
};
void Parser::analyze ()
{
gl();
P();
prog.print();
cout << endl << "Yes!!!" << endl;
}
void Parser::P ()
{
if (c_type == LEX_PROGRAM)
gl();
else
throw curr_lex;
D1();
if (c_type == LEX_SEMICOLON)
gl();
else
throw curr_lex;
B();
if (c_type != LEX_FIN)
throw curr_lex;
}
void Parser::D1 ()
{
if (c_type == LEX_VAR)
{
gl();
D();
while (c_type == LEX_COMMA)
{
gl();
D();
}
}
else
throw curr_lex;
}
void Parser::D ()
{
st_int.reset();
if (c_type != LEX_ID)
throw curr_lex;
else
{
st_int.push ( c_val );
gl();
while (c_type == LEX_COMMA)
{
gl();
if (c_type != LEX_ID)
throw curr_lex;
else
{
st_int.push ( c_val );
gl();
}
}
if (c_type != LEX_COLON)
throw curr_lex;
else
{
gl();
if (c_type == LEX_INT)
{
dec ( LEX_INT );
gl();
}
else
if (c_type == LEX_BOOL)
{
dec ( LEX_BOOL );
gl();
}
else throw curr_lex;
}
}
}
void Parser::B ()
{
if (c_type == LEX_BEGIN)
{
gl();
S();
while (c_type == LEX_SEMICOLON)
{
gl();
S();
}
if (c_type == LEX_END)
gl();
else
throw curr_lex;
}
else
throw curr_lex;
}
void Parser::S ()
{
int pl0, pl1, pl2, pl3;
if (c_type == LEX_IF)
{
gl();
E();
eq_bool();
pl2 = prog.get_free ();
prog.blank();
prog.put_lex (Lex(POLIZ_FGO));
if (c_type == LEX_THEN)
{
gl();
S();
pl3 = prog.get_free();
prog.blank();
prog.put_lex (Lex(POLIZ_GO));
prog.put_lex (Lex(POLIZ_LABEL, prog.get_free()), pl2);
if (c_type == LEX_ELSE)
{
gl();
S();
prog.put_lex (Lex(POLIZ_LABEL, prog.get_free()), pl3);
}
else
throw curr_lex;
}
else
throw curr_lex;
}//end if
else if (c_type == LEX_WHILE)
{
pl0=prog.get_free();
gl();
E();
eq_bool();
pl1=prog.get_free(); prog.blank();
prog.put_lex (Lex(POLIZ_FGO));
if (c_type == LEX_DO)
{
gl();
S();
prog.put_lex (Lex (POLIZ_LABEL, pl0));
prog.put_lex (Lex ( POLIZ_GO));
prog.put_lex (Lex ( POLIZ_LABEL, prog.get_free()), pl1);
}
else
throw curr_lex;
}//end while
else if (c_type == LEX_READ)
{
gl();
if (c_type == LEX_LPAREN)
{
gl();
if (c_type == LEX_ID) {
check_id_in_read();
prog.put_lex (Lex ( POLIZ_ADDRESS, c_val) );
gl();
}
else
throw curr_lex;
if ( c_type == LEX_RPAREN )
{
gl();
prog.put_lex (Lex (LEX_READ));
}
else
throw curr_lex;
}
else
throw curr_lex;
}//end read
else if (c_type == LEX_WRITE)
{
gl();
if (c_type == LEX_LPAREN)
{
gl();
E();
if (c_type == LEX_RPAREN)
{
gl();
prog.put_lex (Lex(LEX_WRITE));
}
else
throw curr_lex;
}
else
throw curr_lex;
}//end write
else if ( c_type == LEX_ID )
{
check_id ();
prog.put_lex (Lex ( POLIZ_ADDRESS, c_val) );
gl();
if ( c_type == LEX_ASSIGN )
{
gl();
E();
eq_type();
prog.put_lex (Lex (LEX_ASSIGN) );
}
else
throw curr_lex;
}//assign-end
else
B();
}
void Parser::E ()
{
E1();
if ( c_type == LEX_EQ || c_type == LEX_LSS || c_type == LEX_GTR ||
c_type == LEX_LEQ || c_type == LEX_GEQ || c_type == LEX_NEQ )
{
st_lex.push (c_type);
gl();
E1();
check_op();
}
}
void Parser::E1 ()
{
T();
while ( c_type == LEX_PLUS || c_type == LEX_MINUS || c_type == LEX_OR)
{
st_lex.push (c_type);
gl();
T();
check_op();
}
}
void Parser::T ()
{
F();
while ( c_type == LEX_TIMES || c_type == LEX_SLASH || c_type == LEX_AND)
{
st_lex.push (c_type);
gl();
F();
check_op();
}
}
void Parser::F ()
{
if ( c_type == LEX_ID )
{
check_id();
prog.put_lex (Lex (LEX_ID, c_val));
gl();
}
else if ( c_type == LEX_NUM )
{
st_lex.push ( LEX_INT );
prog.put_lex ( curr_lex );
gl();
}
else if ( c_type == LEX_TRUE )
{
st_lex.push ( LEX_BOOL );
prog.put_lex (Lex (LEX_TRUE, 1) );
gl();
}
else if ( c_type == LEX_FALSE)
{
st_lex.push ( LEX_BOOL );
prog.put_lex (Lex (LEX_FALSE, 0) );
gl();
}
else if (c_type == LEX_NOT)
{
gl();
F();
check_not();
}
else if ( c_type == LEX_LPAREN )
{
gl();
E();
if ( c_type == LEX_RPAREN)
gl();
else
throw curr_lex;
}
else
throw curr_lex;
}
////////////////////////////////////////////////////////////////
void Parser::dec ( type_of_lex type )
{
int i;
while ( !st_int.is_empty())
{
i = st_int.pop();
if ( TID[i].get_declare() )
throw "twice";
else
{
TID[i].put_declare();
TID[i].put_type(type);
}
}
}
void Parser::check_id ()
{
if ( TID[c_val].get_declare() )
st_lex.push ( TID[c_val].get_type() );
else
throw "not declared";
}
void Parser::check_op ()
{
type_of_lex t1, t2, op, t = LEX_INT, r = LEX_BOOL;
t2 = st_lex.pop();
op = st_lex.pop();
t1 = st_lex.pop();
if (op == LEX_PLUS || op == LEX_MINUS || op == LEX_TIMES || op == LEX_SLASH)
r = LEX_INT;
if (op == LEX_OR || op == LEX_AND)
t = LEX_BOOL;
if (t1 == t2 && t1 == t)
st_lex.push(r);
else
throw "wrong types are in operation";
prog.put_lex (Lex (op) );
}
void Parser::check_not ()
{
if (st_lex.pop() != LEX_BOOL)
throw "wrong type is in not";
else
{
st_lex.push (LEX_BOOL);
prog.put_lex (Lex (LEX_NOT));
}
}
void Parser::eq_type ()
{
if (st_lex.pop() != st_lex.pop())
throw "wrong types are in :=";
}
void Parser::eq_bool ()
{
if ( st_lex.pop() != LEX_BOOL )
throw "expression is not boolean";
}
void Parser::check_id_in_read ()
{
if ( !TID [c_val].get_declare() )
throw "not declared";
}
////////////////////////////////////////////////////////////////
class Executer
{
Lex pc_el;
public:
void execute ( Poliz & prog );
};
void Executer::execute ( Poliz & prog )
{
Stack < int, 100 > args;
int i, j, index = 0, size = prog.get_free();
while ( index < size )
{
pc_el = prog [ index ];
switch ( pc_el.get_type () )
{
case LEX_TRUE: case LEX_FALSE: case LEX_NUM: case POLIZ_ADDRESS: case POLIZ_LABEL:
args.push ( pc_el.get_value () );
break;
case LEX_ID:
i = pc_el.get_value ();
if ( TID[i].get_assign () )
{
args.push ( TID[i].get_value () );
break;
}
else
throw "POLIZ: indefinite identifier";
case LEX_NOT:
args.push( !args.pop() );
break;
case LEX_OR:
i = args.pop();
args.push ( args.pop() || i );
break;
case LEX_AND:
i = args.pop();
args.push ( args.pop() && i );
break;
case POLIZ_GO:
index = args.pop() - 1;
break;
case POLIZ_FGO:
i = args.pop();
if ( !args.pop() ) index = i-1;
break;
case LEX_WRITE:
cout << args.pop () << endl;
break;
case LEX_READ:
{
int k;
i = args.pop ();
if ( TID[i].get_type () == LEX_INT )
{
cout << "Input int value for" << TID[i].get_name () << endl;
cin >> k;
}
else
{
char j[20];
rep:
cout << "Input boolean value (true or false) for" << TID[i].get_name() << endl;
cin >> j;
if (!strcmp(j, "true"))
k = 1;
else
if (!strcmp(j, "false"))
k = 0;
else
{
cout << "Error in input:true/false" << endl;
goto rep;
}
}
TID[i].put_value (k);
TID[i].put_assign ();
break;
}
case LEX_PLUS:
args.push ( args.pop() + args.pop() );
break;
case LEX_TIMES:
args.push ( args.pop() * args.pop() );
break;
case LEX_MINUS:
i = args.pop();
args.push ( args.pop() - i );
break;
case LEX_SLASH:
i = args.pop();
if (i)
{
args.push(args.pop() / i);
break;
}
else
throw "POLIZ:divide by zero";
case LEX_EQ:
args.push ( args.pop() == args.pop() );
break;
case LEX_LSS:
i = args.pop();
args.push ( args.pop() < i);
break;
case LEX_GTR:
i = args.pop();
args.push ( args.pop() > i );
break;
case LEX_LEQ:
i = args.pop();
args.push ( args.pop() <= i );
break;
case LEX_GEQ:
i = args.pop();
args.push ( args.pop() >= i );
break;
case LEX_NEQ:
i = args.pop();
args.push ( args.pop() != i );
break;
case LEX_ASSIGN:
i = args.pop();
j = args.pop();
TID[j].put_value(i);
TID[j].put_assign(); break;
default:
throw "POLIZ: unexpected elem";
}//end of switch
++index;
};//end of while
cout << "Finish of executing!!!" << endl;
}
class Interpretator
{
Parser pars;
Executer E;
public:
Interpretator (char* program): pars (program) {}
void interpretation ();
};
void Interpretator::interpretation ()
{
pars.analyze ();
E.execute ( pars.prog );
}
int main ( int argc, char ** argv )
{
try
{
Interpretator I ( argv[1] );
I.interpretation ();
return 0;
}
catch (char c)
{
cout << "unexpected symbol " << c << endl;
return 1;
}
catch (Lex l)
{
cout << "unexpected lexeme";
cout << l;
return 1;
}
catch ( const char *source )
{
cout << source << endl;
return 1;
}
}