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