Итак, сразу ссылки на исходники anon:anon@svn://svn.loglist.org/usr/svn/opensource/msl-fl/ и anon:anon@svn://svn.loglist.org/usr/svn/opensource/msvlib . Исходный код будет еще и тут:
http://pastebin.com/G8PKZLq5 . Версия: #define USE_MSLFL_VER 3
Следующая задача: .
Немного подумать и можно писать код. Но для начала: а что мы вобще такое пишем? Интерпретатор с синтаксисом c++ и php, последний нам ближе. Так что же, у нас, такое переменные? Это динамический массив в каждый элемент которого можно запихнуть такой же массив. То есть структура проста: ключ, значение, указаель на следующий элемент и указатель на массив, хранящийся в этом массиве.
Класс:
class msl_value{
// prev, next, up first, up end
msl_value *_p, *_n, *_a, *_e;
MString key, val;
};
Теперь я беру свой шаблон OMatrixT, который разрулит всеми указателями и пишу функции New() - выделяющую память под переменную, Find() - ищет переменную по имени, Get() - возвращает значение переменной, Set() - соответственно устанавливает. В итоге:
class msl_value : public OMatrixT{
public:
// prev, next, up first, up end
msl_value *_p, *_n;
MString key, val;
msl_value(){ _p=0; _n=0; }
msl_value* New(){
msl_value *p=new msl_value;
if(!p) return 0;
OMAdd(p);
return p;
}
msl_value* Find(VString key){
if(!this) return 0;
for(msl_value*p=_a; p; p=p->_n){
if(p->key==key) return p;
}
return 0;
}
void Set(VString key, VString val){
msl_value *p=Find(key);
if(p){
p->val=val;
} else{
p=New();
if(p){
p->key=key; p->val=val;
}
}
return ;
}
VString Get(VString key){
msl_value *p=Find(key);
if(p)
return p->val;
else
return VString();
}
void Del(VString key){
msl_value *p=Find(key);
if(p){
OMDel(p); delete p;
}
return ;
}
~msl_value(){ Clear(); }
void Clear(){ OMClear(); }
};
Добавляем это в msl как msl_value global; и никак иначе. Глобальные переменные есть. Где-то в процессе нужно будет подумать о работе с ветками переменных в случае передачи их в функцию или обратно. А сейчас думаем над передачей самой переменной. Например в случае $hello='Hello World!'; мы должны записать имя первой переменной. Даже не так, мы ее установим, раз в нее устанавливаются данные. Это нужно для того, чтобы на нее можно было ссылаться. Дальше выполняем 'Hello World!', который дожен вернуться как msl_val, где key пустой, а значение 'Hello World!'. Ок. Так же перепишем обработку параметров функций, чтобы передавать не строку, а msl_val.
Вот кстати можно реализовать function()='value', чтобы значение подставлялось как последний пераметр.
Так, вот итоговая мысль, видим переменную - создаем, это нужно для всяких $a[$b]['c'][0xd][e()]; если в нее не устанавливаются данные удалим, ибо у нас линейность, а значит обрабатываем по порядку и не знаем, просто она тут висит или в нее устанавливаются данные.
Теперь по шагам.
Пусть все крутится в DoCode(), он будет раскрывать все скобки, находить переменные и функции. Для того, чтобы он понимал, когда выйти добавляем параметр unsigned char ecode=1, сначала неактивный, ибо ну кто добавит char(1) в код? В принципе подойдет любое другое неиспольземое значение. Надеюсь не будет предложений ecode=0 и if(ecode), что абсолютно лишнее. Добавляем обработчик if(*line==ecode){ return ; }. Ок, всякие (), [] готовы к обработке. Так как в функции может быть и скобка и запятая, добавляем еще один такой же параметр.
Так же надо добавить возвращение результата, добавим параметр msl_value &outval. Порядок.
Переписываю DoCode() под обработку всех возможных вариантов. DoCodeFunctionArgs() больше не нужна, DoCode() прекрасно выполнит ее функцию.
Новая схема работы: Do() -> DoCode(line, to, outval, ';'); Код делится на блоки по ;, пока не дойдет до конца.
DoCodeValues() обрабатывает переменные,
Добавляем SGet() в msl_value, эта функция вернет адрес на переменную, если ее нет, создаст. Это не радует, и обязательно будет удаление таких переменных, если им не присваивается значение. А лучше сделать так сразу. Скажем через тот же SGet(), установив указатель val.sz=0xffffffff; Указатель остается нулевым, и никаких последствий быть не должно, а переменная помечена.
... Много кода спустя.
Есть, работает. Пришлось поработать над DoCode() и DoCodeFunction(), остальное практически без изменений. Код стал сложнее, добавилась работа с переменными, которые у нас одного типа в виде динамических массивов.
Жить стало лучше, жить стало веселее, однако и на данном этапе разработки код особо не поиспользуешь. Вот и остается думать, что делать дальше.
В планах: подключаемые функции, новый класс для хранения переменных, мысли о многопоточности. Но это все не главное. Нам нужны if, while и for, нам нужны операции с переменными, весь набор: !, ||, &&, ., +, /, *, -, .=, ... Одна из этих важных тем и станет нашей следующей целью. Они обе достаточно сложные и вот тут то придется пораскинуть мозгами. Все, что написано до этого сущая ерунда, всего-то 480 строк.
Наслаждайтесь, экспериментируйте, ищите ошибки и баги. Следующий шаг совсем скоро.