Главная страница

компилятор ТСС. Tiny c compiler by Fabrice Bellard Описание алгоритмов


Скачать 191.99 Kb.
НазваниеTiny c compiler by Fabrice Bellard Описание алгоритмов
Анкоркомпилятор ТСС
Дата08.11.2019
Размер191.99 Kb.
Формат файлаodt
Имя файлаtcc book.odt
ТипДокументы
#94047
страница11 из 38
1   ...   7   8   9   10   11   12   13   14   ...   38
void parse_number(const char *p) Функия работает с массивом token_buf, состоящим из 1024 байт. Временной переменной q присваивается адрес начала этого массива. Текузий ASCII симовл записываеется в переменну ch, это значение записывается в t и еще раз получется по указателю p. Т.е. в t оказывается символ, предшествующий текущему. Этот символ записывается по адресу q База системы счисления (переменная b) в начале выполнения равняется 10. Проверяется значение переменной t, если это '.', управление передается на метку float_frac_parse. Если встречается 0 а за ним 'x' или 'X', то база системы системы счисления обновляется значением 16, из потока считывается еще один ASCII-символ, а ссылка на '0' в буфере сдвигается назад чтобы использовать занимаемое им место. Если установлен флаг tcc_ext, то за нулем моежет идти 'b' или 'B'. В этом случае производятся теже самые едйсствия, только база системы системы счисления обновляется значением 2 Бесконечный цикл обновляет значение t величеной текущего числа. Если текущий ASCII-символ лежит между 'a' и 'f', от его кода отнимается код 'a' и прибавляется 10. Если текущий ASCII-символ лежит между 'A' и 'F', от его кода отнимается код 'A' и прибавляется 10. Третье условие проверка является ли ASCII-симовл цифрой. В этом случае от его кода отнимается код ASCII-символа '0' Если ни одно из предыдущих трех условий не выполненно, бесконецный цикл прерывается. Если величина полученого числа больше базы, цикл так же прерывается. Если в буфер записано слишком много цифр компилятор завершается. Это действие предворяется метой num_too_long Если ни одно из условий прекращения цикла не сработало, ASCII-символ заносится в буфер и получается новый ASCII-символ. Далее проверяется переход к дробной части. Условие сработает, если встречен ASCII-символ '.', либо мы имеем дело с десятичной системой счисления и встречаем 'e' или 'E', либо мы имеем дело с шестнадцатиричной системой счисления и встерчаем символ 'p' или 'P'. Если сработал переход к дробной части, но система счисления не десятичная, то происходит следующая обработка: В конец буфера записывается нулевой символ. Для шестнадцатеричной системы, сдвиг устаналвливается равным четырем битам, для двоичной двум. Оба элемента массива bn обнуляются с помощью bn_zero() Указатель в буфере (переменная q) помещатеся на его начало. Пока не встречается нулевой символ, продолжаем собират число из составных частей. Вычитаем из ASCII-символа код 'a', 'A' или '0' в зависимости от самого символа и вызываем bn_lshift() для добавления части в число. Она модифицирует оба элемента массива bn. На первом шаге значение младшего элемента сдвигается на величину сдвига и производтся побитовое ИЛИ с переданным значением. На втором шаге присходит тоже самое со старшим элементом, только переданное значение заменяется результатом полученным на пердидушем шаге сдвинутым на 32 бита вправо. Счетчик frac_bits обнуляется Если текущий ASCII-символ это '.', то он пропускается и начинается бесконечный цикл, который закончится если один из следующих ASCII-символов не лежит между 'a' и 'f', 'A' и 'F' или '0' и '9'. Полученная из ASCII-кода часть числа проверяется на превышение основания системы счисления и затем передается на вход bn_lshift(). Счетчик frac_bits увеличивается на величину сдвига, из потока извлекается следующий ASCII-символ Для двоичных и щестнадцетиричных чисел следующий символ должен быть 'p' или 'P'. Если это не так компилятор завершается ошибкой иначе символ пропускается. Предполагается что экспонента будет положительной. Ее значение обнуляется. Пропускаются ASCII-символы '+' и '-', в случае '-' знак экспоненты менятся на отрицательный. Следующий ASCII-символ должны быть цифрами экспоненты, если это не так, компилятор завершается. Все обнаруженные далее цифры объединяются в одно число с помощью вычитания кода ASCII-символа '0' и умножения предидущего результата на 10. Итоговому результату присваиваетсся знак. Два числа типа int из массива bn объединяются в одно число типа double. Это число изменятся с помощью ldexp(). Ей на вход передается разность итоговой величины мантисы и счетчика frac_bits ASCII-симовл обнаруженный после цифр мантисы переводится в верхний регистр. Если это 'F', то выставляется токен TOK_CFLOAT. Если 'L', выставляется TOK_CLDOUBLE. В обоих случаях обнаруженный ASCII-символ пропускается. Если символ не обнаруживается, выставляется токен TOK_CDOUBLE без пропуска символа. В зависимости от токена число запивывается в разные поля глобальной структуры CValue. В поле f для TOK_CFLOAT, в поле ld для TOK_CLDOUBLE, в поле d для TOK_CDOUBLE Для десятичной системы счисления если встречается '.', проверяется указатель q если от вышел за границы буфера, осуществляется переход на метку num_too_long В буфер записывается '.' и из потока получается следующий ASCII-символ. С метки float_frac_parse начинается копирование в буфер всех найденных далее цифр. Указатель q на каждом шаге проверяется на выход за границы буфера. Если встречается ASCII-символ экспоненты 'e' или 'E', он помещается в буфер и получется новый символ, если следующий ASCII-символ это '-' или '+', он так же помещается в буфер. Далее проверяется что следущие ASCII символы это цифры экспоненты, если это не так, компилятор завершается. Все эти цифры добавляются в буфер. При каждом получении ASCII символа, указатель q проверяется на переполнение. В буфер добавляется нулевой символ. Далее происходит поиск и пропуск ASCII символа 'F' или 'L', если найден 'F', то в поле f глобальной структуры Cvalue записывается результат вызова strtof(), если найден 'L' то в поле ld записывается результат strtold(). Если не найден один из этих символов, в поле d записывается результат strtod(). Каждому сулчаю соотвествует свой токен: первому TOK_CFLOAT, второму TOK_CFLOAT, третьему TOK_CDOUBLE. Если после десятичных или шестнадцетеричных чисел не найдена точка или экспонента происходит следующая обработка. В конец буфера добавляется нулевой символ, указатель перемещается на начало. Если основание системы счисления определено как 10, но первая цифра это 0, тогда он пропускается, а основание системы счисления меняется на 8. Итоговое число обнуляется. Начинается бесконечный цикл который закончится когда в буфере будет обнаружен нулевой ASCII-символ. Осатльные шестнадцетиричные и десятичные цифры преобразуются из ASCII-символов. Проверяется превышение основания текущей системы счисления. Цифры объединяются в итговое число с помощью умножения на основание системы счисления. При умножение проверяется переполнение числа. Выполнив операцию побитового И итогового числа с 0xffffffff00000000LL и сравнив результат с нулем, мы поймем нужно ли выделить побольше памяти. Если да, то выполним двоичный сдвиг на 63 позиции и если значение больше нуля, то выставляем токен TOK_CULLONG. Если памяти нужно много но при сдвиге получено нулевое значение, выставляем токен TOK_CLLONG. Если памяти нужно не так много, то возможны два варианта: итоговое число больше 0x7fffffff, тогда выставлем TOK_CUINT, если меньше, выставляем TOK_CINT Счетчики ASCII-символо 'L' и 'U' обнуляются. Бесконечный цикл переводит текущий ASCII-символ в верхний регистр и сравнивает его последоватльено с 'L' и 'U'. При нахождении букв увеличиваются соответствущие счетчики, которые на каждом шаге проверяются на переполнение. Если счетчик 'L' достигает 2, то TOK_CINT заменяется TOK_CLLONG, а TOK_CUINT заменяется TOK_CULLONG. Если счетчик 'U' достигает 1, TOK_CINT заменяется на TOK_CUINT, а TOK_CLLONG) заменятеся TOK_CULLONG. Если памяти нужно не много (токены TOK_CINT или TOK_CUINT), то в глобальной структуре CValue используется поле ui, если памяти нужно больше (остальные токены), то поле ull
1   ...   7   8   9   10   11   12   13   14   ...   38


написать администратору сайта