|
Программирование >> Формирование пользовательского контейнера
vt.v type = tok; запоминает тип vt.value =0; инициализирует переменную с нулевым значением Обрабатывает список, разделенный запятыми, do { get token{); получает имя var Проверяет, нет ли уже переменной с тем же именем, что и у локальной переменной в этой области видимости, if(!local var stack.empty()) for(int i=local var stack.size()-1; i >= nest scope stack. topO ; i-) i f(!s trcmp(local var s tack[i].var name, token)) throw InterpExc(DUP VAR); strcpy (vt. var name, token); local var stack.push back(vt); get token(); } while(*token == ,); if(*token != ;) throw InterpExc(SEMI EXPECTED); Каждый раз, когда встречается локальная переменная, ее имя, тип и значение (первоначально 0) помещаются в стек. Процесс протекает следующим образом. Сначала функция decl locai () читает тип объявленной переменной или переменных и устанавливает их начальное значение, равное нулю. Далее она входит в цикл, в котором читаются имена из разделенного запятыми списка идентификаторов. Каждый проход цикла помещает информацию об одной переменной в стек локальных переменных. Во время обработки проверяется, нет ли уже переменной с таким же именем в текущей области видимости (переменные, объявленные в текущей области видимости, находятся между текущей верщиной стека iосаi var stack и значением индекса, сохраненным в вершине стека nest scope stack). В конце выполняется проверка - для того, чтобы убедиться, что последняя лексема содержит точку с запятой. Вызов функций, определенных пользователем Возможно, самая трудная часть реализации интерпретатора для языка С++ - это управление выполнением функций, определенных пользователем. И не только, потому что интерпретатору нужно начинать чтение исходного кода с новой позиции, а затем возвращаться в вызывающую процедуру после завершения функции, ему приходится иметь дело со следующими тремя задачами: передачей параметров, выделением памяти для них и возвратом значения из функции. Все вызовы функций (за исключением начального вызова функции maino) выполняются через анализатор выражений из функции atom о с помощью вызова функции call (). Именно эта функция обрабатывает тонкости вызова функций. Далее приведен ее код. Давайте внимательно исследуем эту функцию. Вызывает функцию. void call О char *1ос, *teiip; int Ivartenp; Сначала находит точку входа функции, loc = find func(token); if(loc == NULL) throw InterpExc(FUNC UNDEF); функция не определена else { Сохраняет индекс стека локальных переменных. Ivartenp = local var stack.size(); get args(); получает аргументы функции tenp = prog; сохраняет местоположение return func call stack.push(1vartenp); заносит в стек индекс локальной переменной prog = loc; переустанавливает prog на начало функции get params(); загружает параметры функции со значениями аргументов interpO; интерпретирует функцию prog = tenp; переустанавливает программный указатель if{func call stack.empty()) throw InterpExc(RET NOCALL); Восстанавливает прежнее состояние 1ocal var stack. local var stack.resize(func call stack.top()); func call stack.pop0; Первое, что делает функция call (), - находит местоположение в исходном коде точки входа заданной функции с помощью вызова функции find func(). Далее она сохраняет текущий размер стека локальных переменных в переменной ivartemp. Затем вызывается функция get args () для обработки любых аргументов функции. Функция get args() читает разделенный запятыми список выражений и помещает их в стек локальных переменных в обратном порядке (выражения заносятся в стек в обратном порядке, потому что так их легче сопоставить с соответствующими им параметрами, когда функция интерпретируется). У помещаемых в стек значений нет имен. Имена даются параметрам функцией get params (), к которой мы скоро вернемся. Когда аргументы функции обработаны, текущее значение переменной prog сохраняется в переменной temp. Этот адрес - точка возврата функции. Далее значение ivartemp заносится в стек вызовов функций func caii stack. Его задача - запоминать значение индекса вершины стека локальных переменных при каждом вызове функций. Это значение представляет собой начальную точку в стеке локальных переменных для переменных (и параметров), относящихся к функции, которая вызывается. Значение в вершине стека вызовов функций используется для того, чтобы помешать функции обращаться к любой локальной переменной, не объявленной в ней. Следующие две строки кода устанавливают программный указатель на начало функции и с помощью вызова функции get params() связывают имена ее формальных параметров со значениями аргументов, уже находящихся в стеке локальных переменных. Для этого функция get params () читает каждый параметр и копирует его имя в соответствующий аргумент, уже помещенный в стек локальных переменных local var stack. Непосредственное выполнение функции осуществляется функцией interpO. Когда функция interpO возвращается, указатель программы (prog) устанавливается в точку возврата, а индексу стека локальных переменных присваивается значение, бывшее у него до вызова функции. Этот финальный шаг обеспечивает эффективное удаление из стека всех локальных переменных и параметров функции.
|
© 2006 - 2025 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |