Giter Site home page Giter Site logo

uncalc's Introduction

unCalc - Universal Calculator

image

Тексты не приглажены, а взяты как есть из проекта. Поэтому, возможно, Вам придется кое-что не нужное удалять от туда самостоятельно.

Для выделения из программы баз данных бизнес логики в отдельный программный слой, который, конечно должен иметь возможность полностью настраиваться без перекомпиляции программы, можно использовать какой-нибудь интерпретатор. Тогда появится возможность просто менять программу для интерпретатора и тем самым менять бизнес логику программы. Давайте посмотрим, как можно сделать простейший интерпретатор. Для простоты синтаксиса, а значит и программной реализации, мы не будем придерживаться какого-то известного языка программирования. Назовем наш интерпретатор калькулятором – это нейтрально и непритязательно, так сказать без особых амбиций…

Калькулятор представляет собой двухпроходный интерпретатор, способный выполнять математические, логические, и другие операции, вызывать встроенные или внешние функции. Встроенные функции заложены в калькулятор при его создании, а внешние – создаются программистом при создании приложения. Обычно внешние функции нужны для выполнения действий над данными, которые обрабатывает программа, поэтому приходится каким-то образом дать доступ калькулятора к этим данным, что и вызвало появление внешних функций.

В калькуляторе используется простой синтаксис без понятия блока программного кода и области видимости. Т.е. все переменные являются глобальными, так же нет блоков, наподобие begin … end или { … }, которые присутствуют в языках высокого уровня Паскаль и C++. Несмотря на свои скромные языковые конструкции, калькулятор может выполнять все те же действия, что и вышеизложенные языки, за исключением определения типов пользователя.

Такой синтаксис не случаен. Дело в том, что область применения калькулятора – это обработка событий, вызванных действиями пользователя, и реакций на происходящие события в программе. Время реакции на эти события должно быть минимальным, поэтому процесс пре компиляции и выполнения должен проходить быстро, что требует приближения синтаксиса к оптимальному с точки зрения машины, а не человека. Но, т.к. в этих случаях обычно очень сложных программ писать не приходится, то с некоторой бедностью синтаксиса можно смирится.

Алфавит встроенного калькулятора. Алфавит встроенного калькулятора включает в себя следующие символы:

Все буквы латинского алфавита.

Цифры от 0 до 9

Специальные символы:

     “                   - обрамляет строковую константу

   ;           - завершает оператор

   :           - начало имени метки

   ,          - разделяет параметры, передаваемые функциям

   +                   - сложение
  •      - вычитание
    
  •               - умножение
    

/ - деление

( и ) - скобки в операторах или скобки вокруг параметров, передаваемых функции

< - меньше

              - больше

= - равно

А так же составные символы:

     = =    - сравнение

     >=     - больше или равно

     <=     - меньше или равно

     <>     - не равно

Словарь языка встроенного калькулятора. Как в большинстве языков программирования, неделимые последовательности знаков алфавита образуют слова, отделяемые друг от друга разделителями, и несущими определенный смысл. Разделителями могут служить символ пробела, конца строки, конца оператора, т.е. точка с запятой, комментарии, другие специальные символы и их комбинации.

        Все слова подразделяются на:

                    ключевые слова,

                    стандартные идентификаторы,

                    идентификаторы пользователя.

Ключевые слова являются составной частью языка, имеют фиксированное написание и однозначно определенный смысл:

End – конец программы.

Not – отрицание.

Or – объединение.

Стандартные идентификаторы служат для обозначения заранее определенных конструкций:

True - истина

False - ложь

Pi - число пи = 3.1415926535897932385

Имена встроенных и внешних функций.

Идентификаторы пользователя применяются для обозначения имен меток, переменных, констант, процедур, определенных пользователем. Все идентификаторы должны удовлетворять следующим требованиям:

Идентификаторы имен переменных и процедур, определенных пользователем не должны начинаться с цифр.

Идентификаторы не должны начинаться с символов !, :, _ , т.к. мы будем использовать эти символы в служебных целях.

Пре компилятор воспринимает символы в строчном и прописном регистре в именах идентификаторов как прописные.

Между двумя идентификаторами должен быть хотя бы один разделитель.

Структура программы встроенного калькулятора. Программа встроенного калькулятора состоит из операторов. Операторы могут быть как одиночными, так и составными. Программа обязательно должна заканчиваться словом end .

Строковые константы обрамляются двойными кавычками. Все операторы должны заканчиваться знаком точка с запятой. Метки начинаются двоеточием как в теле программы, так и в строковой константе передаваемой в качестве параметра функциям, например:

GoTo(“:Label1”);

:Label1;

Все переменные являются без типовыми, а точнее вариантными типами, поэтому Вы можете присваивать одной и той же переменной различные значения разных типов, но при выполнении операций, при неправильных типах значений переменных могут происходить исключительные ситуации. Например:

A = “2”;

B = 3;

C = A + B; // даст в результате 5.

A = “Вася”;

B = 3;

C = A + B; // даст в результате строку “Вася3”

C = A / B // вызовет исключительную ситуацию.

В программе Вы можете использовать комментарии. Комментарии начинаются с двойной наклонной черты - //. И заканчиваются концом строки, т.е. как короткие комментарии в С++.

