#include "global.h"
struct entry keywords[]=
{
"if",IF,0,
"else",ELSE,0,
"while",WHILE,0,
"input",INPUT,0,
"print",PRINT,0,
"printn",PRINTN,0,
0,0,0,
};
void init(void)/* Загрузкаключевыхсловвтаблицусимволов */
{
struct entry *i;
for(i=keywords;i->token;i++)
insert(i->lexptr,i->token);
}
#include "global.h"
int CmpNextSym(int,int,int);
char lexbuf[BSIZE];
int lineno = 1;
double tokenval = NONE;
int lexan(void) /* Лексическийанализатор */
{
int t;
while (1)
{
t = fgetc(Open);// Считать в t символ из ранее открытого файла
if (t == ' ' || t == '\t'); /* Отбрасываем разделители-пробелы */
else if (t == '\n')// Если символ перевода строки, то
lineno++;// Увеличить счетчик линий
else if (isdigit(t)) /* t - цифра */
{
ungetc(t, Open);// Вернуть t во входной поток
fscanf(Open,"%lf",&tokenval);// Занести занчение числа (1 или > символов) в tokenval
return NUM;// Вернуть идентификатор числа
}
else if (isalpha(t)) /* t - буква */
{
int p, b = 0;
while (isalnum(t)) /* Пока t - букваилицифра */
{
lexbuf[b++] = t;// Добавить в буффер t
t=fgetc(Open);// Считать очередной символ
if (b >= BSIZE)// если превышен рзмер буффера
error("compiler error");// Вызов процедуры выхода с сообщением об ошибке
}
lexbuf[b] = EOS;// Добавить в буффер признак завершения последовательности символов (слова)
if (t != EOF)// Если t - не признак конца файла, то
ungetc(t, Open);// Вернуть t
p = lookup(lexbuf);// p = положение считанного слова в таблце символов
if (p == 0)// Если слово встретилось впервые
p = insert(lexbuf, ID);// Добавить в таблицу символов новую переменную
tokenval = p;
return symtable[p].token;// Вернуть соответствующий считанному слову идентификатор
}
else if (t == EOF) return DONE;// Если в t признак завершения файла - вернуть идентификатор конца программы
else switch(t)// Иначе, если t один из символов:
{
case '>':
return CmpNextSym('=',JG,JGE);// Если за t следует =, то вернуть инедтификатор условия JGE (больше-равно), иначе - JG (больше)
case '<':
return CmpNextSym('=',JL,JLE);// Меньше-равно, или меньше
case '!':
return CmpNextSym('=',JNE,'!');// Не равно, или символ !
case '=':
return CmpNextSym('=',JE,'=');// Равно (условие) или символ =
case ':':
return CmpNextSym('=',EQUAL,':');// Прсвоитьилисимвол :
case '{':
return BEGIN;// Вернутьидентификатор BEGIN
case '}':
return END;// Вернутьидентификатор END
default:// Если что-либо другое, то
tokenval=NONE;
return t;// Вернуть t
}
}
}
int CmpNextSym(int ch,int good,int bad)
{
int nc=fgetc(Open);// считать следующий символ
if(nc==ch) return good;//если следующий символ = ch - вернуть good
ungetc(nc,Open);//иначе, возврат символа во входной поток
return bad;// вернуть bad
}
#include "global.h"
int FillCode(void);
int FC(void);
int expr(void);
int term(void);
int factor(void);
int IdIn(void);
void LabelPush(int);
int LabelPop(void);
int match(int);
int lookahead;//текущий сканируемый входной токен
int LabelStack[100],LabelCnt=0;
double tv;
int parse(void)/* Разбор и трансляция списка выражений */
{
lookahead=lexan();// Чтение слова
while(lookahead!=DONE)// До тех пор, пока не будет получен идентификатор завершения программы
{
FillCode();// Заполнение таблицы кодов
}
return 0;// Возврат
}
int FillCode()
{
int t;
FC();// Обработкаслова
while(1)// Бесконечно повторять
{
switch(lookahead)
{
case ';'://Если текущее слово - символ ";", то
match(';');// Перейти к следующему слову
insertcode(0,";",0);// Добавить в таблицу клдлв ";"
FC();// Обработка слова
break;
default:
return;
}
}
}
int FC(void)
{
while(1)
{
switch(lookahead)
{
case ID:
match(ID);
tv=tokenval;
match(EQUAL);
expr();// Обработкавыражения
insertcode(EQUAL,symtable[tv].lexptr,0);// Добавить в таблицу кодов присваивание переменной
break;
case PRINTN:
match(PRINTN);
expr();// Обработка выражения
insertcode(PRINTN,"printn",0);// Добавить строчку в таблицу кодов
while(1)
{
switch(lookahead)
{
case ',':// Обработкааргументов, введенных через запятую
match(',');
expr();
insertcode(PRINTN,"printn",0);
break;
default:
return;
}
}
case INPUT:
match(INPUT);
IdIn();// Добваить в таблицу кодов строчку получения заначения переменной
break;
case PRINT:
match(PRINT);
expr();
insertcode(PRINT,"print",0);
while(1)
{
switch(lookahead)
{
case ',':
match(',');
expr();
insertcode(PRINT,"print",0);
break;
default:
return;
}
}
case BEGIN:
match(BEGIN);
FillCode();// Вызов процедуры обработки слов (вначале проверится слово, затем ";")
match(END);
break;
case IF:
match(IF);
match('(');
expr();
insertcode(THEN,"then",0);
LabelPush(lastcode);// Добавитьметку
match(')');
FC();
codetable[LabelPop()].value=lastcode+1;// Изменить занчение в строке метки, для указания на нужную строчку
insertcode(GOTO,"else",0);
LabelPush(lastcode);// Добавитьметку
match(ELSE);
FC();
codetable[LabelPop()].value=lastcode;// Изменить занчение в строке метки, для указания на нужную строчку
break;
case WHILE:
insertcode(WHILE,"while",0);
LabelPush(lastcode);
match(WHILE);
match('(');
expr();
match(')');
insertcode(DO,"do",0);
LabelPush(lastcode);
FC();
codetable[LabelPop()].value=lastcode+1;
insertcode(GOTO,"goto",LabelPop());
break;
default:
return;
}
}
}
int expr(void)
{
term();// Ввызов вспомогательной процедуры разбора
while(1)
{
switch(lookahead)// Обработка операций + - и логических уловий
{
case '+':
match(lookahead);// Перейти к следующему слову
term();
insertcode('+',"+",0);
break;
case '-':
match(lookahead);
term();
insertcode('-',"-",0);
break;
case JNE:
match(lookahead);
term();
insertcode(JE,"!=",0);
break;
case JE:
match(lookahead);
term();
insertcode(JNE,"==",0);
break;
case JL:
match(lookahead);
term();
insertcode(JL,"<",0);
break;
case JLE:
match(lookahead);
term();
insertcode(JLE,"<=",0);
break;
case JG:
match(lookahead);
term();
insertcode(JG,">",0);
break;
case JGE:
match(lookahead);
term();
insertcode(JGE,">=",0);
break;
default:
return;
}
}
}
int term()
{
factor();// Ввызов вспомогательной процедуры разбора
while(1)
{
switch(lookahead)// Обработка матемтических операций типа *, /
{
case '*':
match(lookahead);
factor();
insertcode('*',"*",0);
break;
case '/':
match(lookahead);
factor();
insertcode('/',"/",0);
break;
default:
return;
}
}
}
int factor(void)
{
switch(lookahead)
{
case NUM:
insertcode(NUM,"num",tokenval);
match(NUM);
break;
case ID:
insertcode(ID,symtable[tokenval].lexptr,0);
match(ID);
break;
case '(':
match('(');
expr();
match(')');
break;
default:
error("syntax error");
}
return 0;
}
int IdIn()
{
insertcode(INPUT,symtable[tokenval].lexptr,0);
match(ID);
while(1)
{
switch(lookahead)
{
case ',':
match(',');
insertcode(INPUT,symtable[tokenval].lexptr,0);
match(ID);
break;
default:
return;
}
}
}
void LabelPush(int n)// Добавить метку в стек
{
LabelStack[LabelCnt++]=n;
}
int LabelPop(void)// Извлечь метку из стека
{
LabelCnt--;
return LabelStack[LabelCnt];
}
int match(int t)//процедура переходит к следующему входному токену, если ее аргумент t совпадает со сканируемым символом.
{
if(lookahead==t)// Если t совпадает со сканируемым словом, то
lookahead=lexan();// Считать следующее слово
else error("syntax error");// Иначе - вывод ошибки, выход
return 0;
}
#include "global.h"
#defineSTRMAX 1000 /* Размер массива лексем */
#define SYMMAX 1000 /* Размер таблицы символов */
#define CODEMAX 1000/* Размер таблицы кодов */
char lexemes[STRMAX];
int lastchar = -1; /* Последняя использованная позиция в lexemes */
struct entry symtable[SYMMAX];
int lastentry = 0; // Последняя использованная позиция в таблице символов
char lexgen[STRMAX];
int lastlexgen = -1;
struct code codetable[CODEMAX];
int lastcode = 0; /* Последняяиспользованнаяпозициявтаблицекодов */
int lookup(char s[]) /* Возвращает положение в таблице символов для s */
{
int i;
for(i = lastentry; i > 0; i--)
if (strcmp(symtable[i].lexptr, s) == 0)
return i;
return 0;
}
int insert(char s[], int tok) /* Добавитьстрочкувтаблицусимволов */
{
int len;
len = strlen(s); /* strlen вычисляетдлинустроки */
if (lastentry + 1 >= SYMMAX)
error("symbol table full");
if (lastchar + len + 1 >= STRMAX)
error("lexemes array full");
lastentry++;
symtable[lastentry].token = tok;
symtable[lastentry].lexptr = &lexemes[lastchar + 1];
lastchar += len + 1;
strcpy(symtable[lastentry].lexptr, s);
return lastentry;
}
int insertcode(int tok,char s[],double value){ //Добавлениевтаблицукодов
int len;
len=strlen(s);
if(lastcode+1>=CODEMAX)
error("code table full");
if(lastlexgen+len+1>=STRMAX)
error("lexemes array full");
lastcode++;
codetable[lastcode].value = value;
codetable[lastcode].token = tok;
codetable[lastcode].lexptr = &lexgen[lastlexgen+1];
lastlexgen+=len +1;
strcpy(codetable[lastcode].lexptr,s);
return lastcode;
}
int get_codetable()// Вывеститаблицукодов
{
int i;
for(i=1;i<=lastcode;i++)
printf("%d %d %s %g\n",i,codetable[i].token,codetable[i].lexptr,codetable[i].value);
return 0;
}
int get_symtable()// Вывеститаблицусимволов
{
int i;
for(i=1;i<=lastentry;i++)
printf("%d %d %s %g\n",i,symtable[i].token,symtable[i].lexptr,symtable[i].value);
return 0;
}
#include "global.h"
double stack[1000];
int j=0;
int a;
double pop(void);
void push(double n);
double x,y,z;
int emit(void) //Выполнениепрограммы
{
int i=0;
while(i<lastcode)// Выполнять, пока не достигнут конец таблицы кодов
{
switch(codetable[i].token)// Выполнить действие, в соответствии с прочитанным словом из таблицы кодов
{
case NUM:
push(codetable[i].value);
break;
case ID:
push(symtable[lookup(codetable[i].lexptr)].value);
break;
case '+':
y=pop();
z=pop();
push(z+y);
break;
case '-':
y=pop();
z=pop();
push(z-y);
break;
case '*':
y=pop();
z=pop();
push(z*y);
break;
case '/':
y=pop();
z=pop();
push(z/y);
break;
case EQUAL:
symtable[lookup(codetable[i].lexptr)].value=pop();
break;
case JE:
y=pop();
z=pop();
push(y==z);
break;
case JNE:
y=pop();
z=pop();
push(y!=z);
break;
case JL:
y=pop();
z=pop();
push(y<z);
break;
case JLE:
y=pop();
z=pop();
push(y<=z);
break;
case JG:
y=pop();
z=pop();
push(y>z);
break;
case JGE:
y=pop();
z=pop();
push(y>=z);
break;
case DO:
if(pop()==1)i=codetable[i].value;// Если условие выполнено - перейти в соответствующую строку
break;
case GOTO:
i=codetable[i].value;
break;
case THEN:
if(pop()==1)i=codetable[i].value;
break;
case PRINT:
printf("%g \n",pop());
break;
case PRINTN:
a = pop();
printf("%d \n",a);
break;
case INPUT:
scanf("%lf,",&symtable[lookup(codetable[i].lexptr)].value);
break;
}
i++;
}
return 0;
}
void push(double n)//Положитьвстек
{
stack[j++]=n;
}
double pop()//Извлечьизстека
{
j--;
return stack[j];
}
#include"global.h"
int error(char *s)
{
printf("%s in line %d\n",s,lineno); // вывод сообщения об ошибке в конкретной строке
getch();
exit(1); // выход
return 0;
}
Список использованной литературы
1. А. Ахо, Р. Сети, Д. Ульман Компиляторы: принципы, технологии и инструменты.: Пер. с англ. — М.: Издательский дом "Вильяме", 2003. — 768 с.
2. Липпман C++ для начинающих. – 1194 с.
3. Флоренсов А.Н. Операционные системы: Учеб. пос. - Омск: Издательство ОмГТУ, 2005. – 160 с.