Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
||||||||||||||||||||||||||||||||||||||||||||||
1 | ||||||||||||||||||||||||||||||||||||||||||||||
Пишем свой интерпретатор языка BASIC20.06.2009, 20:03. Показов 242538. Ответов 464
Метки нет (Все метки)
Благодаря форуму и Evg в частности интерпретатор развивается, потихоньку превращаясь в простенький интерпретатор QBASIC.
Некоторые из самых старых версий сохранились в теме и ссылки на них будут добавлены в это сообщение,а также ссылки на другие темы,связанные с этой. Репозиторий с проектом находится тут, там же есть возможность в браузере посмотреть историю ревизий (английский в логах весьма примитивен,комментарии и рекомендации можете писать в личку),а также скачать самый последний архив репозитория в формате .tar.gz Если кто-то пользуется Subversion,скачать исходники можно так: Код
svn co https://basin.svn.sourceforge.net/svnroot/basin basin Технический приём для формирования согласованных данных https://www.cyberforum.ru/c-linux/thread46096.html Вопрос по svn (Subversion) Создание системы тестирования ПО. Вопрос про разные реализации бэйсиков Можно ли выразить порядковый номер элемента массива через индексы? [C++] Какие флаги указать линкеру для компиляции программы? Как можно определить переменную в файле configure.in,чтобы её можно было использовать в Makefile? Странный SIGSEGV, или что зависит от порядка написания интерфейса класса https://www.cyberforum.ru/c-linux/thread61324.html Альтернативная версия интерпретатора от Evg на C Это простая реализация разбора выражений, написанная Evg на C: Представление выражения в двоичном дереве ***************** Первое сообщение: ***************** Задание(Страуструп,из книги,по готовому коду): Введите программу калькулятора и заставьте её работать.Например,при вводе
LexicalAnalyzer.h
LexicalAnalyzer.cpp
main.cpp
Анализатор-то работает,но конечное значение не вычисляется.Более того,если вводим
Добавлено через 2 часа 5 минут 30 секунд Пришлось решать влоб с дебаггером.У Страуструпа опечатка (или намеренная ошибка,что более вероятно ) Вот в этом куске кода в функции get_token():
Добавлено через 16 минут 19 секунд И ещё опечатка была
31
|
20.06.2009, 20:03 | |
Ответы с готовыми решениями:
464
Пишем свой интерпретатор языка BASIC Пишем свой strlen Пишем свой чекер пишем свой троян с нуля |
14.08.2009, 20:43 | 81 |
Но ведь тебе никто не мешает распарсить выражение a+a+a+...<неизвестное количество раз> и построить его в виде дерева. Так же и здесь если в лоб, что всё будет в виде дерева (без бумажки нарисовать трудно). Либо всё делать линейно (т.е. вообще отказаться от оператора IF в промежуточном представлении, заменив егона пару операций BRANCH и COND_BRANCH). В любом случае в процессе распарсивания у тебя будет рекурсивный вызов одного и того же синтаксического правила, а за счёт этого построится либо нужное количество уровней в дереве, либо нужное количество операций перехода
Я потому тебя и веду по тому пути, чтобы пришлось переделывать. Ибо только занимаясь этим на практике можно реально понять КАК надо писать программу, чтобы она в будущем легко переделывалась, а так же сразу закладываться на какие-то переделки, которые сейчас не нужны, но теоретически могут понадобиться в будущем Значит пока одна большая проблема снимается с повестки дня. ТОгда надо взять за основу какой-то из существующих бэйсиков. Если все они с процедурами, то просто выкидываем поддержку процедур. Тестовых примеров насребём в соотвествующем разделе форума. Щас я туда закину вопрос по поводу всех этих бэйсиков Добавлено через 5 минут 26 секунд Закинул сюда Вопрос про разные реализации бэйсиков Добавлено через 1 час 16 минут 21 секунду Пока не забыл. Функции тем не менее остаются, но только встроенные (SIN, COS и т.п.). С точки зрения парсера удобнее считать, что это keyword'ы - проще получается разбор. С точки зрения дальнейшей поддержки функций лучше считать, что это IDENT, а дальше уже разбираться, у нас идёт обращение к переменной или вызов функции Добавлено через 4 часа 31 минуту 32 секунды Кстати, звучит как парадокс, но вариант с промежуточным представлением проще, чем с двумя проходами. Хотя тебе полезно сделать оба варианта (сначала "плохой")
1
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
||||||
15.08.2009, 23:25 [ТС] | 82 | |||||
Так,думаю,нужно подвести некоторые итоги.Я сейчас недаром застрял,я думал над реализацией промежуточного представления,но что-то никак не укладывается в голове,как вообще это организовать,то есть не вижу реализации за идеей.Вот смотрю на твой пример реализации и просто не понимаю,что с чем там будет связываться,если будет строиться дерево,то есть как после построения дерева его потом разгребать.Самое непонятное для меня это то,что переменные по ходу работы программы могу меняться,и как это связывается с деревом,вообщем бардак полный в голове Вариант с пропуском кода не лучше,то есть как-то не видится вариант реализации,делать флаги какие-то,что-ли,что-бы передавались в функции,а потом их менять после выхода из пропускаемого блока... это тоже не так просто.Это надо тогда подпортить все функции этими флагами. Понять бы получше механизм промежуточного представления,в каком точно виде всё это дерево будет и что будет его читать.
Насчёт системы тестирования-реально полезная вещь,которая позволила мне исправить кучу логических ошибок без особых затрат!Теперь даже можно сделать такой исходник
Правда пришлось делать скидку на то,что блоки в IF и WHILE пропускаются без разбора,но даже и так много изменил всяких мелочей.Пока ещё вложенность условий не поменял везде(имею ввиду непроинвертированные),но кое-что подправил.Код прилагаю,посмотри,как выглядит syntax_parser.cpp,там я поменял больше всего с точки зрения отступов и т.д.Меня очень интересует мнение по оформлению,стал ли код менее читабельным.Я расположил строки немного плотнее.
0
|
16.08.2009, 00:27 | 83 |
Я вроде уже писал. Посмотри тут посты 3 и 5. Фактически там у меня сначала строится промежуточное представление (когда выражение представлено в виде дерева), а потом обходится и обсчитывается (по сути происходит исполнение)
В данном примере по сути делается то, что должно быть в промежуточном представлении на тех местах, где идёт выражение. Если опять непонятно, буду думать, как объяснять. Проще всего было бы набросать рабочий исходник на Си для демонстрации. Может, если не поленюсь, набросаю какой-нибудь кастрированный вариант Добавлено через 11 минут 13 секунд Исходники потом гляну
1
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|
17.08.2009, 16:55 [ТС] | 84 |
Я посмотрел твои исходники,вроде всё понятно,но я не представляю,что изменить именно в моей реализации,как-то смутно всё.Как будто снова вернулся к отправной точке,когда только начинал перекраивать калькулятор.Просто не могу представить механизм работы после промежуточного представления. Может,я просто морально не готов писать всё заново Но если бы точно представлял,что и как сделать,то наверное переделал бы.
Я решил проблему с динамической памятью,оказалось,всё просто.С самого начала я не пользовался динамической памятью,но тогда прога вылетала,и я ошибочно подумал,что это необходимо,использовать new.Теперь я просто передаю сами объекты из функций.Всё использование динамической памяти было полностью убрано из программы. Ещё я добавил оператор GOTO.
0
|
17.08.2009, 17:52 | 85 | |||||||||||||||
Морально быть готовым написать заново - тоже важно И в этом вопросе я тебя понимаю.
Промежуточное представление - это некий набор структур данных, связанных между собой, которые отражают исходную программу. Пример отображения выражения ты уже видел - это дерево. Сейчас попробую на пальцах объяснить, как хранить операторы и пока не забыл, скажу: про непонятки лучше спрашивать максимально конкретно, а то какие-то вещи для меня слишком очевидны, что я за общими вопросами могу и не увидеть проблему Программа у тебя состоит из цепочки операторов. Нам всю эту цепочку надо иметь в некотором внутреннем виде, который мы затем будем интерпретировать. Если помнишь мои предыдущие пояснения, то структуры, хрянащиеся в списке, я хранил в одном флаконе: данные и топологию (т.е. как элементы связаны между собой). Мне такой вариант кажется более удобным, но я его не навязываю. Просто я сам не смогу внятно написать всё это с использованием stl'ских контейнеров, поэтому напишу именно по-своему - так хоть есть вероятность, что поймёшь Рассмотрим для начала простой код. Если ты это не поймёшь, будем жевать подробнее, если поймёшь - попробуем двигаться дальше. Поэтому для начала простой пример
Промежуточное представление будет состоять из statement'ов. Все они провязаны в список по очереди через поле next (см. ниже). Структура для хранения представления statement'а в таком упрощённом случае следующая
При таком раскладе привожу код, который "вручную" создаёт промежуточное представление. Чтобы понятно было, что у нас в итоге получится. Понятно, что аналогичное представление у тебя будет строиться в процессе работы парсера. Разделяю построение каждого оператора отдельно (ибо реально они будут отдельно), перменная Last моделирует некую глобальную переменную
Давай пока на этом остановлюсь. И жду уже более конкретных вопросов Ну подобные моменты я видел, планировал устранить это в процессе капитальной чистки мусора после того, как наметится окончательная схема. Ну если сам разобрался - одной проблемой меньше Вперёд он тоже прыгает? И приведи пример исходника, который уже работает (попробуй включить GOTO вовнутрь IF'а)
1
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|||||||||||||||||||||
17.08.2009, 18:35 [ТС] | 86 | ||||||||||||||||||||
Пыгает вроде.. у меня сами метки создаются в глобальной таблице,так что неважно,куда прыгать..В сообщение твоё сейчас буду вникать.
А вот пример:
В главной функции:
А это в syntax_parser.cpp:
0
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|
17.08.2009, 18:51 [ТС] | 87 |
А да,та версия,что я выкладывал,ещё без GOTO,так что вот новая
0
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|
17.08.2009, 19:41 [ТС] | 88 |
Да,теперь мне понятна идея реализации,по крайней мере,направление.Незнаю почему,но когда кто-то целенаправленно объясняет,мозг воспринимает лучше,хотя в исходниках было то же самое.))
Что мне не понятно: как будет организован while ,а также goto при такой реализации?Мы же уже не будем работать с файлом,тогда как узнать,на какую строку/символ прыгать? А так вроде доходит потихоньку,что у нас будут данные,но присваивания и вообще опрерации над ними ещё не произведены,и будут сделаны после. Как всегда,перекраивать надо с ног до головы Добавлено через 19 минут 44 секунды P.S.GOTO прыгает только вперёд.Потому что сначала ему надо узнать метку и создать её,а уже потом прыгать .Я понял о чём ты,скорее всего это разрешается промежуточным представлением. Добавлено через 19 минут 45 секунды Я кажется понимаю,goto просто будет хранить порядковый номер следующей инструкции.
0
|
17.08.2009, 19:52 | 89 | |||||
Я почему спросил. Если идёт GOTO вперёд, то в момент, когда ты его парсишь, метка ещё не создана, а потому куда переходить пока непонятно. Это тоже непростой момент
Интерпретатор - это всё-таки не программа школьного уровня по сортировке массива. Тут всё-таки нужны специфические навыки. Ну а в качестве первой серьёзной программы не каждый потянет. Собственно, никто не обещал, что будет легко Если идея более-меняя ясна, сейчас попробую про операции передачи управления пояснить (чуть позже) Промежуточное представление, это некий набор данных, который больше не будет меняться. Если бы мы писали компилятор, то с этого предстваления мы бы строили непосредственно код. Но поскольку у нас интерпретатор, то небольшая часть промежуточного представления будет меняться, а именно - значения переменных. Больше меняться ничего не должно. В своих примерах я Value делал в виде указателя (на некий динамический объект), но технически скорее всего будет удобнее внутри Variable хранить Value по значению (а не по ссылке) Что касается компилятора - теоретически ничего не мешает нам его в будущем написать. Пусть код будет медленным и гавёным, но это будет рабочий код. В крайнем случае можно написать конвертор Бэйсик->Си. Но это так, к сведению. Пока мы пишем интерпретатор Я ж говорю, по большому счёту структура парсера особо и не менялась. Поменяется начинка. Один раз сделав ты на своей шкуре немного лучше начнёшь понимать, как изначально писать программу, пригодную для дальнейшей безболезненной перестановки с ног на голову Добавлено через 6 минут 35 секунд Вот так выглядят метка и операция GOTO. Всё это так же является частью поля Statement.data
1
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|
17.08.2009, 20:05 [ТС] | 90 |
Да,всё вроде понятно теперь. Пока что у меня GOTO действительно только назад прыгает.
0
|
17.08.2009, 20:31 | 91 | |||||||||||||||
Теперь что касается всякийх циклов и условных исполнений. Нам дополнительно понадобится одна-единственная операция условного перехода (CONDITIONAL_GOTO)
Например, для такого кода
Код
STMK_LET, var=a, val=10 (в нормальном варианте в правой части будет Expr) STMK_COND_GOTO, cond_expr=<дерево "a<3">, label_true=L1, label_false=L2 STMK_LABEL, условно пишу L1, чтобы по тексту можно было понять. Реально из STMK_IF сюда будет торчать ссылка STMK_LET, var=b, val=20 STMK_GOTO, label=L3 STMK_LABEL, условно пишу L2 STMK_LET, var=c, val=30 STMK_LABEL, условно пишу L3 STMK_LET, var=d, val=40
Код
STMK_LABEL, L1 STMK_COND_GOTO, cond_expr=<дерево "a<3">, label_true=L2, label_false=L3 STMK_LABEL, L2 STMK_LET, var=c, val=1 STMK_GOTO, label=L1 STMK_LABEL, L3 STMK_LET, var=d, val=2
1
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
||||||
18.08.2009, 22:39 [ТС] | 92 | |||||
Ещё одна мелочь.Вот тут
0
|
19.08.2009, 20:17 | 93 | ||||||||||
Expression нет смысла провязывать в цепочку. Это же по сути дерево. Statement'ы мы в цепочку провязываем для того, чтобы всё это потом обходить последовательно. Т.е. вместо Value у тебя будет указатель на Expression, который, по аналогии с моим примером выглядить что-то типа того
Я описывал простой случай (чтобы понятно было). Реально правая часть ОБЯЗАНА (а не "может быть") выражением. Константа - это же тоже выражение. Построение дерева аккуратно укладывается в твой парсер (смотри мой пример про выражения) Добавлено через 8 минут 59 секунд Не забудь сделать отладочную печать представления. При этом каждому Statement'у надо присваимвать уникальный номер. Тогда в операциях перехода можно будет его печатать, чтобы визуально понять, куда у тебя реально идёт переход Добавлено через 4 минуты 11 секунд И сразу думай о том, как работать с массивами. Ибо, навскидку, это последний невыясненный момент Ну и надо разобраться, как же реально в Q-Basic'е идёт работа с типом. Потму как надо уже под это дело подстраиваться Добавлено через 20 часов 44 минуты 14 секунд Смотрю исходники. По оформлению читать уже гораздо проще чем раньше. Но три пробела в начале строки по прежнему убивают наповал Внутри syntax_ParseTerm ты в цикле вызываешь syntax_ParseTerm, хотя мне кажется, что надо всё-таки syntax_ParsePrimary. Проверить не могу, т.к. по тем исходникам из #87 ничего не могу запустить. На твой пример из #86 ругается "Wrong definition", а напрямую подавfть выражение в PRINT пока не работает. По идее то, что написано рабочее, но глубины воображения что-то не хватает понять, где это можетнакосячить (если накосячит вообще) Добавлено через 2 минуты 46 секунд AND, OR и XOR ты назвал BINARY_OP. Название этого термина переводится как "двухаргументная операция". Правильное названия - "побитовая операция" (BIT_OP или BITWISE_OP) Добавлено через 2 минуты 19 секунд Из syntax_parserIdentLValue ты вызываешь syntax_parserBinaryExpr, что не есть верно, т.к. у тебя в этом случае будет по синтаксису разрешена операция типа "A&B = 5" Добавлено через 3 минуты 32 секунды Фрагмент процедуры void syntax_parserStmtKwLET:
1
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|
19.08.2009, 22:37 [ТС] | 94 |
Насчёт wrong definition,скорее всего ты скопипастил код прямо из сайта,я уже писал,что названия типов должны быть маленькими буквами,это движок сайта меняет на большие,я уже задумываюсь о том,чтобы сменить с int на INT.
Насчёт 3-х пробелов - это я подглядел в где-то в исходниках GNU,и мне понравилось,потому как в той IDE,где я работаю,folding находится очень близко к краю,и часто код закрывается случайно.Ещё причина,почему это показалось удобным-так лучше видно препроцессорные команды из общей массы.То есть это не религиозное что-то,причина есть Добавлено через 31 минуту 38 секунд Насчёт LET A&B = 5 ,вроде у меня не пропускает подобные выражения,пишет "Wrong let statement".То есть LET гарантирует присваивание сразу после первого идетификатора.А вот с goto есть проблема,и правда.Как раз о чём ты говорил,внутри IF.Это происходит в момент,если например,после одного прыжка мы уже не заходим в IF,а пропускаем этот блок. Насчёт выражений в PRINT-так и было задумано,выражения только в LET Я начал что-то ваять с промежуточным кодом,пока только интерфейс tree.h - идёт туговато )
0
|
19.08.2009, 23:03 | 95 | |||||
Точно. Совсем забыл. Надо будет потом тряхануть народ на предмет этого. Подозреваю, что бэйсику должно быть до фонара INT, int или InT
Не помню, у кого вычитал. Не важно какой стиль, важно лишь, чтобы всегда делал одинаково. Нелогично А что туго? Может опять начать с простых вещей (считать, что у нас есть только LET и PRINT)? И зачем tree.h? Выражения уже сами по своей структуре являются деревоподобными. Statement'ы будут в виде списка. Как-то деревья как некое универсальное понятие особо и не нужно Добавлено через 4 минуты 59 секунд С заменой INT'а на int заработало. При вводе когда нажал Ctrl^D (т.е. фактически конец ввода), прога ушла в бесконечный цикл и начала срать на экран, потом терминал завис Добавлено через 1 минуту 42 секунды Для такого кода напечаталось 0. ОШибка
Я кстати понял причину этой ошибки. Текст спрячу. Если интересно - попробуй для начала сам разобраться qqq
То, как у тебя построена процедура syntax_parserTerm даёт эффект, что операции начинают считаться справа налево, хотя должны слева направо. 5 * 6 / 11 должно считаться как "(5*6)/11" а у тебя считается как "5*(6/11)" - почитай внимательно формальное описание синтаксиса в посте #29
1
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
||||||
20.08.2009, 01:36 [ТС] | 96 | |||||
Вот это новость! Как теперь это исправить,я даже не знаю )) Наверное я зря убрал динамическую память,помнится тогда всё работало (ну вроде )
Добавлено через 12 минут 55 секунд Скорее всего это связано с тем,что передаваемое значение-это не просто значение,а объект.Видимо,объект по значению целиком не передаётся,если он не в динамической памяти,ведь это некая составная единица,и похоже,что так делать с объектами нельзя.То есть получается,что все промежуточные значения теперь теряются при передаче из функции,я попробую переделать.Но имеет ли смысл,вроде решено делать промежуточный код ? Добавлено через 1 час 1 минуту 0 секунд А может,ты прав,я заметил,что у меня выражение вроде как по другому сворачивается,но как теперь переделать-ума не приложу. Деревья как отдельное понятие не нужны,но ведь надо же куда-то свалить все эти структуры? Добавлено через 13 минут 30 секунд Вот поменял немного-вроде теперь ок
0
|
20.08.2009, 14:12 | 97 |
С косяком при подсчёте выраения до конца разобрался? Или надо пояснить?
> Деревья как отдельное понятие не нужны,но ведь надо же куда-то свалить все эти структуры? В каком смысле сваливать? Создаёшь новый узел Expression (через new), цепляешь его к представлению. Т.е. в Statement'е будет торчать ссылка на созданный узел Expression. А из него будут торчать ссылки на другие Expression'ы и Variable'ы. Или я вопрос как-то не так понял Добавлено через 7 минут 58 секунд Не забудь на данную ошибку тест написать, чтобы в будущем не проявилось Добавлено через 4 часа 50 минут 57 секунд У меня всё-таки $опа зачесалась и я накатал-таки упрощённый вариант интерпретатора с промежуточным представлением. Если интересно будет - можешь попробовать посмотреть
1
|
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
|
|
20.08.2009, 16:24 [ТС] | 98 |
Да вроде,у меня неправильно до этого было,я и раньше замечал,но,видимо не заметил ошибку.Дело было по ходу как раз в в том что в цикле я вызывал syntax_parserTerm,а надо было Primary.
Я имел ввиду что структуры данных Expression,Statement надо же где-то пристроить,так пусть лучше будут в отдельном файле.И потом уже при исполнении уже другая единица (по-моему этим уже не должен заниматься парсер синтаксиса)эти данные тоже будет подключать. Интересно,конечно,прикрепи поглядеть.Я,конечно,растянул написание своей программы неимоверно долго,всё это можно было написать намного быстрее,я полагаю...
0
|
20.08.2009, 16:57 | 99 | |||||
Интерпретатор - это всё-таки сложная программа. То, что ты растянул во времени - это не страшно. Объём большой, а в голове, не имея соотвествующего опыта, уложить всё сразу сложно. Главное - всё-таки дописать его до такого состояния, когда реально будет видно, что дальнейшее наращивание языка - это тупое добавление кода, а вся структура уже будет в устаканенном состоянии. Исходники выложу чуть позже (комментарии допишу)
Оговорю сразу несколько моментов, которые у меня пока не сделаны:
Если какие-то косяки найдёшь - говори. Если будет время - попробую впараллель с тобой писать. Так проще будет твои проблемы понимать. Чтобы было перед глазами - кладу исходник и отладочную печатьпромежуточного представления (думаю, без комментариев будет понятно)
Код
s1. LET A1 = i:10 s2. LET A2 = i:100 s3. LET B1 = ((A1 + (i:5 * A2)) - i:50) s4. PRINT B1 s8. CBRANCH B1 -> t=s5 f=s6 s5. LABEL #then s9. LET C = i:1 s10. LET D = i:2 s11. BRANCH -> s7 s6. LABEL #else s12. LET C = i:10 s13. LET D = i:20 s7. LABEL #finish s14. PRINT C s15. PRINT D s19. CBRANCH (B1 - i:460) -> t=s16 f=s17 s16. LABEL #then s20. LET C = i:1 s21. LET D = i:2 s22. BRANCH -> s18 s17. LABEL #else s23. LET C = i:10 s24. LET D = i:20 s18. LABEL #finish s25. PRINT C s26. PRINT D s27. LET COUNT = i:0 s28. LET SUM = i:0 s29. LABEL #start s32. CBRANCH (COUNT - i:100) -> t=s30 f=s31 s30. LABEL #loop s33. LET COUNT = (COUNT + i:1) s34. LET SUM = (SUM + COUNT) s35. BRANCH -> s29 s31. LABEL #finish s36. PRINT COUNT s37. PRINT SUM Код
460 1 2 10 20 100 5050 Вот исходники. interp.rar - в KOI-8, interp_w.rar - в WIN1251 (с виндовыми энтерами) Трассировочные макросы: lex.c - LEX_TRACE_TOKEN statement.c - STMT_TRACE interp.c - INTERP_TRACE Надеюсь, что после этого ты начнёшь понимать, что из себя представляет промежуточное представление и как с нима работают. А так же посмотри на сопосб, когда в лексическом и синтаксическом разборе работа построена так, что всегда подкачиваем на одну единицу вперёд (на один символ для лексическогоразбора, на один токен - для синтаксического) Добавлено через 1 минуту 25 секунд В печати промежуточного представления надо смотреть именнопорядок, в котором всё печатается. То, что номера печатаются не по порядку - это фича, связанная с механизмом создания меток для переходов вперёд
1
|
20.08.2009, 16:58 | 100 |
Фалй забыл приаттачить
1
|
20.08.2009, 16:58 | |
20.08.2009, 16:58 | |
Помогаю со студенческими работами здесь
100
Пишем свой класс, спецификатор доступа protected Интерпретатор небольшого языка программирования на С++ Не удается откомпилировать интерпретатор М-языка Интерпретатор музыки стандарта BASIC PLAY на С++ Написать интерпретатор программного языка -помощь Интерпретатор/компилятор ассемблер-подобного языка Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |