Омский Государственный Технический Университет
Кафедра информатики и вычислительной техники
Курсовая работа по дисциплине: "спо".
-
Выполнил:
Иваненко А.А. В-411
Проверил:
Флоренсов А.Н.
ОМСК 2005
Задание №6
Используя компилятор компиляторов BISON или ZUBR разработать интерпретатор с языка программирования, который описательно задается следующими определениями:
-
язык обеспечивает вычисления на основе типа double языка Си (используемого компилятором компиляторов) и допускает использование одномерных массивов;
-
для задания массивов используются описания вида:
massive имя_массива[размерность_массива];
где размерность_массива задается целым числом;
-
переменная определяется либо как идентификатор, либо как идентификатор, за которым в квадратных скобках записано обозначение переменной или константы;
-
в левой части оператора присваивания может стоять обычная или индексированная переменная;
-
арифметические выражения могут использоваться сколь угодно сложной структуры, но не должны содержать обращений к функциям;
-
язык содержит операторы цикла, задаваемые ключевым словом while, и условные операторы if, причем возможно использование этого оператора как с частью else, так и без нее; допускаются операторы break и continue;
-
условия задаются в виде
выражение опреация_сравнения выражение
- для выдачи результатов служат операторы
оut список_переменных
outn список_переменных
причем оператор outn выдает округленные целые значения переменных, а для ввода оператор in список_переменных
где список_переменных представляет собой перечисление через запятую;
-
остальные синтаксические элементы языка выбираются разработчиком самостоятельно;
-
имена программных объектов должны формироваться по общеупотребительному правилу: первым символом должна быть произвольная латинская буква, последующими символами могут быть цифры или латинские буквы.
Листинг программы
comp.y – файл исходника для zubra:
//---------------------------------------------------------------------------------------------------------------
%{
#include"main.h"
%}
%token NUMBER IDENT DOUBLE WHILE DO IF ELSE THEN BEGIN END JE JNE JG JL JGE JLE OUT IN OUTN
%union{
float val;
int postoken;
}
%%
begin : declaration program
;
declaration : DOUBLE IDENT ';' declaration { dobavperem(poiskslova($2.postoken),0); }
| /* e */
;
program : BEGIN cmp_stmt END
;
cmp_stmt : stmt_list
| /* e */
;
stmt_list : stmt_list ';' stmt
| stmt
;
stmt : IDENT '=' expression { if(poiskperem(poiskslova($1.postoken))==0) zubr_error("нет такой переменной");
command('=',poiskslova($1.postoken),0); }
| WHILE { command(WHILE, "while", 0); posWHILE=lentryc; }
cmp DO { command(DO, "do", 0); }
stmt { command(STOPUN,"stopun",posWHILE); }
| IF { command(IF,"if",0); }
cmp THEN { command(THEN,"then",0); }
stmt else
| OUT { command(OUT, "write",0); } indent_list { command(STOP,"stop",0); }
| OUTN { command(OUTN,"writen",0); } indent_list { command(STOP,"stop",0); }
| IN { command(IN, "read",0); } indent_list { command(STOP,"stop",0); }
| program
| /* e */
;
else : ELSE { command(ELSE,"else",0); } stmt { command(STOPIF,"stopif",0); }
| /* e */ { command(STOPIF,"stopif",0); }
;
indent_list: indent_list ',' IDENT { command(IDENT,poiskslova($3.postoken),0); }
| IDENT { command(IDENT,poiskslova($1.postoken),0); }
;
cmp : expression JE expression { command(JE ,"==",0); }
| expression JNE expression { command(JNE,"!=",0); }
| expression JG expression { command(JG ,">", 0); }
| expression JL expression { command(JL ,"<", 0); }
| expression JGE expression { command(JGE,">=",0); }
| expression JLE expression { command(JLE,"<=",0); }
| expression
;
expression : expression '+' terminal { command('+',"+",0); }
| expression '-' terminal { command('-',"-",0); }
| terminal
;
terminal : terminal '*' factor { command('*',"*",0); }
| terminal '/' factor { command('/',"/",0); }
| factor
;
factor : '(' expression ')'
| IDENT { if(poiskperem(poiskslova($1.postoken))==0)
zubr_error("not declaration type");
command(IDENT,poiskslova($1.postoken),0); }
| NUMBER { command(NUMBER,"4uslo",$1.val); }
;
%%
#include"table.c"
#include"stack.c"
#include"perem.c"
#include"interpret.c"
FILE *openfile;
/*--------------------------------- Вывод ошибки ----------------------------------------*/
void zubr_error(char *s) {
printf("Error: %s on %d\n",s,LineStr);
exit(1);
}
/*--------------------------------Сравнение символов---------------------------------------*/
int compare(int ex, int Y, int N) {
int TN=fgetc(openfile);
if(TN==ex)return Y;
ungetc(TN,openfile);
return N;
}
/*---------------------------Лексический анализатор-------------------------------------*/
int zubr_lex(void) {
int c;
while(1)
{
c=fgetc(openfile);
if(c == ' '||c == '\t') ;
else
if(c == '\n') LineStr++; /*считаем строки*/
else if(isdigit(c)) /*считываем число */
{
ungetc(c,openfile);
fscanf(openfile,"%g",&zubr_lval.val);
return NUMBER;
}
else if(isalpha(c)) /*считываем индетификатор */
{
int p,b = 0;
while(isalnum(c))
{
LexBuf[b++]=c;
c=fgetc(openfile);
if(b >= 128)
{
zubr_error("compiler error");
exit(1);
}
}
LexBuf[b]='\0';
if(c!=EOF)
ungetc(c,openfile);
p = poisk(LexBuf);
if(p == 0)
p = dobavit(LexBuf,IDENT);
zubr_lval.postoken=p;
return TableN[p].token;
}
else {
switch(c) {
case '>': return compare('=',JGE,JG);
case '<': return compare('=',JLE,JL);
case '!': return compare('=',JNE,'!');
case '=': return compare('=',JE,'=');
default:
return c;
}
}
}
}
void print(){
int i;
for(i=0;i<=lentryc;i++)
printf("%d %s %d\n",i,COM[i].n1,COM[i].zn1);
}
/*------------------------------ Главная программа -------------------------------------*/
void main(int argc,char *argv[]) {
if((openfile=fopen(argv[1],"r"))==NULL){
printf("not declarate file\n");
exit(1);
}
rezervirov();
zubr_parse();
run();
fclose(openfile);
// print();
}
interpret.c – файл интерпритатора:
//--------------------------------------------------------------------------------------------------------
int lentryc = 0;
struct intercommand{
int pos;
int COMMAND;
char *n1;
float zn1;
}COM[1000];
int command(int com, char *s1,float zn1) {
lentryc++;
COM[lentryc].n1=malloc(strlen(s1)+1);
COM[lentryc].COMMAND = com;
strcpy(COM[lentryc].n1, s1);
COM[lentryc].zn1 = zn1;
return LastEntry;
}
void run(void)
{
int tab,srav;
float t;
float b=0,c=0;
for(tab=1;tab<=lentryc;tab++){
if(COM[tab].COMMAND=='+') {
pop(&b);
pop(&c);
push(c+b);
}
if(COM[tab].COMMAND=='-') {
pop(&b);
pop(&c);
push(c-b);
}
if(COM[tab].COMMAND=='*') {
pop(&b);
pop(&c);
push(c*b);
}
if(COM[tab].COMMAND=='/') {
pop(&b);
pop(&c);
push(c/b);
}
if(COM[tab].COMMAND==IDENT) {
push(poisktipaperem(COM[tab].n1));
}
if(COM[tab].COMMAND==NUMBER) {
push(COM[tab].zn1);
}
if(COM[tab].COMMAND=='=') {
pop(&b);
changeperem(COM[tab].n1,b);
}
if(COM[tab].COMMAND==JG) {
pop(&b);
pop(&c);
push(c>b);
}
if(COM[tab].COMMAND==JL) {
pop(&b);
pop(&c);
push(c<b);
}
if(COM[tab].COMMAND==JE) {
pop(&b);
pop(&c);
push(c==b);
}
if(COM[tab].COMMAND==JNE) {
pop(&b);
pop(&c);
push(c!=b);
}
if(COM[tab].COMMAND==JLE) {
pop(&b);
pop(&c);
push(c<=b);
}
if(COM[tab].COMMAND==JGE) {
pop(&b);
pop(&c);
push(c>=b);
}
if(COM[tab].COMMAND==THEN) {
pop(&b);
push(b);
if(b==0)
while(COM[tab].COMMAND!=ELSE&&COM[tab].COMMAND!=STOPIF)tab++;
}
if(COM[tab].COMMAND==ELSE) {
pop(&b);
if(b==1)
while(COM[tab].COMMAND!=STOPIF)tab++;
}
if(COM[tab].COMMAND==DO) {
pop(&b);
push(b);
if(b==0)
while(COM[tab].COMMAND!=STOPUN)tab++;
}
if(COM[tab].COMMAND==STOPUN) {
pop(&b);
push(b);
if(b==1)
tab=COM[tab].zn1;
}
if(COM[tab].COMMAND==STOPIF) {
pop(&b);
}
if(COM[tab].COMMAND==OUT) {
tab++;
while(COM[tab].COMMAND!=STOP) {
printf("%f ",poisktipaperem(COM[tab].n1));
tab++;
}
}
if(COM[tab].COMMAND==OUTN) {
tab++;
while(COM[tab].COMMAND!=STOP)
{
printf("%f\n",poisktipaperem(COM[tab].n1));
tab++;
}
}
if(COM[tab].COMMAND==IN) {
tab++;
while(COM[tab].COMMAND!=STOP) {
float n;
scanf("%g",&n);
changeperem(COM[tab].n1,n);
tab++;
}
}
}
}
//-------------------------------------------------------------------------------------------------------------------
main.h – файл переменных:
//-------------------------------------------------------------------------------------------------------------------
#include<string.h>
#include<ctype.h>
#include<stdio.h>
#define MAX_TABLE 128
#define MAX_STR 1000
#define STOP 1001
#define STOPUN 1002
#define STOPIF 1003
extern int dobavit(char s[],int t);
extern char *poiskslova(int t);
extern int poisk(char s[]);
extern void rezervirov(void);
extern void zubr_error(char *s);
extern int dobavperem(char s[],int type);
extern int poiskperem(char s[]);
extern int command(int command,char *s1,float zn1);
extern void run(void);
//-------------------------------------------------------------------------------------------------------------------
perem.c – файл работы с переменными:
//-------------------------------------------------------------------------------------------------------------------
struct peremen{
char *name;
float DOUB;
int type;
}PR[MAX_TABLE];
int lentryp = 0;
int lcharp = -1;
int poiskperem(char s[]) {
int tab;
for(tab=lentryp;tab>0;tab--)
if(strcmp(PR[tab].name,s) == 0)
return tab;
return 0;
}
int dobavperem(char s[],int type) {
if(poiskperem(s)==0) {
int len;
len=strlen(s);
if(lentryp+1>=MAX_TABLE)
zubr_error("table symbol is full");
if(lentryp + len + 1>=MAX_STR)
zubr_error("lexemes size of");
lentryp++;
PR[lentryp].type = type;
PR[lentryp].name = &LexWords[lcharp+1];
lcharp +=len+1;
strcpy(PR[lentryp].name, s);
return lentryp;
}else {
zubr_error("not second declarate");
}
}
float poisktipaperem(char *s) {
int tab;
for(tab=lentryp;tab>0;tab--)
if(strcmp(PR[tab].name,s) == 0)
return PR[tab].DOUB;
return -1;
}
int poiskperemzn(char *s) {
int tab;
for(tab=lentryp;tab>0;tab--)
if(strcmp(PR[tab].name,s) == 0)
return PR[tab].type;
return -1;
}
float changeperem(char *s,float n) {
int tab;
for(tab=lentryp;tab>0;tab--)
if(strcmp(PR[tab].name,s) == 0){
PR[tab].DOUB=n;
return PR[tab].DOUB;
}
return -1;
}
stack.c – файл стека:
//-------------------------------------------------------------------------------------------------------------------
float stack[100]; //СТЕК
int istack=0; //позиция курсора в стеке
void push(float n){
if(istack!=999){
stack[istack]=n;
istack++;
}
}
void pop(float *n){
if(istack!=0){
istack--;
*(n)=stack[istack];
}
}
//-------------------------------------------------------------------------------------------------------------------
table.c – файл таблицы символов:
//-------------------------------------------------------------------------------------------------------------------
int posIF;
int posWHILE;
char LexWords[MAX_STR];
int LastChar = -1;
struct TableContents
{
char *nameword;
int token;
};
struct TableContents TableN[MAX_TABLE];
int LastEntry = 0;
struct TableContents words[]=
{
"double", DOUBLE,
"begin" , BEGIN,
"end" , END,
"while" , WHILE,
"do" , DO,
"if" , IF,
"then" , THEN,
"else" , ELSE,
"outn" , OUTN,
"out" , OUT,
"in" , IN,
0 , 0
};
int LineStr=1;
char LexBuf[128];
void rezervirov(void) {
struct TableContents *tab;
for(tab=words;tab->token;tab++)
dobavit(tab->nameword,tab->token);
}
int poisk(char s[]) {
int tab;
for(tab=LastEntry;tab>0;tab--)
if(strcmp(TableN[tab].nameword,s) == 0)
return tab;
return 0;
}
int dobavit(char s[],int t) {
int Len;
Len=strlen(s);
if(LastEntry+1>=MAX_TABLE)
zubr_error("symbol table full");
if(LastEntry + Len + 1>=MAX_STR)
zubr_error("lexemes array full");
LastEntry++;
TableN[LastEntry].token = t;
TableN[LastEntry].nameword = &LexWords[LastChar+1];
LastChar +=Len+1;
strcpy(TableN[LastEntry].nameword, s);
return LastEntry;
}
char *poiskslova(int t) {
int tab;
for(tab=LastEntry;tab>0;tab--)
if(tab == t)
return TableN[tab].nameword;
return 0;
}