Порядок выполнения операций естественный, принятый в математике, т.е. сначала операторы в скобках и функции, умножение и деление, сложение и вычитание, булевы операторы, например: 2+2*2 = = 6, а не 8. Вы можете использовать скобки, чтобы переопределить очередность выполнения операций, например: (2 + 2)*2 = = 8.

В качестве параметров функциям можно передавать другие функции и т.д., например: C = sin(cos(Z));

В числовых константах используется в качестве разделителя дробной и целой части только точка при любых настройках Вашей операционной системы. В качестве разделителя в датах – точка, а в качестве разделителей времени – двоеточие.

Все остальное, даже циклы и безусловные переходы мы организуем либо встроенными, либо внешними функциями. Если функция возвращает значение, которое Вам не нужно, Вы можете его игнорировать, т.е. записывать её в программе как процедуру без присваивания.

Вот как выглядит типичная программа:

Если ошибка, то просто уходим из программы

OnExcept(":Exit");

Получаем код текущей таблицы. Здесь IdMain и IdType – встроенные переменные

ThisTable = tTableId(IdMain, IdType);

Получаем код записи, которую будем искать в справочнике при его открытии

FindValue = tGetValByFieldNum(ThisTable, 74);

Получаем код другой таблицы – таблицы справочника

Categors = tTableId(5, 3);

Подготавливаем справочник к открытию

SetOpenDoc(5, 3, "Категории социального положения");

Открываем справочник. OpenReference вернет true, если пользователь нажмет Ok

if(OpenReference(5, 3, FindValue), ":SetVal", ":Exit");

:SetVal;

Устанавливаем код из справочника в текущую запись

tSetValByFieldNum(ThisTable, 74, tGetValByName(Categors, "ID_NUM"));

:Exit;

end;

Вот, собственно, все начальные условия, которые нам предстоит выполнить.

Проектирование калькулятора. Калькулятор должен иметь как минимум следующие блоки:

Компилятор, точнее что-то вроде анализатора текста ( парсер ), разбивающего текст на лексемы, и создающего нужные объекты для дальнейшего выполнения программы. Два стека – вычислительный и стек вызова подпрограмм. Я на всякий случай разделил их для простоты. Сам вычислитель, способный правильно выполнять программу, согласно правилам математики, вызывать функции и т.д. Контейнер переменных. Контейнер встроенных функций. Контейнер внешних функций, способный перед выполнением программы регистрировать внешние функции. Ну, и собственно, компонент – контейнер для всех этих объектов, который может согласовать их работу, который можно поставить на форму.

Тексты – разбор полетов.

Калькулятор. TunCalck = class(TComponent)

private

FCompiler: TunCompiler;

FStack: TunStack;

FSubStack: TunStack;

FVariables: TunVariables;

FFunctions: TunFunctions;

FStalker: TunStalker;

FExternals: TunExternals;

function GetCompProgramm: TStringList;

function GetProgramm: TStringList;

function GetVariable(const AName: string): Variant;

procedure SetVariable(const AName: string; const AVal: Variant);

function GetIsDebug: boolean;

procedure SetIsDebug(const Value: boolean);

protected

procedure DoCheckName(const VarName: string; var TypeName: TEnumToken;

                                                  var InternalName: string);

public

constructor Create(AOwner: TComponent); override;

destructor Destroy; override;

procedure Compile;

function Run: Variant;

property Programm: TStringList read GetProgramm;

property CompilerProgramm: TStringList read GetCompProgramm;

property Variable[const AName: string]: Variant read GetVariable write SetVariable;

property Variables: TunVariables read FVariables;

property Functions: TunFunctions read FFunctions;

property Externals: TunExternals read FExternals;

published

end;

Fcompiler – это наш компилятор, упомянутый как пункт 1. Fstack и FsubStack – два стека для вычислений и подпрограмм, соответственно. Fvariables – контейнер с переменными. Ffunctions – контейнер с встроенными функциями. Fexternals – контейнер внешних функций. И, наконец, Fstalker – сам вычислитель.

Посмотрим, что собственно, происходит, когда нам нужно что-то посчитать. Например, нужно посчитать видимость пункта меню для пользователя:

Присваиваем калькулятору программу.

    Calck.Programm.Assign( Work[I].WorckCheckPrg);

                    Устанавливаем значения неких переменных в программе

    Calck.Variable[‘VISIBLE’]:=true;

    Calck.Variable[‘ID_TYPE’]:=TypeDescriptor.ID;

    Calck.Variable[‘ID_MAIN’]:=MainOwner;

                    Запускаем программу на выполнение.

    Calck.Run;

                    Получаем результат, посчитанный калькулятором.

    isOk:=Calck.Variable[‘VISIBLE’];

                    …

Здесь isOk – видимость пункта меню.

Это один из способов, но можно зарегистрировать внешние функции, и управлять поведением программы с их помощью. Этот вариант мы рассмотрим позже.

Вот метод Run:

function TunCalck.Run: Variant;

var AOldTimeSeparator: Char;

AOldDateSeparator: Char;

AOldDecimalSeparator: Char;

Begin

Если программа пуста, то просто выходим, иначе “компилируем”

if Trim(Programm.Text) <> '' then

FCompiler.Compile

uncalc's People

Contributors

dima72 avatar stikriz avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.