Подразделы

Другие разделы

Дата и время

05/05/2024 05:51:57

Авторизация

Имя:
Пароль:
Зарегистрироваться
Восстановить пароль
 

printПримеры для средств разработки трасляторов

printBison+Flex

Пример интерпретатора простого языка типа BASIC, в котором есть комментарии (смотри пример), операторы присваивания, ввода (INPUT), вывода (PRINT), ветвления (IF…THEN…ELSE…END IF) и цикла (WHILE…WEND).
Суммарный объем 222 строки, аналогичный код в CAIO – 118 строк.
basic.lex:
%option case-insensitive noyywrap bison
%top{
#include "basic.h"
static string s;
%}
%x S_STRING
%%
else	return ELSE;
end	return END;
if	return IF; 
input	return INPUT; 
mod	return MOD;
print	return PRINT;
then	return THEN;
wend	return WEND;
while	return WHILE;
[-()*+/=\n]	return yytext[0]; 
[ \t\r]		;
"/'"(.|\n)*?"'/"|'.*	;
\d+	{ yylval.int_=stoi(yytext);  return NUMBER; }
[a-zA-Z]\w*	{ yylval.int_=find_id(yytext);  return IDENT; }
\"	{  BEGIN(S_STRING); s=""; }
<S_STRING>\"\"	{  s+='"'; 	}
<S_STRING>\"	{  BEGIN(INITIAL); 
                   yylval.int_=tc.size(); 
                   tc.push_back(s);
                   return (STRING); 
                }
<S_STRING>.	s+=yytext;
<S_STRING>\n	yyerror("Ошибка в строке"); 
.		;
%%
void yystart(FILE *f)
{ yyrestart(f);
}
basic.grm:
%define parse.error verbose
%{
#include "basic.h"
%}
%union {
  int int_;
  list<Statement> * Code_;
  Expr Expr_;
  Statement Statement_;
}
%token ELSE "else" END "end" IF "if" INPUT "input" MOD "mod" 
%token PRINT "print" THEN "then" WEND "wend" WHILE "while"
%token <int_> IDENT "?идент?" STRING "?строка?" NUMBER "?число?"
%type <Code_> code optelse
%type <Expr_> expr
%type <Statement_> operator
%left '+' '-'
%left '*' '/' "mod"
%left UMINUS
%destructor { delete $$; } <Statement_>
%destructor { delete $$; } <Expr_>
%destructor { for(auto s:*$$) delete s; delete $$; } <Code_>
%%
program: code	{ interpret($1); }
	;
code	: { $$=new list<Statement>(); }
        | code operator '\n' { $$=$1; $$->push_back($2); $1=nullptr; }
	;
operator: { $$=new emptystmt(); }
	| IDENT  '=' expr	{ $$=new assign($1,$3); }
	| "input"  IDENT 	{ $$=new input($2); }
	| "print"  expr	{ $$=new print($2); }
	| "print"  STRING 	{ $$=new printstr($2); }
	| "while"  expr '\n' code "wend"	{ $$=new whilestmt($2,$4); }
	| "if"  expr optthen '\n' code optelse "end" "if" { $$=new ifstmt($2,$5,$6); }
	;
expr	: expr '+' expr	{ $$=new op2('+',$1,$3); }
	| expr '-' expr	{ $$=new op2('-',$1,$3); }
	| expr '*' expr	{ $$=new op2('*',$1,$3); }
	| expr '/' expr	{ $$=new op2('/',$1,$3); }
	| expr "mod" expr { $$=new op2('%',$1,$3); }
	| '-' expr %prec UMINUS	{ $$=new op2('-',new number(0),$2); }
	| '(' expr ')'	{ $$=$2; }
	| NUMBER 	{ $$=new number($1); }
	| IDENT 	{ $$=new ident($1); }
	;
optthen	: | "then" ;
optelse	: { $$=new list<Statement>(); }
        | "else" '\n' code	{ $$=$3; }
	;
