Получилось несколько коряво в смысле кода, но зато вроде бы юзабельно.
Оформлено в виде ActiveX DLL, чтобы в классах были публичные UDT и енумы.
Интерфейс класса clsParser:
Go -- получает строку, разбирает её и строит дерево.
Root -- корень получившегося дерева. Его метод Evaluate возвратит результат вычисления.
Symbols -- коллекция под символы. Константы могут быть любого типа, приводимого к Double; функции должны быть классами-функторами, принимающими массив Double (см. пример).
Коллекция символов должна быть задана до вызова Go, потому что ссылки на неё расползаются по дереву. Но сами символы в неё добавлять и удалять можно в любое время.
Класс clsParser одноразовый: после первого вызова Go он превращается в зомби. Можно взять из него Root, а сам класс выбросить.
Предусмотрена многоуровневая обработка ошибок. У всех ошибок в Err.Source записывается позиция в строке, в которой эта ошибка возникла.
Таблицы, управляющие автоматами, сгенерированы парой flex/yacc. Менять их вручную, чтобы потвикать грамматику -- сомнительное удовольствие. Может, кто-нибудь сподобится написать кк для VB6? Для всех остальных популярных языков (C, C++, C#, Java) их уже навалом.
Распознаваемые выражения состоят из чисел, символов, и четырёх арифметических действий.
Число -- это последовательность вида [0-9]*(\.[0-9]*)?([Ee][+-]?[0-9]+)? (в мантиссе должна быть хотя бы одна цифра)
Символ -- это последовательность вида [A-Za-z_][0-9A-Za-z_]*
Распознаваемая грамматика:
- Код: Выделить всё
expr: NUMBER
| NAME args
| expr '+' expr
| expr '-' expr
| expr '*' expr
| expr '/' expr
| '-' expr
| '+' expr
| '(' expr ')'
;
args: | '(' seq ')' ;
seq: exp | exp ',' seq ;