static void next(void) Начиня с метки redo, вызывается next_nomacro(). Если указатель macro_ptr обнулен: Если присвоенный токен не является служебным (занчение меньше TOK_IDENT) и установлен флаг парсинга PARSE_FLAG_PREPROCESS. Функция define_find() может найти сущность. В этом случае подготавливается экземпляр структуры TokenString с помощью tok_str_new(). Обнуляется цепочка сущностей nested_list и передается вместе с остальными подготовленными парамерами в macro_subst_tok(). Если вызов этой функции окажется удачным, вызывается tok_str_add(), которая добавляет переданный ей ноль в конец, одновременно обновляя поля экземпляра структуры TokenString и выделяя память если нужно. Указатели macro_ptr и macro_ptr_allocated обновлеются адресом поля str полученного экземпляра TokenString, выполнение переходит на метку redo. Если указатель macro_ptr не обнулен: Если установлен флаг unget_buffer_enabled, указатель macro_ptr обновляется значением unget_saved_macro_ptr. Флаг unget_buffer_enabled сбрасывается. Если во время проверки флаг unget_buffer_enabled сброшен. Память занятая macro_ptr_allocated освобождается с помощью tok_str_free() она в свою очередь просто вызывает tcc_free(), макрос macro_ptr обнуляется, выполнение переходит на метку redo Если встечается токен TOK_PPNUM и установлен флаг парсинга PARSE_FLAG_TOK_NUM, вызывается parse_number() для текущего экземпляра структуры CValue static int macro_subst_tok(TokenString *tok_str, Sym **nested_list, Sym *s, struct macro_level **can_read_stream) Начнем с условия, когда встечаются токены TOK___DATE__ или TOK___TIME__ Используются две функции, предоставляемые операционной системой time() и localtime() чтобы заполнить соответствующие структуры значениями текущего времени. Для первого макроса, полученные значения выводятся в строку "%s %2d %d" для отображения даты, а для второго в "%02d:%02d:%02d" для отображения времени. Переменная cstrval будет содержать ардрес получившейся строки. Далее идет метка add_cstr она предполагает что будет добавлен токен строкового типа. Следующая метка add_cstr1, она предполагает что тип уже определен до нее. Создается строка с помощью cstr_new(), заполняется с помощью cstr_cat(), в конец добавляется нулевой символ с помощью cstr_ccat(), подготавливается экземпляр структуры Cvalue и для ее вызывается tok_str_add2() Вернемся к двум пропущенным обработкам. Если встречается TOK___LINE__ текущая строка файла (поле line_num) выводится в строку с помощью snprintf(). Ее адрес записывается в cstrval, тип токена выставляется в TOK_PPNUM и управление передается add_cstr1 Если встечается токен TOK___FILE__ Адрес имени файла (поле filename) записывается в cstrval и управление передается add_cstr Если три предидущих условия не сработали, то макрос обрабатывается следующим образом: Флаг mstr_allocated сбрасывается. Из переданного экземпляра структуры Sym связанный с ним ASCII-символ записывается в переменную mstr, поле type укзывает на структуры типа. В этой структуре поле t определяет код типа. Если это MACRO_FUNC, происходит следующая обработка: С метки redo начинает обработка, если указатель macro_ptr содержит не нулевое значение. Мы получаем код макроса по данному указателю. Если это 0 и указатель can_read_stream, переданный в параметре не нулевой, получаем по этому указателю на адрес в цепочке структур macro_level. Если этот адрес не нулевой, указатель macro_ptr обновляется указателем взятым из полученного экземпляра стркутуры macro_level. В этом экземпляре указатель обнуляется. Адрес в параметре can_read_stream обноляется полем prev той же структуры. Выполнение возвращается на метку redo Если указатель macro_ptr содержит нулевое значение, мы провереям первый ASCII-символ по указателю buf_ptr. Пока мы обнаруживаем символы пропуска (пробел, табуляция и т.д), а так же символы перевод строки, мы их не обрабатываем. Первый же ASCII-символ, отличный от указанных помещается во временную переменнюу t для последующей обрабоки. Предполагается что за именем макроса следует открывающаяся скобка, если это не так, завершаем обработку. Функция next_nomacro() вызывается дважды. Один раз для скобки, второй раз для параметра. В начале функции обявляются два указателя на сущности args и sa. Указатель args обнуляется, а sa обновляется полем next, сущностьи переданной на вход вункции. Если встречается закрывающаяся скобка, а оба указателя пусты, завершаем разбор параметров макроса. Если цепочка sa сразу же обрывается, выполнение компилятора завершается с ошибкой. Инициализируется str - новая строка с помощью tok_str_new(). Бесконечный цикл продолжается пака next_nomacro() в процессе обрабоки не выставит минус один как код токена, т. е. не встретит ошибку. Второе обязательное условие — количество закрывающих скобок должно быть больше, чем отрывающихся (контролируется увеличением и уменьшением переменной parlevel) это условие используется в связке ИЛИ с условием, что текущий ASCII-символ отличен от закрывающейся скобки и запятой или текущая сущность в цепочке sa имеет ненулевой тип. Если текущий токен это не TOK_LINEFEED, для него вызывается tok_str_add2(), которя добавляет текущий токен и связанный с ним экземплят структуры CValue в строку str. Добавляется завершающий нулевой символ. С помощдю sym_push2() в цепочку args добавляется сущность, содержащая все ASCII-симовлы, собранные в строке str. Код токена и его тип берутся из текущего токена в цепочке sa. Позиция в цепочке sa переремещается вперед. В обычно случае, закрывающася скобка останавливает цикл разбора параметров макроса, но если включена поддержка вложенных параметров GNU, в цепочке sa остались сущности и у текущей сущности ненулевой тип, при встрече закрывающейся скобки, обработка продолжается. Предполагается что параметры разделены запятой, если это не так, компилятор завершается с ошибкой. Для запятой вызывается next_nomacro() и бесконечный цикл продолжатся. После завершения обработки параметров, в цепочки sa должны остаться сущности, если это не так, компилятор завершается с ошибкой. Вызывается macro_arg_subst(). Ей передается указатель nested_list. Фунции выстраивают цепочку, связанную этим указателем. Следует отметить, что next() вызывает рассматриваемую сейчас функцию macro_subst_tok() передавая ей указатель на NULL. Т.е. на начало списка. Сам собой адрес сам по себе не нулевой, хотя данные хранящиеся по данному адресу нулевые. Так же на вход функции передается mstr и цепочка args. Результат функции заносятся в ту же mstr В конце для поля структуры Sym, содержащего строку вызывается tok_str_free(), за тем sym_free() для самой структуры. Ссылка на структуру обновляется предоварительно сохраненной ссылкой на предыдущую структуру, которая сохраняется во временной переменной до очистки. Очистка продолжатеся пока не достигнет нулевой ссылки, т. е. конца цепочки. Устанавливается флаг mstr_allocated После всех условий вызывается sym_push2() чтобы добавить в nested_list, новый токен. macro_subst() вызывается для замены макроса на оконьчательный код. Связанный список nested_list применяемый при замене сдвигается на одну позцию назад с помощью сохранения текущий позиции и вызова для нее sym_free() после сдвига. Если в процессе обработки был установлен флаг mstr_allocated, то вызывается tok_str_free() для строки mstr. |