#pragma hdrstop
#pragma argsused
#include <stdio.h>
#include <fstream>
#include <iostream>
#include <sstream>
#include <vector>
#include <string>
#include <stdlib.h>
using namespace std;

//lexical_analizator
ifstream mprog;
int k=0,q=1,z=0;
char c;

//not a type - type 0
//reserved words - type 1
//delimiters - type 2
//numerical constants - type 3
//identificators - type 4
//string constants - type 5

string reserv[] ={"program", "int", "boolean", "true", "false", "if", "while", "read", "write", "case", "of", "end", "break", "not", "and", "or", "else"};
//1 - reserved words 		 0		        1		        2   		     3                   4		    5 		   6 		    7 		     8 		      9		   10		11 		12 	         13 	       14 	   15  		 16

string delims[] ={"(", ")", "{", "}", "-", "+", "=", "@", "@", ";", ",", "<", ">", "/", "*", "!=", "<=", ">=", "==", ":"};  //@ - empty symbol
//2 - delimiters		         0	1	   2 	     3 	        4	5	   6 	     7 	        8 	9	 10 	     11 	       12         13 	  14 	       15  	 16  	      17 	18	    19

class lexem
{
 public:
  int type;
  int number;
  string id;

  lexem (int type, int number): type(type), number(number) {}
  lexem (int type, string id): type(type), id(id) {}

 void print ()
   {
    cout<<type<<"  ";
    if ((type!=4)&&(type!=5)) cout<<number;
    if ((type==4)||(type==5)) cout<<id<<endl;
   }
};


lexem* L;


void open_file (int argc, char** argv)
{
 string name,path;
  if (argc<2) {cout<<" ERROR: not enough arguments."<<endl; exit(1); }
  if (argc>2) {cout<<" ERROR: too many arguments."<<endl; exit(1); }
 path=argv[1];
 mprog.open(path.c_str(), ios::in);
  if (!mprog.is_open()){ cout << " ERROR: Wrong directory or wrong filename"<<endl; exit(1);}
 return;
}

//------------------------------------------------ LEXICAL ANALYSIS ------------------------------------------------

lexem* getlex ()

