%option case-insensitive locations astprint lexprint
%operator <yfx> '+' '-'
%operator <yfx> '*' '/' 
%operator <fy> '-'
%type <int> ?число? ?идент?
%type <Statement> оператор
%type <Expr> выр
%{
#include <string>
#include <iostream>
#include <map>
#include <cctype>
using namespace std;
int find_id(string name);
}
%% // правила для лексического анализатора
[ \t\r] 				; // пропустить пробелы
\d+ 					?число?  <stoi(yytext)>
[a-zA-Z]\w*				?идент?  <find_id(yytext)>
%% // правила для синтаксического анализатора
программа = код  			<$1>
	  ;
код = { оператор '\n' }
    ;
оператор = 					
  | ?идент? '=' выр 			<assign($1,$3)>
  | "input" ?идент?  			<input($2)>
  | "print" выр  			<print($2)> 
  | "while" выр '\n' код "wend" 	<whilestmt($2,$4)> 	
  | "if" выр ["then"] '\n'  код
     [ "else" '\n' код 			
     ] "end" "if" 			<ifstmt($2,$5,$6)> 	
  ;
выр = выр '+' выр			<plus($1,$3)>
    | выр '-' выр 			<minus($1,$3)>
    | выр '*' выр 			<mult($1,$3)>
    | выр '/' выр 			<divide($1,$3)>
    | '-' выр 				<neg($2)>
    | '(' выр ')'
    | ?число? 				<number($1)>
    | ?идент?				<ident($1)>
    ;
%%
int mem[1000]; // память для данных
visitor eval<Expr,int> { // вычисление выражения
  visit plus(x, y): return eval(x)+eval(y);
  visit minus(x, y): return eval(x)-eval(y);
  visit mult(x, y): return eval(x)*eval(y);
  visit divide(x, y): return eval(x)/eval(y);
  visit neg(x):  return -eval(x);
  visit number(x):  return x;
  visit ident(x): return mem[x];
}
void yyinterpret(List<Statement> p) // выполнение операторов
{ for(auto s:p)
    match s {
      rule assign(v, e): mem[v]=eval(e);
      rule input(v): cin>>mem[v];
      rule print(e): cout<<eval(e)<<endl;
      rule whilestmt(e,p1): while(eval(e)) yyinterpret(p1);
      rule ifstmt(e,p1,p2): if(eval(e)) yyinterpret(p1);
                            else yyinterpret(p2);
    }
}
map<string,int> ti; // таблица идентификаторов
int find_id(string name) // поиск в таблице
{ for(auto &ch:name) ch=toupper(ch);
  int k=ti[name];
  if(k==0) k=ti[name]=ti.size();
  return k;
}
