Создание программы-интерпретатора для обработки исходных текстов программ, выполняющих действия над комплексными числами
В настоящее время языки высокого уровня стали основным средством разработки программ. Поэтому компиляторы составляют существенную часть системного программного обеспечения ЭВМ. Сегодня только очень малая часть программного обеспечения, требующая особой эффективности, разрабатывается с помощью ассемблеров. В настоящее время имеет применение довольно большое количество языков программирования… Читать ещё >
Создание программы-интерпретатора для обработки исходных текстов программ, выполняющих действия над комплексными числами (реферат, курсовая, диплом, контрольная)
В настоящее время языки высокого уровня стали основным средством разработки программ. Поэтому компиляторы составляют существенную часть системного программного обеспечения ЭВМ. Сегодня только очень малая часть программного обеспечения, требующая особой эффективности, разрабатывается с помощью ассемблеров. В настоящее время имеет применение довольно большое количество языков программирования. Наряду с традиционными языками, такими, например, как Фортран, широкое распространение получили так называемые «универсальные» языки (Паскаль, Си, Модула-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; (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
#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=%sn", var->name, parser_value_show_as_string (&var->val));
RichEdit1->Lines->Add (buffer);
break;
case TOK_STRING:
sprintf (buffer," %s=%sn", 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.14 159 265 358 979 324
#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, '', 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=%sn», 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)
' Логическое OR */
while (oper == TOK_OR)
DEBUG_PAR2(«ОТЛАДКА parser_bool2 (
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=%sn», 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=%sn», 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=%sn», 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);
/* '^' Экспоненциальный: 23 = 8. */
if (currToken.type == TOK_EXP)
{
lexer_get_token (cb, &currToken);
printf («parser_level3: Оператор=%c Значение v1=%sn», TOK_EXP, parser_value_show_as_string (&v1));
DEBUG_PAR2(«ОТЛАДКА parser_level3: Оператор=%c Значение v1=%sn», 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=%sn», 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) = '';
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) = '';
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) = '';
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) = '';
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) = '';
}
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) = '';
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/* «+ + «*/, sizeof (char));
*tmp = '" ';
if (len)
strncpy (tmp+1, s, len);
*(tmp+len+1) = '" ';
*(tmp+len+2) = '';
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:%sn», lexer_line_num (cb), msg);
else
sprintf (buffer, «Ошибка парсера%sn», 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
#include
#include
#include
#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
{ /* Обнулить строку */
*_tokRec->str = '';
_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), '');
*buf = *(buf+1) = *(buf+2) = '';
*(_tokRec->str) = *(_tokRec->str+1) = *(_tokRec->str+2) = '';
_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) = '';
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 = '';
/* Возврат последнего символа в поток данных */
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) = '';
}
/* Текстовая строка «xxx» или 'xxx' */
else if (ch == '" ' || ch == ''')
{
char chStart = ch;
cPtr = buf;
ch2 = ''; // Поддержка кавычек внутри текста «…» …"
while (1)
{
ch = lexer_get_char (cb);
if (ch == TOK_EOF) break;
// Проверка «и '
if (ch == chStart && ch2 ≠ '\')
{
break;
}
else
{
ch2 = *cPtr;
*cPtr++ = ch;
}
}
*cPtr = '';
int len = min (strlen (buf), MAX_TOKEN_LEN);
strncpy (_tokRec->str, buf, len);
*(_tokRec->str + len) = '';
_tokRec->type = TOK_STRING;
}
/* Это целое число или десятичное; 123, 0.51,.67, -2.67, +89, -4e3, +2e-9*/
else if (strchr («123 456 789±.», 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 («123 456 789», 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 = '';
double d = atof (buf);
_tokRec->type = TOK_NUMERIC;
/* Возвращаем число в виде строки */
int len = min (strlen (buf), MAX_TOKEN_LEN);
strncpy (_tokRec->str, buf, len);
*(_tokRec->str + len) = '';
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) = '';
}
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] ≠ '')
{
size_t len = strlen (cb->char_backbuf);
ch = *(cb->char_backbuf + len — 1);
*(cb->char_backbuf + len-1) = '';
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.%sn», (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), 40 960);
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, '', 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, '', MAX_CHAR_BACKBUF_LEN);
/* Обнулить счетчик Tokenов */
cb->tok_backbuf_count = 0;
}
4. Описание тестового примера
Текст программы:
a=sqrt (36)
b=abs (-6)
c=22
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.30 259
Результат:6
Результат:-2.78465e+13
Заключение
В данной курсовой работе была выполнена задача создания простой программы-интерпретатора для обработки исходных текстов программ, выполняющих действия над комплексными числами.
Библиографический список
1. Серебряков В. А., Галочкин М. П., Гончар Д. Р., Фуругян М. Г. Теория и реализация языков программирования. М.: «МЗ-Пресс», 2003. 296 с.
2. Атакищев О. И., Волков А. П., Титов В. С., Старков Ф. А. Формальные грамматики и их применение в распознавании образов. — Курск, 2000. -115с.
3. Бек Л.
Введение
в системное программирование. — М.: Мир, 1988. — 448 с.
4. Молчанов А. Ю. Системное программное обеспечение — СПб.: Питер, 2003 г.