бордер-то, может, и простая команда, но параметром может быть любое сложное выражение
синтаксически разбирается и вычисляется которое универсальной медленной процедурой
бордер-то, может, и простая команда, но параметром может быть любое сложное выражение
синтаксически разбирается и вычисляется которое универсальной медленной процедурой
Прихожу без разрешения, сею смерть и разрушение...
С любовью к вам, Yandex.Direct
Размещение рекламы на форуме способствует его дальнейшему развитию
Нет. Я имел в виду немного другое.
Интерпретатор тратит около 10 тыс. тактов просто на команду. Не на выражение, а на команду.
А вот если сделать "сложное выражение" и прогнать через компилятор, то даже синусы-косинусы, которые вычисляются ТЕМИ ЖЕ процедурами ПЗУ будут работать быстрее "простых" команд.
Тем более интерпретатору НЕ НАДО разбирать параметр, при вводе строки этот параметр уже преобразовался к 5 байтному значению - его просто надо загрузить и выполнить.
- - - Добавлено - - -
К сожалению я проверял в эмуляторе и из 128 режима, поэтому он мог мне приврать несколько процентов.
Но в любом случае 7 и 10 команд - цифры одного порядка, всё равно это тысячи тактов.
Это безумно много.
- - - Добавлено - - -
Я утрировано так написал. Понятно что у них не было ни времени с этим разбираться ни больших объёмов ПЗУ чтобы всё это хранить.
И даже бейсик-то они не с нуля присали а большую часть слизали из предыдущих проектов, где этот бейсик был ещё хуже.
Перефразирую по-другому, что если бы в проект добавить спеца, увеличить ПЗУ и дать чуток больше времени на подготовку, то без проблем бейсик мог бы работать почти со скоростью компилятора
- - - Добавлено - - -
С этим никто не спорит. Это и 30 лет назад понятно было. Просто несправедливость-то вопиющая
- - - Добавлено - - -
Дело как бы не в процедурах, которые рисуют на экране.
Ну медленные там CIRCLE, DRAW, PRINT и всё иже с ними, ну и положить на это.
Очень медленным получился сам интерпретатор.
- - - Добавлено - - -
не помню, читал ли эту книжку в детстве. У меня не было свободного доступа к литературе. В любом случае, даже если листал её, то уже после изучения машинных кодов.
но даже оттуда цитирую (с сокращениями):
Наиболее простой способ трансляции - это немедленный "дословный" перевод, так называемая интерпретация.... Интерпретатор опознаёт ключевые слова языка и тут же подсовывает процессору соответствующую последовательность кодов.
Компилятор... создаёт программу в кодах, независимую от каких либо трансляторов.
Но ещё раз обращаю внимание (с BORDER это может быть и не показательно) что, и интерпретатор, и компилятор вызывают одни и те же процедуры ПЗУ: они оба в конечном итоге выполняют команду CALL ПЗУ
Просто компилятор это может сделать сразу, а вот интерпретатору придётся "опознать ключевое слово". Но блин, ключевое слово - ОДИН БАЙТ. А на это тратится тысячи тактов
Еще раз, внимательно, по слогам. Для интерпретатора не существует "просто команды". Даже для уже токенизированной строки он сперва определяет по одной таблице класс команд по типу и количеству операндов, потом парсит и вычисляет операнды, каждый из которых может оказаться (а может и не оказаться, но интерпретатор не помнит этого) выражением весьма сложным, потом только находит по второй таблице через токен и вызывает нужную процедуру. Тыщи тактов на ВСЁ это вместе всегда уходит. Код к тому же не оптимизированный по скорости.
Прихожу без разрешения, сею смерть и разрушение...
vlad-kras(16.11.2023)
Я вам верю что спектрум-бейсик это делает именно так.
Просто "определяет по одной таблице класс команд по типу и количеству операндов" - это звучит пугающе. А на самом-то деле раскидали по таблице токенов - первые 5 токенов = без операндов (cls, run), потом 10 с одним операндом (paper, border, peek), потом ещё 10 с двумя и т.п. - при грамотном порядке токенов "класс команды" определяется из её номера напрямую.
"потом парсит... операнды"
К сожалению у меня пробел в знаниях, поэтому я не знаю насколько это сложно. Но можно ж было как-то облегчить интерпретатору этот парсинг, чтобы он не тратил тыщи тактов на него.
"вычисляет операнды, каждый из которых может оказаться (а может и не оказаться, но интерпретатор не помнит этого) выражением весьма сложным"
в этом деле интерпретатор НЕ отличается от компилятора - и тот и другой считают выражения на встроенном калькуляторе. Ну и выражение сложное/простое - это ж одна проверка и один переход - ну два, ну три десятка тактов...
"потом только находит по второй таблице через токен и вызывает нужную процедуру"
ну и в чём проблема-то? LD A,код_токена: ADD A,A: LD H,адрес_таблицы: LD L,A: LD B,(HL): INC L : LD C,(HL): PUSH HL: RET = итого меньше 70 тактов получается
Если код токена известен и таблица удобно размещена, то вообще можно за 50 тактов сделать
Просто изначально непонятно ну зачем так тормозить ;(
Такое происходит при использовании любого ЯВУ.
Можно вырубить себе дом в скале, или построить конуру из ж\б блоков. Именно этим и приходится платить за то, чтобы не держать в голове адреса подпрограмм ПЗУ (те же команды работающие с магнитной лентой, явно стоят того, чтобы не заниматься эквилибристикой с ассемблером) и использовать "универсальные" конструкции типа арифметических и логических значений в одних и тех же операторах. Именно поэтому компилляторы имеют граниченный список операторов которые они могут "переварить" в набор маш. процедур.
- - - Добавлено - - -
Фишка в том, что тот же RUN может использоваться как с параметром, так и без (по сути, он всегда с параметром, даже если его не задал пользователь). С остальными командами, аналогичная ситуация (тот же GO TO n может использоваться с явным числовым выражением, а может использоваться алгебраическая конструкция GO TO n+m, и даже, алгебраически-логическая GO TO n+(m AND a)+(o AND b).
Когда есть, но не знаешь где - это все равно, что нету.
vlad-kras(16.11.2023)
Небольшой пример приведу на счёт с параметром и без параметра. Есть такая вроде бы функция BIN. Но это на самом деле не функция, это другое представление числа. После него так же идёт пятибайтная форма. И даже если [B]BIN[/] без параметров то дальше идёт пятибайтный ноль. То есть не было проблем превратить команду без параметров в команду с параметрами на уровне редактора.
А вот теперь про выражения, тоже обращаю внимание: а как компилятор считает выражения?
Если мы возьмём современный оптимизирующий компилятор - то он оценит требуемый тип - целое, если в выражении все переменные целые - то он посчитает их без привлечения сопроцессора. Более того, современный компилятор умный, он может заметить, что "переменные" n и m на самом деле константы (задаются один раз в программе, либо однозначно задаются недалеко от места их использования)... поэтому в некоторых случаях оптимизирующий компилятор заменит выражения на их значение.
Но разговор-то про примитивный компилятор. Который ничего не придумывает за программиста, а тупо выполняет.
Соответственно "скомпилированная" программа также будет считать выражения. И интерпретатор считает и компилятор считает - получается разница не слишком большая...
- - - Добавлено - - -
Лет 25 бы назад за такую книжку душу бы продал. А сейчас к сожалению лениво.
Но насколько мне не изменяет память "пятибайтный" формат может специальным образом хранить целые в дополнительном коде
Соответственно, можно было десятком проверок пробежаться по команде PLOT 128,88 и вызвать PLOT_BC из ПЗУ.
Конвертация-то не всегда нужна.
- - - Добавлено - - -
Ещё раз резюмирую что хотел сказать про компиляторы.
Есть оптимизирующий компилятор. Который понимает код лучше программиста.
Например делаем CLS: RUN - компилятор понимает, что два раза чистить экран не нужно, поэтому команду CLS можно выкинуть.
или DRAW 128,88: PLOT 128,88 - тут тоже компилятор видит, что точка уже поставлена, команда PLOT 128,88 - лишняя.
А есть обычный тупой компилятор - ему дают команды и он их транслирует в код, который потом будет выполняться. Каждая команда - в свой кусок кода. Разумеется, этот компилятор будет пользоваться встроенным калькулятором - во первых ради упрощения программы и уменьшения кода, а во вторых из-за совместимости: негоже если в интерпретаторе и в скомпилированной программе вычисления будут давать разные результаты. И получается разница совсем небольшая интерпретатор вызывает калькулятор или машинный код вызывает калькулятор.
В детстве набирал программку из ZX-Ревю http://zxpress.ru/book_articles.php?id=750 по рисованию криволинейной поверхности.
Она работала безумно медленно. Попробовал заменить синус (вернее сразу всю функцию) на массив - получилось лишь немногим быстрее.
Откомпилировал обе версии в Tobos FP - вариант с синусом работал сносно, с массивом - довольно неплохо.
Если же писать в ассемблере на кодах калькулятора, то получалось ещё быстрее чем Tobos FP в варианте с синусом.
Вот и получается ересь: во всех трёх случаях (без массива которые) используются одни и те же процедуры ПЗУ, но почему-то с Tobos FP работает работает намного быстрее бейсика, а ассемблер - ещё быстрее. Хотя казалось бы синус он и в Африке - синус. Да и калькулятор один и тот же (сопроцессор я не вставлял).
Значит основные тормоза давал интерпретатор, потому что арифметика во всех трёх случаях не менялась...
mmxdmv, вроде как tobos, использует свой калькулятор и формат хранения чисел ("Диалекты Spectrum-бейсика", изд. Питер).
Попутно, накладывается ограничение на некоторые операторов (где-то полностью, в других случаях, частично теряем ряд фукций операторов).
А если использовать целочисленные компилляторы, прирост скорости выполнения получается еще больше.
Последний раз редактировалось null_device; 17.07.2017 в 17:39.
Когда есть, но не знаешь где - это все равно, что нету.
Эту тему просматривают: 1 (пользователей: 0 , гостей: 1)