Описание тестового примера
Введение
В настоящее время языки высокого уровня стали основным средством разработки программ. Поэтому компиляторы составляют существенную часть системного программного обеспечения ЭВМ. Сегодня только очень малая часть программного обеспечения, требующая особой эффективности, разрабатывается с помощью ассемблеров. В настоящее время имеет применение довольно большое количество языков программирования. Наряду с традиционными языками, такими, например, как Фортран, широкое распространение получили так называемые «универсальные» языки (Паскаль, Си, Модула-2, Ада) и др., а также некоторые специализированные (например, язык обработки списочных структур Лисп). Кроме того, большое распространение получили языки, связанные с узкими предметными областями, такие, как входные языки пакетов прикладных программ. Для ряда названных языков имеется довольно много реализаций для различных операционных систем и архитектур ЭВМ. В рамках традиционных последовательных машин развивается большое число различных направлений архитектур. Примерами могут служить архитектуры CISC, RISC. Такие ведущие фирмы, как Intel, Motorola, Sun, начинают переходить на выпуск машин с RISC-архитектурами. Естественно, для каждой новой системы команд требуется полный набор новых компиляторов с распространенных языков. Поэтому важную роль компиляторов в современном системном ПО для ЭВМ невозможно переоценить. В данной курсовой работе делается попытка создания простого интерпретатора с целью изучения принципов строения и работы этого вида системного ПО.
Техническое задание
В данной курсовой работе требуется: Создать программу-интерпретатор, способную получать на входе текстовый файл (в формате ASCII или ANSI) с текстом программы. На выходе - выводит на экран результаты вычислений, определяемых программистом. Если входная программа содержит ошибку - сообщение о типе ошибки.
Интерпретатор должен воспринимать и обрабатывать следующие инструкции: а) объявление переменной с одновременным присвоением ей начального значения Имя Переменной = значение или Имя Переменной = выражение Значение переменной задается вещественным числом в десятичной системе счисления. Например, X=0.06 Выражения записываются по правилам, Например, F=-X/0.01 б) вывод результатов на экран PRINT (Имя Переменной) или PRINT (выражение) Например, PRINT(X) и PRINT(X+F) в) Операндами выражения могут быть вещественные числа и имена объявленных ранее переменных. В выражении допускаются следующие операторы: + сумма; разность, унарный минус; * произведение; / частное; ABS(…) модуль числа; ^ возведение в степень (степень выражается целым числом ³0); SQRT(…) квадратный корень; EXP(…) экспонента; LN(…) натуральный логарифм. Порядок выполнения операций может регулироваться скобками (). Инструкции в тексте программы разделяются точкой с запятой, либо каждая инструкция - с новой строки.
Разработка грамматики Список допустимых лексем (слов языка). Допустимыми являются: имя переменной <имя переменной> = L<C>; (L - буква, C - цифра) зарезервированные слова <зарезервированные слова> = <'print', 'abs', 'sqrt', 'exp', 'ln'> используемые символы <символы> = <'+', '-', '/', '*', '(', ')', '.', '^'> Все буквы - маленькие латинские. Программа состоит из двух основных блоков, парсера и лексера. Парсер отвечает за разбиение на токены, а лексер анализирует токены, и в зависимости от содержимого выполняет над ними действия.
Описание программы
Программа-интерпретатор выполнена с использованием среды разработки Borland С++ 6.0 и представляет собой интерактивную оболочку, позволяющую загружать исходный ASCII-текст, содержащий программу, написанную в соответствии с синтаксисом входного языка.
интерпретатор текстовый файл лексема Интерфейс программы
Интерфейс программы состоит из формы (Form1), также ее можно считать диалоговым окном между пользователем и программой выполняющей вычисление по заданному алгоритму. На форме также расположены Panel1, RichEdit1, MainMenu1 и OpenDialog1. Свойства для компонентов Panel 1: - Высота (Height) = 289 Ширина (Width) = 449 Form 1: - AutoSize = true Caption = Интерпретатор арифметики вещественных чисел MainMenu 1: Состоит из следующих пунктов Файл Открыть Выход Выполнить Для пунктов меню Открыть, Выход и Выполнить предусмотрены комбинации кнопок, для более быстрого выполнения задач. Открыть Ctrl+O Выход Ctrl+X Выполнить F9 Структура меню
Для того чтобы задать каждому пункту меню определенную комбинацию быстрых клавиш необходимо в окне Object Inspector компонента MainMenu1 выбрать необходимый пункт меню и в поле ShortCut выбрать необходимую комбинацию. Из за того что мы используем RichEdit1 наше приложение будет интерактивным а именно, после того как код программы будет загружен в окне нашего приложения в него можно будет вносить изменения и дополнять его. OpenDialog 1: Для того чтобы во время открытии текстового (txt) файла нам не мешались файлы с другими расширениями, нам необходимо установить фильтр для данного компонента OpenDialog1. В окне Object Inspector для OpenDialog1 в пункте Filter нажимаем на кнопку и устанавливаем необходимые фильтры.
*.txt - Отображать файлы с расширением TXT *.* - Отображать все файлы
Результатом обработки текста программы является вывод в окне интерпретатора результата вычисления, либо сообщения об ошибке.
Листинг программы
Unit 1. cpp #include <vcl.h> #pragma hdrstop #include "Unit1.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm"*Form1; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //---------------------------------------------------------------------------__fastcall TForm1::Open1Click(TObject *Sender) {->Options.Clear();->Options << ofAllowMultiSelect << ofFileMustExist;(OpenDialog1->Execute())->Lines->LoadFromFile(OpenDialog1->FileName);
} //---------------------------------------------------------------------------__fastcall TForm1::Calculate1Click(TObject *Sender) {*code;buffer[1024];= RichEdit1->Lines->GetText();*cb = parser_codebuffer_new(code); /* Вычислить выражения */v1 = parser_evaluate(cb); /* Напечатать результат выполнения операции */->Lines->Add((v1.error)); /* Важно: Обязательно освободить массив значений v1 */_value_free(&v1); /* Освободить буфер кода и список переменных */ parser_codebuffer_destroy(cb); /* И освободить cb */(cb); }__fastcall TForm1::Variable_print_all(ParserVariable *variables[]) {(!variables) return;_t i;buffer[1024];(i=0; i< MAX_VARIABLE_LIST_LEN; i++) {(!variables[i]) continue;*var = variables[i];(var->val.type) {TOK_NUMERIC:(buffer,"%s=%s\n",var->name, parser_value_show_as_string(&var->val));->Lines->Add (buffer);;TOK_STRING:(buffer,"%s=%s\n",var->name, var->val.s);->Lines->Add (buffer);;:(buffer, "%s Имеет неизвестный тип переменной%d.\n", var->name, var->val.type);->Lines->Add (buffer);; } } } //---------------------------------------------------------------------------__fastcall TForm1::Exit1Click(TObject *Sender) {(); } Parser.cpp #include "lexer.h" #include "parser.h" #include "Unit1.h" #ifndef M_PI #define M_PI 3.14159265358979323 #endifparser_statements(CodeBuffer *cb);parser_assign(CodeBuffer *cb);do_sqrt(ParserVal *a, int b);do_abs(ParserVal *, int);do_exp(ParserVal *, int);do_ln(ParserVal *, int);do_pow(ParserVal *, int);do_integer(ParserVal *, int);do_round(ParserVal *, int);do_fraction(ParserVal *, int);do_boolean_str(int oper, ParserVal *v1, ParserVal *v2);do_boolean(int oper, ParserVal *v1, ParserVal *v2);do_math(int oper, ParserVal *v1, ParserVal *v2);do_unary(int oper, ParserVal *v1);do_power(ParserVal *v1, ParserVal *v2);parser_do_print(ParserVal *, int);g_function_table[] = { /* Массив внутренних функций */ {"sqrt", 1, do_sqrt}, {"abs", 1, do_abs}, {"exp", 1, do_exp}, {"ln", 1, do_ln}, {"pow", 2, do_pow}, {"print", 1, parser_do_print}, {"int", 1, do_integer}, {"modf", 1, do_fraction} };*lookup_builtin_function(char *name);*builtin_function_arg_text(BuiltinFunction *func);_t parser_strlen(char *s);execute_builtin_function(CodeBuffer *cb, BuiltinFunction *func);parser_bool_or(CodeBuffer *cb);parser_bool_and(CodeBuffer *cb);parser_bool1(CodeBuffer *cb);parser_bool2(CodeBuffer *cb);parser_bool3(CodeBuffer *cb);parser_level1(CodeBuffer *cb);parser_level2(CodeBuffer *cb);parser_level3(CodeBuffer *cb);parser_level4(CodeBuffer *cb);parser_level5(CodeBuffer *cb);parser_error(CodeBuffer *cb, char *msg, int opt);parser_convert_to_numeric(ParserVal *v);parser_convert_to_string(ParserVal *v);is_numeric(ParserVal *v);is_string(ParserVal *v);str_icmp(char *s1, char *s2);parser_add_strings(ParserVal *v1, ParserVal *v2);get_int_part(double x);round_num(double d, unsigned int dec_places); /* Хранение глобальных tokenов для функций которые не анализируют их */ TokenRec currToken;parser_evaluate(CodeBuffer *cb) { /* Начало parsingа для col 0, line 1 */>curr_pos = 0;>line_num = 1;(cb->char_backbuf, '\0', MAX_CHAR_BACKBUF_LEN);>tok_backbuf_count = 0;_variable_add_standard_constants(cb);v1 = parser_statements(cb);
/* Необходимо освободить v1 после использования. Вызов parser_value_free(&v1); */v1; }parser_do_print(ParserVal *v, int arg_count){buffer[1024];_convert_to_numeric(v);>s = parser_format_string("Результат:%g", v->d);->RichEdit1->Lines->Add(v->s);; }parser_statements(CodeBuffer *cb) {v1;_value_init_to_numeric(&v1, 0.0);_get_token(cb, &currToken);(currToken.type!= TOK_EOF) {= parser_assign(cb);(v1.error) {_error(cb, v1.error, TRUE);v1; }(v1.type) {TOK_STRING:;TOK_NUMERIC: break;'\n': /* Пустая инструкция */; } } /* Необходимо освободить V1 после использования. parser_value_free(&v1); */v1; }parser_assign(CodeBuffer *cb) {v1;**variables = parser_variable_create_list(); /* Текущий token идентификатор а следующий token знак '=' */ while (currToken.type == TOK_IDENT && lexer_lookahead(cb, '=', TRUE/*remove it*/)) {*var = (ParserVariable *)calloc(1, sizeof(ParserVariable));>name = parser_format_string("%s", currToken.str);_value_init_to_numeric(&var->val, 0.0); /* Добавить переменную в список */_variable_add_to_list(variables, var);_get_token(cb, &currToken); } /* Анализ и оценка значения */= parser_bool1(cb); if (!v1.error) {_t i;(i = 0; i < MAX_VARIABLE_LIST_LEN; i++) {(!variables[i]) continue;_value_copy(&v1, &variables[i]->val);_variable_add_to_list(cb->variable_list, variables[i]); } }(variables);v1; }parser_bool1(CodeBuffer *cb) {oper;v1 = parser_bool2(cb); oper = currToken.type; /* Логический оператор: '&&' Логическое AND */ while (oper == TOK_AND) {_PAR2("ОТЛАДКА parser_bool1 (&&): Оператор=%c Значение v1=%s\n", oper, parser_value_show_as_string(&v1));_get_token(cb, &currToken);v2 = parser_bool2(cb);_boolean(oper, &v1, &v2); /* Free v2 */_value_free(&v2);= currToken.type;(v1.error) break; }v1; }parser_bool2(CodeBuffer *cb) {oper;v1 = parser_bool3(cb); oper = currToken.type; /* Логический оператор: '||' Логическое OR */ while (oper == TOK_OR) {_PAR2("ОТЛАДКА parser_bool2 (||): оператор=%c Значение v1=%s\n", oper, parser_value_show_as_string(&v1));_get_token(cb, &currToken);v2 = parser_bool3(cb);_boolean(oper, &v1, &v2); /* Free v2 */_value_free(&v2);= currToken.type;(v1.error) break; }v1; }parser_bool3(CodeBuffer *cb) {oper;v1 = parser_level1(cb); oper = currToken.type; /* Логический оператор: ==, >, >=, <, <= */ while (oper == TOK_EQ || oper == TOK_GT || oper == TOK_LT || oper == TOK_LE || oper == TOK_GE) {_PAR2("ОТЛАДКА parser_bool3 (==, >, >=, <, <=): оператор=%c Значение v1=%s\n", oper, parser_value_show_as_string(&v1));_get_token(cb, &currToken);v2 = parser_level1(cb);_boolean(oper, &v1, &v2); /* Free v2 */_value_free(&v2);= currToken.type;(v1.error) break; }v1; }parser_level1(CodeBuffer *cb) {oper;v1 = parser_level2(cb); oper = currToken.type; /* Математические операторы: +, - */ while (oper == TOK_PLUS || oper == '-') {_PAR2("ОТЛАДКА parser_level1 (+/-): оператор=%c Значение v1=%s\n", oper, parser_value_show_as_string(&v1));_get_token(cb, &currToken);v2 = parser_level2(cb);_math(oper, &v1, &v2); /* Free v2 */_value_free(&v2);= currToken.type;(v1.error) break; }v1; }parser_level2(CodeBuffer *cb) {oper;v1 = parser_level3(cb);= currToken.type; // *, /(oper == TOK_MUL || oper == TOK_DIV) {_PAR2("ОТЛАДКА parser_level2: оператор=%c Значение v1=%s\n", oper, parser_value_show_as_string(&v1));_get_token(cb, &currToken);v2 = parser_level3(cb);_math(oper, &v1, &v2); /* Free v2 */_value_free(&v2);= currToken.type;(v1.error) break; }v1; }parser_level3(CodeBuffer *cb) {v1 = parser_level4(cb); /* '^' Экспоненциальный: 2^3 = 8. */(currToken.type == TOK_EXP) {_get_token(cb, &currToken);("parser_level3: Оператор=%c Значение v1=%s\n", TOK_EXP, parser_value_show_as_string(&v1));_PAR2("ОТЛАДКА parser_level3: Оператор=%c Значение v1=%s\n", TOK_EXP, parser_value_show_as_string(&v1));v2 = parser_level3(cb); /* Recursively */_power(&v1, &v2);
/* Free v2 */_value_free(&v2); }v1; }parser_level4(CodeBuffer *cb) { int oper; oper = 0; /* Унарный +/- пример. (+3) + -3. */(currToken.type == '-' || currToken.type == '+') {= currToken.type;_get_token(cb, &currToken); }v1 = parser_level5(cb);(oper!= 0) {_PAR2("ОТЛАДКА parser_level4 (унарный +/-): Оператор=%c Значение v1=%s\n", oper, parser_value_show_as_string(&v1));_unary(oper, &v1); }v1; }parser_level5(CodeBuffer *cb) {val;v1; //= {.type=TOK_NUMERIC, {.d=0.0},.error=NULL};.type=TOK_NUMERIC;.d=0.0; v1.error=NULL; /* Сохранение текущего типа tokenа */ val = currToken;(currToken.type) { /* '(' Выражение ')'. Пример. "((2 + 5) * 6)" */TOK_PAROPEN:_get_token(cb, &currToken); v1 = parser_bool1(cb); /* С правой скобкой ')'? */(currToken.type!= TOK_PARCLOSE) { /* Отсутствие правая скобка ')' */ v1.error = parser_format_string("Отсутствует правая скобка ')'."); }_get_token(cb, &currToken);;TOK_NUMERIC:.type = TOK_NUMERIC;.d = currToken.val.d;_get_token(cb, &currToken); break;TOK_IDENT: { /* Это встроенная функция? */*func = lookup_builtin_function(currToken.str); if (func) { /* Проверка открытия '(' */ if (!lexer_lookahead(cb, '(',TRUE/*remove it*/)) { /* Отсутствие '(' */.error = parser_format_string("Отсутствует левая скобка '(' у функции%s.\n", func->name);l_end_ident; }_get_token(cb, &currToken);= execute_builtin_function(cb, func); /* С закрытием ')'? */(currToken.type!= TOK_PARCLOSE) { /* Отсутствие ')' */.error = parser_format_string("Отсутствует правая скобка ')'. получен знак '%s'.", currToken.str); } } { /* Это переменная */i = parser_variable_find(cb->variable_list, currToken.str);(i > -1) {*var = cb->variable_list[i];_value_copy(&var->val, &v1); } { /* Неизвестная переменная или идентификатор */ v1.error = parser_format_string("Неизвестный идентификатор '%s'.", currToken.str); } }_end_ident:_get_token(cb, &currToken); };TOK_STRING: /* Строка цитаты " или ' */_value_set_to_string(&v1, currToken.str);_get_token(cb, &currToken);;'\n':';': /* Конец или пустой оператор */.type = '\n'; lexer_get_token(cb, &currToken);;:.error = parser_format_string("Неизвестный знак '%s'", currToken.str);_get_token(cb, &currToken); }_PAR2("ОТЛАДКА parser_level5: type=%d Значение v1=%s.\n", val.type, parser_value_show_as_string(&v1));v1; }do_boolean_str(int oper, ParserVal *v1, ParserVal *v2) {_convert_to_string(v1);_convert_to_string(v2);ret = strcmp(v1->s, v2->s);(oper) { /* v1 == v2 */TOK_EQ:_value_set_to_numeric(v1, (double)(ret == 0));; /* v1 > v2 */TOK_GT:_value_set_to_numeric(v1, (double)(ret > 0));; /* v1 >= v2 */TOK_GE:_value_set_to_numeric(v1, (double)(ret > 0 || ret == 0));; /* v1 < v2 */TOK_LT:_value_set_to_numeric(v1, (double)(ret < 0));; /* v1 <= v2 */TOK_LE:_value_set_to_numeric(v1, (double)(ret < 0 || ret == 0));; /* v1 && v2 */TOK_AND:(!(parser_strlen(v1->s) && parser_strlen(v2->s))) { /* Set v1 to zero (FALSE) */_value_free(v1); }; /* v1 || v2 */TOK_OR:(!parser_strlen(v1->s)) { /* Copy v2 to v1 */_value_free(v1);_value_copy(v2, v1); }; } }do_boolean(int oper, ParserVal *v1, ParserVal *v2) {(is_string(v1) || is_string(v2)) {_boolean_str(oper, v1, v2);; }_convert_to_numeric(v1);_convert_to_numeric(v2);(oper) { /* v1 == v2 */TOK_EQ:->d = (v1->d == v2->d);; /* v1 > v2 */TOK_GT:->d = (v1->d > v2->d);; /* v1 >= v2 */TOK_GE:->d = (v1->d >= v2->d);; /* v1 < v2 */TOK_LT:->d = (v1->d < v2->d);; /* v1 <= v2 */TOK_LE:->d = (v1->d <= v2->d);; /* v1 && v2 */TOK_AND:(v1->d == 0.0 || v2->d == 0.0) { /* Set v1 to zero (FALSE) */->d = 0.0; }; /* v1 || v2 */TOK_OR:(v1->d == 0.0) { /* Copy v2 to v1 */->d = v2->d; }; } }do_math(int oper, ParserVal *v1, ParserVal *v2) {(oper == '+') {(is_string(v1) || is_string(v2)) {_add_strings(v1, v2); } {->d = v1->d + v2->d; }; }((is_string(v1) || is_string(v2))) {->error = parser_format_string("Строка не может принять математический оператор '%c'.", oper); return; }_convert_to_numeric(v1);_convert_to_numeric(v2);(oper) {'-':->d = v1->d - v2->d;;'*':->d = v1->d * v2->d;;'/':(v2->d!= 0.0)->d = v1->d / v2->d; {->error = parser_format_string("Деление на ноль."); }; } }do_power(ParserVal *v1, ParserVal *v2) {_convert_to_numeric(v1);_convert_to_numeric(v2);(is_numeric(v1) && is_numeric(v2)) {d = v1->d;i;(i=1; i<(long)v2->d; i++) v1->d *= d; } {->error = parser_format_string("Строка не может принять экспоненциальный оператор '^'."); } }do_unary(int oper, ParserVal *v) {_convert_to_numeric(v);(!is_numeric(v)) {>error = parser_format_string("Строка не может принять унарный '%c' оператор.", oper);; }>d = -v->d; }is_numeric(ParserVal *v) {v->type == TOK_NUMERIC; }is_string(ParserVal *v) {v->type == TOK_STRING; }parser_convert_to_numeric(ParserVal *v) {(v->type == TOK_NUMERIC) return; /* ATM we do not convert string to numeric value */ }parser_convert_to_string(ParserVal *v) { /* Преобразование числового значения в строку */ if (v->type == TOK_STRING) return; /* Value as string picture */*p = parser_value_show_as_string(v);>s = (char*) calloc(MAX_NUMERIC_LEN, sizeof(char));_t len = min(parser_strlen(p), MAX_NUMERIC_LEN-1);(len)(v->s, p, len); *(v->s + len) = '\0';>type = TOK_STRING; }*parser_value_show_as_string(ParserVal *v) { /* Static char buffer, return pointer to it */char buf[MAX_TOKEN_LEN]; /* Это строка? */(v->type == TOK_STRING) {_t len = min(parser_strlen(v->s), MAX_TOKEN_LEN);(buf, v->s, len); *(buf + len) = '\0';buf; } /* Это числовое */ceil_diff = ceil(v->d) - v->d;floor_diff = v->d - floor(v->d);diff, res;(ceil_diff < floor_diff) {= ceil_diff;= ceil(v->d); } {= floor_diff;= floor(v->d); }(diff < 0.0009)(buf, "%ld", (long)res); /* Отобразить как целое */ else(buf, "%.3f", v->d); /* Отобразить как действительное десятичное число */ return buf; }parser_value_as_numeric(ParserVal *v) {(v->type == TOK_NUMERIC)v->d;0.0; }*parser_value_as_string(ParserVal *v) { /* Do not free the value.points to a static char buffer. */parser_value_show_as_string(v); }parser_value_as_boolean(ParserVal *v) {(v->type == TOK_NUMERIC)(int)v->d!= 0;(str_icmp(v->s, "Истина"))TRUE;(str_icmp(v->s, "1"))TRUE;(str_icmp(v->s, "Лож"))FALSE;(str_icmp(v->s, "0"))FALSE;FALSE; }parser_add_strings(ParserVal *v1, ParserVal *v2) {_convert_to_string(v1);_convert_to_string(v2); size_t len1 = min(parser_strlen(v1->s), MAX_TOKEN_LEN);_t len2 = min(parser_strlen(v2->s), MAX_TOKEN_LEN); char *p = (char*)calloc(len1 + len2 + 1, sizeof(char));(len1)(p, v1->s, len1);(len2)(p + len1, v2->s, len2); *(p + len1 + len2) = '\0';(v1->s);->s = p; } /* ************************** */ /* Numeric and string values */ /* ************************** */parser_value_set_to_numeric(ParserVal *v, double d) {_value_free(v);_value_init_to_numeric(v, d); }parser_value_set_to_string(ParserVal *v, char *s) {_value_free(v);_value_init_to_string(v, s); }parser_value_init_to_numeric(ParserVal *v, double d) {>d = d;>type = TOK_NUMERIC;>error = NULL; }parser_value_init_to_string(ParserVal *v, char *s) {_t len = min(parser_strlen(s), MAX_TOKEN_LEN);>s = (char*)calloc(len + 1, sizeof(char));(len)(v->s, s, len); *(v->s + len) = '\0';>type = TOK_STRING;>error = NULL; }parser_value_free(ParserVal *v) {_value_delete(v); }parser_value_copy(ParserVal *from_v, ParserVal *to_v) { *to_v = *from_v;(from_v->type!= TOK_STRING) return;_t len = min(parser_strlen(from_v->s), MAX_TOKEN_LEN);_v->s =(char*) calloc(len + 1, sizeof(char));(len)(to_v->s, from_v->s, len); *(to_v->s+len) = '\0'; }parser_value_delete(ParserVal *v) {(v->type == TOK_STRING) { /* Free string value */(v->s) free(v->s);>s = NULL; } /* Free error */(v->error) free(v->error);>error = NULL; /*it keep the type. */ }do_sqrt(ParserVal *v, int arg_count) { /* Return sqrt(v[0]) in v[0] */[0].d = sqrt(v[0].d); }do_abs(ParserVal *v, int arg_count) { /* Return abs(v[0]) in v[0]. */[0].d = fabs(v[0].d); }do_exp(ParserVal *v, int arg_count) { /* Return exp(v[0]) in v[0]. */[0].d = exp(v[0].d); }do_ln(ParserVal *v, int arg_count) { /* Return log(v[0]) in v[0]. */[0].d = log(v[0].d); }do_pow(ParserVal *v, int arg_count) { /* Return pow(v[0], v[1]) in v[0]. */[0].d = pow(v[0].d, v[1].d); }do_integer(ParserVal *v, int arg_count) { /* Return integer (whole part of) v[0] in v[0]. */(v[0].d, &v[0].d/*int part*/); }do_fraction(ParserVal *v, int arg_count) { /* Return fraction (decimal part of) v[0] in v[0]. */int_part;[0].d/*fraction*/ = modf(v[0].d, &int_part); }do_round(ParserVal *v, int arg_count) { /* Round v[0] to nearest n decimal. n = {0...10}.[1] contains n. Returns the rounded value in v[0]. */ /* TODO: Find a better way to do this! */char buf[MAX_NUMERIC_LEN];char format[MAX_NUMERIC_LEN]; sprintf(format, "%%.%df", (int)v[1].d);(buf, format, v[0].d); v[0].d = atof(buf); }*lookup_builtin_function(char *name) {i;(i=0; i< sizeof(g_function_table)/sizeof(g_function_table[0]); i++) {(!strcmp(g_function_table[i].name, name))&g_function_table[i]; }NULL; }execute_builtin_function(CodeBuffer *cb, BuiltinFunction *func) {v[MAX_FUNC_ARGS];i;(i=0; i< MAX_FUNC_ARGS; i++)_value_init_to_numeric(&v[i], 0.0);(!func) return v[0];arg_count = 0;(func->num_args) {[arg_count] = parser_bool1(cb);_count++;(arg_count >= func->num_args || arg_count >= MAX_FUNC_ARGS) break;(func->num_args == (int)'*') {(currToken.type == ',') { /* Removed comma */ ; /* ok */ }if (currToken.type == ')') {; } {[0].error = parser_format_string("Missing ',' or ')' at function%s.", func->name);v[0]; } } { /* Remove comma between expressions */(currToken.type!= TOK_COMMA) {*p = builtin_function_arg_text(func);[0].error = parser_format_string("Missing ',' at function%s. Function%s takes%s arguments.", func->name, func->name, p);(p);v[0]; } } /* Next token */_get_token(cb, &currToken); }(arg_count == 0) {*p = builtin_function_arg_text(func);[0].error = parser_format_string("Не заданы аргументы. Функция%s имеет%s аргумент(ы).", func->name, p);(p);v[0]; }>func(v, arg_count);v[0]; }*builtin_function_arg_text(BuiltinFunction *func) {*p;(func->num_args == '*')= parser_format_string("До%d", MAX_FUNC_ARGS);= parser_format_string("%d", func->num_args); /* You should free() the value after usage */p; }*parser_copy_string(char *s) {_t len = min(parser_strlen(s), MAX_TOKEN_LEN);*tmp = (char*)calloc(len+1, sizeof(char));(len)(tmp, s, len); *(tmp+len) = '\0';tmp; }*parser_quote_string(char *s) {_t len = min(parser_strlen(s), MAX_TOKEN_LEN);*tmp;(len > 0 && (*s == '"' || *s == '\'')) {parser_copy_string(s); }=(char*) calloc(len + 3/* " + \0 + " */, sizeof(char)); *tmp = '"';(len)(tmp+1, s, len); *(tmp+len+1) = '"'; *(tmp+len+2) = '\0';tmp; }_t parser_strlen(char *s) {(!s) return (size_t)0;strlen(s); }*parser_format_string(const char *fmt,...) {*msg = (char*)calloc(MAX_TOKEN_LEN, sizeof(char));_list args;_start(args, fmt);(msg, fmt, args);_end(args);msg; }parser_error(CodeBuffer *cb, char *msg, int opt) {buffer[1024];(opt && cb)(buffer, "Ошибка парсера в строке%d:%s\n", lexer_line_num(cb), msg);(buffer, "Ошибка парсера%s\n", msg);->RichEdit1->Lines->Add(buffer); } /* Переменные */parser_variable_add_value(CodeBuffer *cb, char *name, ParserVal *value) {(value->type == TOK_STRING)_variable_add_string_var(cb, name, value->s, FALSE/*quoted*/);_variable_add_numeric_var(cb, name, value->d); }parser_variable_add_numeric_var(CodeBuffer *cb, char *name, double val) {(!(cb && name)) return;*var = parser_variable_create_new(name);_value_init_to_numeric(&var->val, val);_variable_add_to_list(cb->variable_list, var); }parser_variable_add_string_var(CodeBuffer *cb, char *name, char *val, int quoted) {(!(cb && name)) return;*var = parser_variable_create_new(name); /* "Цитировать"? */(quoted) {*tmp = parser_quote_string(val);_value_init_to_string(&var->val, tmp);(tmp); }_value_init_to_string(&var->val, val);_variable_add_to_list(cb->variable_list, var); }parser_variable_add_standard_constants(CodeBuffer *cb) {(!cb) return; }**parser_variable_create_list() { /* Создать пустой список переменных */**list; list = (ParserVariable **)calloc(MAX_VARIABLE_LIST_LEN, sizeof(ParserVariable));list; }*parser_variable_create_new(char *name) {*var = (ParserVariable *)calloc(1, sizeof(ParserVariable));>name = parser_format_string("%s", name); /* Присвоить 0.0 (TOK_NUMERIC) */_value_init_to_numeric(&var->val, 0.0);var; }parser_variable_add_to_list(ParserVariable *variables[], ParserVariable *var) {i;= parser_variable_find(variables, var->name); if (i > -1) { /* Обновление существующей переменной */ parser_variable_delete(variables[i]);[i] = var;i; } /* Добавление новой переменной */(i = 0; i< MAX_VARIABLE_LIST_LEN; i++) {(!variables[i]) {[i] = var;i; } }_error(NULL, "Список переменных переполнен.\n", FALSE);-1; }parser_variable_find(ParserVariable *variables[], char *name) {i;(i=0; i< MAX_VARIABLE_LIST_LEN; i++) {(!variables[i]) break;(!strcmp(name, variables[i]->name)) return i; }-1; }parser_variable_print_all(ParserVariable *variables[]) {(!variables) return;_t i;(i=0; i< MAX_VARIABLE_LIST_LEN; i++) {(!variables[i]) continue;*var = variables[i];(var->val.type) {TOK_NUMERIC:("%s=%s (numeric).\n", var->name, parser_value_show_as_string (&var->val));;TOK_STRING:("%s=%s (string).\n", var->name, var->val.s);;:("%s Неизвестный тип переменной%d.\n", var->name, var->val.type);; } } }*parser_variable_get_debug_text(ParserVariable *variables[]) { /* Return a long string (text) with variable names and values.for inspection and debugging. */(!variables) return NULL;*text = parser_format_string("Переменные:\n");_t i;(i=0; i< MAX_VARIABLE_LIST_LEN; i++) {(!variables[i]) continue;*var = variables[i];*tmp;= NULL;(var->val.type) {TOK_NUMERIC:= parser_format_string("%s=%s (numeric).\n", var->name, parser_value_show_as_string(&var->val));;TOK_STRING:= parser_format_string("%s=%s (string).\n", var->name, var->val.s);;:= parser_format_string("%s Неизвестный тип переменной%d.\n", var->name, var->val.type);; }(tmp) {*tmp2 = parser_format_string("%s%s", text, tmp);(text);= tmp2; }(tmp); }text; }parser_variable_delete(ParserVariable *var) {(!var) return;_value_delete(&var->val);(var->name);>name = NULL; }parser_variable_delete_all(ParserVariable *variables[]) {(!variables) return;_t i;(i=0; i< MAX_VARIABLE_LIST_LEN; i++) {_variable_delete(variables[i]); }(variables);= NULL; }str_icmp(char *s1, char *s2) {strcmp(s1, s2); } Lexer.cpp #include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> #include "lexer.h" #include "parser.h"lexer_lookahead_token(CodeBuffer *cb, char *_token, int _remove/*Удалить если нашли?*/, int _eat_nl/*Искать переводы строки? '\n'?*/) {tok;ret = FALSE;(1) {_get_token(cb, &tok);(tok.type == TOK_EOF) break;= (!strcmp(tok.str, _token));(!ret && (_eat_nl && tok.type == '\n')) continue;(!ret) {_put_token_back(cb, &tok); } {(!_remove)_put_token_back(cb, &tok); }; }ret; }lexer_put_token_back(CodeBuffer *cb, TokenRec *_tokRec) {(cb->tok_backbuf_count >= MAX_TOKEN_BACKBUF_LEN-1) {_error(cb, "Буфер Tokenа переполнен.\n"); }>tok_backbuf[cb->tok_backbuf_count] = *_tokRec;>tok_backbuf_count++; }lexer_get_token_from_backbuf(CodeBuffer *cb, TokenRec *_tokRec) { /* Содержит буфер данные? */(cb->tok_backbuf_count > 0) {>tok_backbuf_count--; *_tokRec = cb->tok_backbuf[cb->tok_backbuf_count]; /* Взяли данные из буфера */TRUE; } { /* Обнулить строку \0 */ *_tokRec->str = '\0'; _tokRec->type = TOK_EOF; } /* Буфер был пустой */ return FALSE; }lexer_get_token(CodeBuffer *cb, TokenRec *_tokRec) { /* Читаем следующий Token из буфера */ char ch;ch2 = 0;*cPtr;char buf[MAX_TOKEN_LEN]; /* Очистить буфер tokenов */(_tokRec, sizeof(TokenRec), '\0'); *buf = *(buf+1) = *(buf+2) = '\0'; *(_tokRec->str) = *(_tokRec->str+1) = *(_tokRec->str+2) = '\0'; _tokRec->type = TOK_EOF; /* Проверка буфера tokenов */ if (lexer_get_token_from_backbuf(cb, _tokRec)) {_tokRec->type; } /* Выбираем следующий символ, удаляем пробелы, комментарии */ ch = lexer_get_charEx(cb); /* Проверяем является ли символ оператором */ switch (ch) {'=': _tokRec->type = TOK_ASSIGN; /* == */(lexer_lookahead(cb, '=',1)) _tokRec->type = TOK_EQ;;'+': /* += */(lexer_lookahead(cb, '=',1)) _tokRec->type = TOK_ASPLUS; /* ++ */if (lexer_lookahead(cb, '+',1)) _tokRec->type = TOK_INCR; /* + */ _tokRec->type = TOK_PLUS;;'-': /* -= */(lexer_lookahead(cb, '=',1)) _tokRec->type = TOK_ASMINUS; /* -- */if (lexer_lookahead(cb, '-',1)) _tokRec->type = TOK_DECR; /* - */ _tokRec->type = TOK_MINUS;;'*': /* *= */(lexer_lookahead(cb, '=',1)) _tokRec->type = TOK_ASMUL; /* * */ _tokRec->type = TOK_MUL;;'/': /* /= */(lexer_lookahead(cb, '=',1)) _tokRec->type = TOK_ASDIV; /* / */ _tokRec->type = TOK_DIV;;'^': /* ^ */ _tokRec->type = TOK_EXP;;'%': /*%= (modulus) */(lexer_lookahead(cb, '=',1)) _tokRec->type = TOK_ASMOD; /*% */ _tokRec->type = TOK_MOD; break; } /* Конец проверки. Это оператор? */(_tokRec->type!= TOK_EOF) { *(_tokRec->str) = ch; *(_tokRec->str+1) = '\0'; goto l_end; } /* Конец ввода данных? */(ch == TOK_EOF) { _tokRec->type = ch; goto l_end; } /* Новая строка или новый оператор? */(ch == ';' || ch == '\n') { _tokRec->type = ch; *(_tokRec->str) = ch; goto l_end; }(strchr("(),.{}", ch)) { /* Знаки) (;., } { */ _tokRec->type = ch; *(_tokRec->str) = ch;l_end; } // Идентификатор= tolower(ch);((ch2 >= 'a' && ch2 <= 'z') || strchr("_$", ch)) { *buf = ch;= buf +1;= lexer_get_char(cb);((isalnum(ch) || strchr("_$", ch)) && ch!= TOK_EOF) { *cPtr++ = ch;= lexer_get_char(cb); } *cPtr = '\0'; /* Возврат последнего символа в поток данных */ lexer_put_back(cb, ch); _tokRec->type = TOK_IDENT;len = min(strlen(buf), MAX_TOKEN_LEN);(_tokRec->str, buf, len); *(_tokRec->str + len) = '\0'; } /* Текстовая строка "xxx" или 'xxx' */ else if (ch == '"' || ch == '\'') {chStart = ch;= buf; ch2 = '\0'; // Поддержка кавычек внутри текста ".....\"...." while (1) {= lexer_get_char(cb);(ch == TOK_EOF) break; // Проверка \" и \'(ch == chStart && ch2!= '\\') {; } {= *cPtr; *cPtr++ = ch; } } *cPtr = '\0';len = min(strlen(buf), MAX_TOKEN_LEN); strncpy(_tokRec->str, buf, len); *(_tokRec->str + len) = '\0'; _tokRec->type = TOK_STRING; } /* Это целое число или десятичное; 123, 0.51,.67, -2.67, +89, -4e3, +2e-9*/ else if (strchr("0123456789+-.", ch)) {hasDecimal = 0;hasExp = 0;hasExpSign = 0;= buf; *cPtr++ = ch;(ch == '.') { hasDecimal = 1; } /* Принимаются следующие варианты записи: , -2.67, +89, -4e3, +2e-9 */ /* Также принимаются шестнадцатеричные числа в виде 0x7FCD и 0XA. */is_hex = FALSE;(ch == '0') {_hex = lexer_lookahead(cb, 'x', 1/*Истина*/);(!is_hex)_hex = lexer_lookahead(cb, 'X', 1/*Истина*/); } /* Добавляем 'x' чтобы запись соответствовала формату "0x" */ if (is_hex) *cPtr++ = 'x';int count = 0;/*Сброс индекса*/(1) {= lexer_get_char(cb);(ch == TOK_EOF) break;(ch == '.' &&!hasDecimal) { *cPtr++ = ch;= 1; }if ((ch == 'e' || ch == 'E') &&!hasExp) { *cPtr++ = ch;= 1; }if (strchr("+-", ch) && hasExp && (!hasExpSign)) { *cPtr++ = ch;= ch; }if (strchr("0123456789", ch)) { *cPtr++ = ch; }if (is_hex && strchr("ABCDEFabcdef", ch)) { *cPtr++ = ch; };(count++ > MAX_TOKEN_LEN) break; } /* Возвращаем последний символ обратно в поток */ lexer_put_back(cb, ch); *cPtr = '\0';d = atof(buf); _tokRec->type = TOK_NUMERIC; /* Возвращаем число в виде строки */ int len = min(strlen(buf), MAX_TOKEN_LEN); strncpy(_tokRec->str, buf, len); *(_tokRec->str + len) = '\0';(hasDecimal || hasExpSign == (int)'-') { _tokRec->val.d = d; } { /* На самом деле целое */ _tokRec->val.d = (long)d; } } /* Конец проверки на число */ { /* Неизвестный символ. Прекращаем дальнейший ввод */ _tokRec->type = TOK_EOF; }_end: /* Заносим номер строки и возвращаем token (*_tokRec) и его тип */ _tokRec->line_num = lexer_line_num(cb);_tokRec->type; }lexer_line_num(CodeBuffer *cb) {cb->line_num; }lexer_put_back(CodeBuffer *cb, char _ch) {_t len = strlen(cb->char_backbuf);(len < MAX_CHAR_BACKBUF_LEN - 1) { *(cb->char_backbuf + len) = _ch; *(cb->char_backbuf + len+1) = '\0'; } {_error(cb, "Буфер Parser'а переполнен."); } }lexer_remove_line(CodeBuffer *cb) {ch = lexer_get_char(cb);(ch!= TOK_EOF && ch!= '\n') {= lexer_get_char(cb); }_put_back(cb, ch); }lexer_get_charEx(CodeBuffer *cb) {ch;ch2;move;= lexer_get_char(cb);(ch!= TOK_EOF) {= 0; /* Удаляем пробелы */(isspace(ch)) {= lexer_get_char(cb); } /* Удаляем строки начинающиеся с '#' */ if (ch == '#') {_remove_line(cb);= lexer_get_char(cb); } /* Конец строки (оператора)? */(ch == '\n' || ch == ';') {ch; } /* Удаляем пробелы */(isspace(ch)) {= lexer_get_char(cb); } /* Удаляем комментарии которые начинаются с '/ *' и заканчиваются */ if (ch == '/') {= lexer_get_char(cb); if (ch2 == '/') { /* Чтение до конца строки */ ch = lexer_get_char(cb);(ch!= TOK_EOF && ch!= '\n') {= lexer_get_char(cb); }= 1; }if (ch2 == '*') {count = 1; // Внутренний счетчик /* /* /*... */ */ */= lexer_get_char(cb);= 0;(ch!= TOK_EOF) { // Комментарий закончился символом '*/'(ch == '/' && ch2 == '*') {(--count <= 0) {= 1;; } } // Пропускаем все что внутри комментария /* else if (ch == '*' && ch2 == '/') {++; }if (ch == '\n'|| ch == '\r') { ; } /* Предыдущий символ */= ch;= lexer_get_char(cb); }(ch == TOK_EOF && count) {_error(cb, "Многострочный комментарий не закрыт /*... */ "); } } {_put_back(cb, ch2); } }(move)= lexer_get_char(cb);; }ch; }lexer_lookahead(CodeBuffer *cb, int _match_ch, int _remove) {ret;ch = lexer_get_charEx(cb);(ch == _match_ch) {(!_remove) lexer_put_back(cb, ch);= 1; } {_put_back(cb, ch);= 0; }ret; }lexer_get_char(CodeBuffer *cb) {ch = TOK_EOF; /* Проверяем содержимое буфера */ if (cb->char_backbuf[0]!= '\0') {_t len = strlen(cb->char_backbuf);= *(cb->char_backbuf + len - 1); *(cb->char_backbuf + len-1) = '\0';ch; }(!cb->text)TOK_EOF;if (*(cb->text + cb->curr_pos) == TOK_EOF) {TOK_EOF; }= *(cb->text + cb->curr_pos);(ch == '\n')>line_num++;>curr_pos++;ch; }lexer_error(CodeBuffer *cb, char *_msg) {(stderr, "Лексическая ошибка:%s.%s\n", (cb->name? cb->name: ""), _msg); }lexer_match(char *tok1, char *tok2) {(!(tok1 && tok2)) return FALSE; size_t len1 = strlen(tok1);_t len2 = strlen(tok2);(len2 < len1) /* Соответствие шаблона в части tokenа, например lexer_match("abcd", "ab") => TRUE */ return!strncmp(tok1, tok2, len2); else /* Длинна Tokenа и шаблона должны совпадать */ return!strcmp(tok1, tok2); }*lexer_codebuffer_new(char *code) {*cb = (CodeBuffer *)calloc(1, sizeof(CodeBuffer)); lexer_codebuffer_init(cb); /* Выделить память для кода */ size_t len = min(strlen(code), 40960); if (len) {>text =(char*) calloc(len+1, sizeof(char));(cb->text, code, len); }cb; }lexer_codebuffer_init(CodeBuffer *cb) {>text = cb->name = NULL;>curr_pos = 0;>line_num = 1;(cb->char_backbuf, '\0', MAX_CHAR_BACKBUF_LEN); /* Счетчик Tokenов */>tok_backbuf_count = 0; /* Выделить память под переменные (MAX_VARIABLE_LIST_LEN) */ cb->variable_list = parser_variable_create_list(); }lexer_codebuffer_destroy(CodeBuffer *cb) {(!cb) return; /* Очистить буфер кода */ free(cb->text); free(cb->name);>curr_pos = 0;->line_num = 1; /* Удалить все переменные */ parser_variable_delete_all(cb->variable_list);>variable_list = NULL;(cb->char_backbuf, '\0', MAX_CHAR_BACKBUF_LEN); /* Обнулить счетчик Tokenов */>tok_backbuf_count = 0; }
Описание тестового примера
Текст программы:
a=sqrt(36)=abs(-6)=2^2=exp(30)=ln(10)(a)(b)(c)(d)(e)=3.4+2.6(f)=a+b*c-d/e*f(g) Результат Результат:6 Результат:6 Результат:4 Результат:1.06865e+13 Результат:2.30259 Результат:6 Результат:-2.78465e+13
Заключение В данной курсовой работе была выполнена задача создания простой программы-интерпретатора для обработки исходных текстов программ, выполняющих действия над комплексными числами. Библиографический список 1. Серебряков В.А., Галочкин М.П., Гончар Д.Р., Фуругян М.Г. Теория и реализация языков программирования. М.: “МЗ-Пресс”, 2003.- 296 с. 2. Атакищев О.И., Волков А.П., Титов В.С., Старков Ф.А. Формальные грамматики и их применение в распознавании образов. - Курск, 2000. -115с. . Бек Л. Введение в системное программирование. - М.: Мир, 1988. - 448 с. 4. Молчанов А.Ю. Системное программное обеспечение - СПб.: Питер, 2003 г.
Воспользуйтесь поиском по сайту: ©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|