%%
int mem[1000]; 
int eval(Expr e)
{ if(auto n=dynamic_cast<op2 *>(e)) {
    switch(n->op)
    { case '+': return eval(n->x)+eval(n->y);
      case '-': return eval(n->x)-eval(n->y);
      case '*': return eval(n->x)*eval(n->y);
      case '/': return eval(n->x)/eval(n->y);
      case '%': return eval(n->x)%eval(n->y);
    }
  }
  else if(auto n=dynamic_cast<number *>(e)) {
    return n->x;
  }
  else if(auto n=dynamic_cast<ident *>(e)) {
    return mem[n->v];
  }
}
void interpret(list<Statement> *p) 
{ for(auto s:*p)
  { if(auto n=dynamic_cast<assign *>(s)) mem[n->v]=eval(n->e);
    else if(auto n=dynamic_cast<input *>(s)) cin>>mem[n->v];
    else if(auto n=dynamic_cast<print *>(s)) cout<<eval(n->e)<<endl;
    else if(auto n=dynamic_cast<printstr *>(s)) cout<<tc[n->c]<<endl;
    else if(auto n=dynamic_cast<whilestmt *>(s)) {
      while(eval(n->e)) interpret(n->p1);
    }
    else if(auto n=dynamic_cast<ifstmt *>(s)) {
      if(eval(n->e)) interpret(n->p1);
      else interpret(n->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;
}
vector<string> tc; 
void yyerror(const char* msg)
{ cerr<<msg<<"\n";
  exit(1);
}
int main(int argc, char **argv)
{ if(argc>1)
  { FILE *f=fopen(argv[1],"r");
    if(!f) yyerror("Can't open file");
    else yystart(f);
  }
  return yyparse(); 
}
basic.h:
#ifndef BASIC_H
#define BASIC_H 1
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <iostream>
#include <map>
#include <list>
#include <vector>
#include <string>
using namespace std;
struct _domain {
  virtual ~_domain(){}
};
struct Expr_domain : _domain {};
typedef Expr_domain *Expr;
struct Statement_domain : _domain {};
typedef Statement_domain *Statement;
struct op2 : Expr_domain {
	char op;
	Expr x,y;
	op2(char op, Expr x, Expr y):op(op), x(x), y(y){}
	~op2() { delete x; delete y; }
};
struct ident: Expr_domain {
	int v;
	ident(int v):v(v){}
};
struct number: Expr_domain {
	int x;
	number(int x):x(x){}
};
struct assign: Statement_domain {
	int v;
	Expr e;
	assign(int v, Expr e):v(v), e(e){}
	~assign() { delete e; }
};
struct ifstmt : Statement_domain {
	Expr e;
	list<Statement>* p1;
	list<Statement>* p2;
	ifstmt(Expr e, list<Statement>* p1, list<Statement>* p2):e(e), p1(p1), p2(p2){}
	~ifstmt() {
	  delete e;
	  for(auto s:*p1) delete s;
	  for(auto s:*p2) delete s;
	  delete p1;
	  delete p2;
	}
};
struct input: Statement_domain {
	int v;
	input(int v):v(v){}
};
struct print: Statement_domain {
	Expr e;
	print(Expr e):e(e){}
	~print() { delete e; }
};
struct printstr : Statement_domain {
	int c;
	printstr(int c):c(c){}
};
struct whilestmt : Statement_domain {
	Expr e;
	list<Statement> *p1;
	whilestmt(Expr e, list<Statement> *p1):e(e), p1(p1){}
	~whilestmt() {
	  delete e;
	  for(auto s:*p1) delete s;
	  delete p1;
	}
};
struct emptystmt : Statement_domain {};
void yystart(FILE *);
int yylex();
void yyerror(const char*);
void interpret(list<Statement> *);
int find_id(string name);
extern vector<string> tc;
#include "y.tab.h"
#endif
Запуск интерпретатора:
program test.prg
Пример программы test.prg:
/' Программа для проверки гипотезы Коллатца (гипотеза 3n+1):
   какое бы начальное число n мы ни взяли,
   рано или поздно мы получим единицу
'/
print "Введите n:"
input n
k=0
while n-1
  if n mod 2 then ' если n нечетное
    n=n*3+1
  else
    n=n/2
  end if
  print n
  k=k+1
wend
print "Количество итераций"
print k
loading