{
 string s;
 string buf;
 int type=0,number,d=0,comm=0;
 stringstream value (stringstream::in | stringstream::out);

type=0;
if (k!=1) mprog.get(c);
k=0;

 while (mprog.good())
 {
  if (comm) // catching comments
   while (mprog.good())
   {
    mprog.get(c);
    if (c=='*') 
     {
      mprog.get(c);
      if (c=='/')
       {
        comm=0;
        buf.clear();
        mprog.get(c);
        type=0;
        break;
       }
     }
   }

//  if (comm) cout<<"X"<<c<<"X";
  

  while ((isspace(c)) && (type==0))
  {
   mprog.get(c);
   if (!mprog.good()) {q=0; L->type=0; return L;}
  }
  d=0;
  
//   if (!mprog.good()) q=0;
  
  if ((isspace(c)) && (type!=0)) d=1;
  else
 {
   if ((isupper(c))||(islower(c)))
    {
     if (type==0) type=4; //id or reserved word
     if (type==3) { cout<<" LEXICAL ERROR: Incorrect numerical constant format"<<endl; exit(1);}
    }
   else if (isdigit(c))
    {
     if (type==0) type=3; //numerical constant
    }
   else if  ((c==',')||(c==';')||(c=='(')||(c==')')||(c=='{')||(c=='}')||(c=='-')||(c=='+')||(c=='=')||(c=='<')||(c=='>')||(c=='!')||(c=='*')||(c=='/')||(c==':'))
    {
     if (type!=0)
      {
       d=1;
       k=1;
      }
     else
      {
       type=2; d=1;
       buf=buf+c;
       if (c==':') number=19;
       if (c=='(') number=0;           if (c==')') number=1;       if (c=='{') number=2;
       if (c=='}') number=3;           if (c=='-') number=4;       if (c=='+') number=5;
       if (c==';') number=9;           if (c==',') number=10;      if (c=='*') number=14;
       if (c=='!') {mprog.get(c); if (c=='=') {buf=buf+c;number=15;} else { cout<<" LEXICAL ERROR: Wrong symbol \""<<c<<"\" "<<endl; exit(1);}} else
       if (c=='<') {mprog.get(c); if (c=='=') {buf=buf+c; number=16;} else {number=11; k=1;} } else
       if (c=='>') {mprog.get(c); if (c=='=') {buf=buf+c; number=17;} else {number=12; k=1;} } else
       if (c=='=') {mprog.get(c); if (c=='=') {buf=buf+c; number=18;} else {number=6; k=1;} } else
       if (c=='/') {mprog.get(c); if (c=='*') {comm=1; d=0;} else {number=13; k=1;} }
      }
    }
   else if (c=='\"')
    {
     type=5;
     d=1;
     while (mprog.good())
      {
       mprog.get(c);
       if (c!='\"') buf=buf+c;
       else break;
      }
    }
   else { cout<<" LEXICAL ERROR: Wrong symbol \""<<c<<"\" "<<endl; exit(1);}
 }
  if ((type==4) && (d)) for(int i=0; i<17;i++) if (buf==reserv[i]) {type=1; number=i;}
  if ((d)&&((type==1)||(type==2))) L=new lexem(type,number);
  if ((d)&&(type==3)) {value<<buf; value>>number; L=new lexem(type,number);}
  if ((d)&&((type==4)||(type==5))) L=new lexem(type,buf);
  if (!d) buf=buf+c;
  if (d) {/*cout<<"#"<<buf<<"#"<<endl; */buf.clear(); type=0; d=0; break;}

  if (k!=1) mprog.get(c);
  k=0;
 }
 if (!mprog.good()) {q=0; L->type=0;}
return L;
}



//------------------------------------------------ SYNTAX ANALYSIS -------------------------------------------------
void IF();
void WHILE ();
void READ ();
void WRITE ();
void CASE ();
void OPERATOR ();
void EXPRESSION ();
void OR ();
void AND ();
void COMPARE ();
void ADD_SUB ();
void MULT_DIV ();
void VALUE ();




void ERROR (string s)
{
 cout<<endl<<s<<endl;
 getchar();
 exit(1);
}


void VARIABLE ()
{
 if (L->type!=4) ERROR (" SYNTAX ERROR: identificator missing in a variable description");
 L=getlex();
 if ((L->type==2)&&(L->number==6))
  {
   L=getlex();
   if ((L->type==3)||((L->type==1)&&((L->number==3)||(L->number==4)))) L=getlex();
   else  ERROR (" SYNTAX ERROR: wrong constant type in a variable description");
  }
}


void DESCRIPTION ()
{
 VARIABLE ();
 while ((L->type==2)&&(L->number==10))
  {
   L=getlex();
  //   cout<<L->type<<"-"<<L->number<<endl;
   VARIABLE ();
   if (((L->type!=2)||(L->number!=10))&&((L->type!=2)||(L->number!=9))) ERROR (" SYNTAX ERROR: wrong delimiter between variable descriptions");
  }

 if ((L->type!=2)||(L->number!=9)) ERROR (" SYNTAX ERROR: wrong delimiter in the end of variable descriptions");
    L=getlex();
 }


void EQ ()
{
 EXPRESSION();
  if ((L->type==2)&&(L->number==6))
  {
   L=getlex();
   EQ();
  }
}


void EXPRESSION ()
{
 OR();
 while ((L->type==1)&&(L->number==15))
  {
   L=getlex();
   OR();
  }
}

void OR ()
{
 AND();
 while ((L->type==1)&&(L->number==14))
  {
   L=getlex();
   AND();
  }
}


