Создание программы-интерпретатора для обработки исходных текстов программ, выполняющих действия над комплексными числами

Разработка программы-интерпретатора, способной получать на входе текстовый файл (в формате 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

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.