Вы должны искать «абстрактные синтаксические деревья» и «деревья выражений», а также «лексический анализ», «синтаксис», «синтаксический анализ» и «теория компилятора». Чтение ввода текста и получение значения от него довольно сложно для большинства вещей (хотя мы часто пытаемся убедиться, что у нас есть простой ввод).
Первый шаг в создании синтаксического анализатора - записать грамматику для вашего языка ввода. В этом случае ваш язык ввода - это математические выражения, поэтому вы должны сделать что-то вроде:
expr => <function_identifier> ( stmt )
( stmt )
<variable_identifier>
<numerical_constant>
stmt => expr <operator> stmt
(я не писал такую грамматику {ищите BNF
и EBNF
} в течение нескольких лет, так что я, вероятно, допустил несколько вопиющих ошибок, на которые кто-то другой любезно укажет)
Это может быть намного сложнее в зависимости от того, как вы обрабатываете приоритет оператора (умножьте и определите устройство перед сложением и вычитанием содержимого типа), но смысл грамматики в этом случае - помочь вам написать синтаксический анализатор.
Существуют инструменты, которые помогут вам сделать это (yacc
, bison
, antlr
и другие), но вы также можете сделать это вручную. Есть много способов сделать это, но у всех них есть одна общая черта - стек. Для обработки такого языка требуется нечто, называемое автоматом нажатия, что является просто причудливым способом сказать что-то, что может принимать решения на основе нового ввода, текущего состояния и верхнего элемента стека. Решения, которые он может принять, включают в себя нажатие, выталкивание, изменение состояния и объединение (превращение 2+3
в 5
является формой объединения). Объединение обычно называется производством, поскольку оно дает результат.
Из различных распространенных типов парсеров вы почти наверняка начнете с рекурсивного приличного парсера. Они обычно пишутся непосредственно на языке программирования общего назначения, таком как C. Этот тип синтаксического анализатора состоит из нескольких (часто многих) функций, которые вызывают друг друга, и в итоге они используют системный стек в качестве стека автоматов.
Еще одна вещь, которую вам нужно сделать, это записать различные типы слов и операторов, составляющих ваш язык. Эти слова и операторы называются лексемами и представляют собой токены вашего языка. Я представил эти жетоны в грамматике <like_this>
, за исключением скобок, которые представляли себя.
Скорее всего, вы захотите описать свои лексемы с помощью набора регулярных выражений. Вы должны быть знакомы с ними, если вы используете grep
, sed
, awk
или perl
. Они представляют собой способ описания так называемого обычного языка, который может обрабатываться чем-то, что называется конечным автоматом. Это просто причудливый способ сказать, что это программа, которая может принимать решение об изменении состояния, рассматривая только его текущее состояние и следующий ввод (следующий символ ввода). Например, часть вашего лексического описания может быть:
[A-Z] variable-identifier
sqrt function-identifier
log function-identifier
[0-9]+ unsigned-literal
+ operator
- operator
Есть также инструменты, которые могут генерировать код для этого. lex
, который является одним из них, тесно интегрирован с программой генерации синтаксического анализатора yacc
, но поскольку вы пытаетесь учиться, вы также можете написать свой собственный код токенизатора / лексического анализа на языке C.
После того, как вы все это сделали (это, вероятно, займет у вас довольно много времени), вам понадобится, чтобы ваш синтаксический анализатор построил дерево для представления выражений и грамматики входных данных. В простом случае оценки выражений (например, при написании простой программы-калькулятора командной строки) ваш парсер может оценить формулу при обработке ввода, но для вашего случая, насколько я понимаю, вам нужно будет создать дерево (или Обратное польское представление, но деревья на мой взгляд проще).
Затем, прочитав значения переменных, вы можете пройтись по дереву и вычислить фактическое число.