void AND ()
{
 COMPARE();
 while ((L->type==2)&&((L->number==11)||(L->number==12)||(L->number==15)||(L->number==16)||(L->number==17)||(L->number==18)))
  {
   L=getlex();
   COMPARE();
  }
}


void COMPARE ()
{
 ADD_SUB();
 while ((L->type==2)&&((L->number==4)||(L->number==5)))
  {
   L=getlex();
   ADD_SUB();
  }
}


void ADD_SUB ()
{
 MULT_DIV();
 while ((L->type==2)&&((L->number==13)||(L->number==14)))
  {
   L=getlex();
   MULT_DIV();
  }
}


void MULT_DIV ()
{
 VALUE();
 while ((L->type==2)&&((L->number==4)||(L->number==5)))
  {
   L=getlex();
   VALUE();
  }
}

 
 void  VALUE()
 {
 if ((L->type==2)&&(L->number==0))
  {
   L=getlex();
   EQ();
   if ((L->type!=2)||(L->number!=1)) ERROR (" SYNTAX ERROR: missing \')\' in operator");
   L=getlex();
  }
 else if (L->type==4) L=getlex();            //identificator
 else if (((L->type==1)&&((L->number==3)||(L->number==4)))||(L->type==3)) L=getlex();    //true, false or numerical constant
 else ERROR(" SYNTAX ERROR: wrong lexem in operator");
      cout<<L->type<<"!"<<L->number<<endl;
 }


 
void OPERATOR ()
{
 if ((L->type==2)&&(L->number==2))
  {
   L=getlex();
   while ((L->type!=2)||(L->number!=3))
    {
     OPERATOR();
    }
   L=getlex();
  }
  else if((L->type==2)&&(L->number==3)) {return;}
  else
  {
   if ((L->type==1)&&(L->number==5)) {L=getlex(); IF();}
   else if ((L->type==1)&&(L->number==6)) {L=getlex(); WHILE();}
   else if ((L->type==1)&&(L->number==7)) {L=getlex(); READ();}
   else if ((L->type==1)&&(L->number==8)) {L=getlex(); WRITE();}
   else if ((L->type==1)&&(L->number==9)) {L=getlex(); CASE();}
   else if ((L->type==1)&&(L->number==12)) 
    {
     L=getlex();
     if ((L->type!=2)||(L->number!=9)) ERROR (" SYNTAX ERROR: no \";\" at the end of \"break\"-operator");
     L=getlex();
    }
   else
    {
     EQ();
     if ((L->type!=2)||(L->number!=9)) ERROR(" SYNTAX ERROR: no \";\" at the end of operator");
     L=getlex();
    }
  }
}



void IF()
{
 if ((L->type!=2)||(L->number!=0)) ERROR (" SYNTAX ERROR: missing \'(\' in \"if\"-comparison");
 L=getlex();
 EQ();
 if ((L->type!=2)||(L->number!=1)) ERROR (" SYNTAX ERROR: missing \')\' in \"if\"-comparison");

 L=getlex();
 OPERATOR ();
    cout<<L->type<<"*"<<L->number<<endl;

 if ((L->type!=1)||(L->number!=16)) ERROR (" SYNTAX ERROR: missing \"else\" in \"if\"-comparison");
 L=getlex();
     cout<<L->type<<"^"<<L->number<<endl;
 OPERATOR ();
}


void WHILE ()
{
 if ((L->type!=2)||(L->number!=0)) ERROR (" SYNTAX ERROR: missing \'(\' in \"while\"-loop");
 L=getlex();
 EQ();
 if ((L->type!=2)||(L->number!=1)) ERROR (" SYNTAX ERROR: missing \')\' in \"while\"-loop");
 L=getlex();
 if((L->type==2)&&(L->number==3)) ERROR (" SYNTAX ERROR: missing operator in \"while\"-loop");;
 OPERATOR ();
}


void READ ()
{
 if ((L->type!=2)||(L->number!=0)) ERROR (" SYNTAX ERROR: missing \'(\' in \"read\"-operation");
 L=getlex();

 if (L->type!=4) ERROR (" SYNTAX ERROR: missing an identificator for a \"read\"-operation");

 L=getlex();
 if ((L->type!=2)||(L->number!=1)) ERROR (" SYNTAX ERROR: missing \')\' in \"read\"-operation");
 L=getlex();
 if ((L->type!=2)||(L->number!=9)) ERROR(" SYNTAX ERROR: no \";\" at the end of operator");
 L=getlex();
}

void WRITE ()
{
 if ((L->type!=2)||(L->number!=0)) ERROR (" SYNTAX ERROR: missing \'(\' in \"write\"-operation");
 L=getlex();

 if (L->type!=5) EQ (); else L=getlex();
 while ((L->type==2)&&(L->number==10))
  {
   L=getlex();
   if (L->type!=5) EQ (); else L=getlex();
  }
 if ((L->type!=2)||(L->number!=1)) ERROR (" SYNTAX ERROR: missing \')\' in \"write\"-operation");
 L=getlex();
 if ((L->type!=2)||(L->number!=9)) ERROR (" SYNTAX ERROR: no \";\" at the end of \"write\"-operation");
 L=getlex();
}

void ONE_CASE ()
{
 while ((L->type!=2)||(L->number!=19))
 {
  if (L->type!=3) ERROR (" SYNTAX ERROR: not a numerical value as a \"case\"-constant");
  L=getlex();
  if ((L->type!=2)||(L->number!=19))
   {
    if ((L->type!=2)||(L->number!=10)) ERROR (" SYNTAX ERROR: wrong delimeter between \"case\" elements");
    L=getlex();
   }
 }
 L=getlex();
 OPERATOR();
}

void LIST_OF_CASES ()
{
while ((L->type!=1)||(L->number!=11))
 {
 cout<<L->type<<"#"<<L->number<<endl;
  ONE_CASE ();
 }
}


void CASE ()
{
 if ((L->type!=2)||(L->number!=0)) ERROR (" SYNTAX ERROR: missing \'(\' in \"case\"-comparison");
 L=getlex();
 EQ ();
 if ((L->type!=2)||(L->number!=1)) ERROR (" SYNTAX ERROR: missing \')\' in \"case\"-comparison");

 L=getlex();
 if ((L->type!=1)||(L->number!=10)) ERROR (" SYNTAX ERROR: missing \"of\" in \"case\"-comparison");
 L=getlex();

 LIST_OF_CASES();
 cout<<L->type<<"^"<<L->number<<endl;
 if ((L->type!=1)||(L->number!=11)) ERROR (" SYNTAX ERROR: missing \"end\" in \"case\"-comparison");
 L=getlex();
 if ((L->type!=2)||(L->number!=9)) ERROR (" SYNTAX ERROR: no \";\" at the end of \"case\"-comparison");
 L=getlex();
}


void PROGRAM ()
{
 if ((L->type!=1)||(L->number!=0)) ERROR (" SYNTAX ERROR: not a program");
 L=getlex();
 if ((L->type!=2)||(L->number!=2)) ERROR (" SYNTAX ERROR: opening brace missing");
 L=getlex();
 while ( (L->type==1) &&
       ( (L->number==1) || (L->number==2) ) )
  {
   L=getlex();
   DESCRIPTION ();
  }
 while ((L->type!=2)||(L->number!=3))
  {
   OPERATOR();
  }
 if ((L->type!=2)||(L->number!=3)) ERROR (" SYNTAX ERROR: closing brace missing");
  cout<<endl<<("  syntax is correct  ")<<endl;
}



//------------------------------------------------------ MAIN ------------------------------------------------------

int main (int argc, char** argv)
{
 string s ;
 //lexem* L;
 open_file(argc,argv);


// P->print();
// while (q!=0)
//  {
//   P=getlex();
//   cout<<endl;
// P->print();
//  }

L=getlex();
PROGRAM ();

 mprog.close();
 getchar();
 return 0;
}
