?login_element?

Subversion Repositories NedoOS

Rev

Rev 637 | Details | Compare with Previous | Last modification | View Log

Rev Author Line No. Line
230 alone 1
        Введение
8 dimkam 2
 
230 alone 3
Язык NedoLang - подмножество языка Си со строгой типизацией. Программа на NedoLang, оформленная по рекомендациям совместимости, может компилироваться компилятором Си при подключении файла nedodefs.h.
8 dimkam 4
 
230 alone 5
Пакет NedoLang позволяет разрабатывать загружаемые программы (todo и ПЗУ) для Z80 и ARM Thumb без привлечения внешних утилит и библиотек, не считая эмуляторов/отладчиков. Кроме того, поскольку компилятор может компилировать сам себя, то можно работать непосредственно на Z80 (todo и на ARM Thumb).
8 dimkam 6
 
230 alone 7
        Как начать работу
8 dimkam 8
 
230 alone 9
# Создайте в каталоге nedolang каталог своего проекта. Перейдите в этот каталог.
8 dimkam 10
 
230 alone 11
# Создайте исходник главного модуля main.c. В нём напишите:
8 dimkam 12
PROC main()
13
{
14
}
15
 
230 alone 16
# Создайте файл стартапа main.s. В нём напишите:
17
        org 0x6000 ;адрес размещения программы для Z80 (для ARM см. инструкцию к вашему процессору)
18
        jp main ;переход на процедуру main()
19
        include "main.ast" ;код главного модуля
20
        include "main.var" ;переменные главного модуля
21
        include "../_sdk/lib.i" ;стандартная библиотека
8 dimkam 22
 
230 alone 23
# Создайте скрипт компиляции compile.bat. В нём напишите (для Z80 - для ARM используется nedolarm, nedotarm, nedoaarm и нет стандартной библиотеки lib.i):
8 dimkam 24
@echo off
25
path=..\_sdk\
26
 
27
echo ...compiling...
28
nedolang main.c
29
type err.f
30
 
31
echo ...tokenizing...
20 dimkam 32
nedotok main.s main.ast main.var ../_sdk/lib.i
8 dimkam 33
 
34
echo ...assembling...
35
nedoasm main.S_
36
type asmerr.f
37
 
38
pause
39
 
230 alone 40
Уже можно проверять, что ваша программа компилируется - запускайте compile.bat и смотрите ошибки. Сейчас ошибок нет, показывается только lbls ... buf ... - количество меток и размер буфера под них. Ваша программа скомпилирована в main.bin.
8 dimkam 41
 
230 alone 42
# Подключите необходимые библиотеки, например:
43
В начале main.c:
8 dimkam 44
#include "../_sdk/print.h"
230 alone 45
В конце main.s:
46
        include "../_sdk/print.i" ;код библиотеки print
47
В compile.bat исправьте строчку:
20 dimkam 48
nedotok main.s main.ast main.var ../_sdk/lib.i ../_sdk/print.i
8 dimkam 49
 
230 alone 50
Можно проверить, что программа компилируется с библиотеками.
8 dimkam 51
 
230 alone 52
# Добавьте код в main():
8 dimkam 53
  setxy(0x00,0x00);
54
  nprintf("Hello world!\n");
55
 
230 alone 56
# Добавьте скрипт запуска run.bat (для Z80):
8 dimkam 57
call compile.bat
58
nedotrd test.trd -n
59
nedotrd test.trd -s 24576 -ac main.bin
60
..\..\emul\emul.exe test.trd
61
 
230 alone 62
Предполагается, что эмулятор emul.exe лежит в каталоге ..\..\emul\ (т.е. в соседнем с каталогом nedolang).
8 dimkam 63
 
230 alone 64
Теперь у вас на диске test.trd есть запускаемый кодовый файл main.C с адресом 24576 и открывается эмулятор.
8 dimkam 65
 
230 alone 66
# В ..\batch\basics.trd есть бейсик-загрузчик boot, который загружает и запускает main.C с адресом 24576. Добавьте в свой run.bat перед запуском эмулятора:
8 dimkam 67
nedotrd ..\batch\basics.trd -eh boot.$b
68
nedotrd test.trd -ah boot.$b
69
 
230 alone 70
Теперь можно запускать программу простым нажатием Enter в эмуляторе (можно даже настроить автозапуск).
8 dimkam 71
 
230 alone 72
# Можете удалить временные файлы (*.ast, *.var, *.org, *.pst, ошибки и токенизированные ассемблерные тексты) утилитой clean.bat в корневом каталоге nedolang.
8 dimkam 73
 
230 alone 74
Если когда-нибудь понадобится подключить самодельный ассемблерный файл, назначьте ему расширение *.s, чтобы утилита clean.bat его не удалила.
8 dimkam 75
 
230 alone 76
        Описание языка
8 dimkam 77
 
230 alone 78
Язык в текущей версии не обеспечивает аналогов следующих конструкций Си:
79
- многомерные массивы (можно взамен использовать вычисления индекса или массивы указателей);
80
- числа с плавающей точкой (todo!);
81
- sizeof(<expr>) - есть только +sizeof(<type>), +sizeof(<var>) не для массивов;
82
- sizeof нельзя использовать в константах;
83
- #include <filename> (есть только #include "filename");
84
- макросы #define (нерекомендуемое поведение, есть только константы #define);
85
- for (следует взамен использовать while или repeat);
86
- статические структуры и массивы структур (сейчас доступ к структурам только по указателю);
87
- вложенные структуры (todo!);
88
- объединения (нерекомендуемое поведение);
89
- копирование константных строк через =;
90
- выход из середины функции по return (нерекомендуемое поведение);
91
- выход из середины программы по exit (нерекомендуемое поведение);
92
- вызов функции по указателю с параметром и возвращаемым значением (сейчас можно вызывать по указателю только процедуры без параметров);
93
- тип указателя на указатель (можно обойти, т.к. тип указателя указывается при разыменовании - *(<poitype>)poi; poke *(<poitype>)(<poiexpr>) = <expr>).
8 dimkam 94
 
230 alone 95
Команды собираются в блоки, окружённые фигурными скобками {<command><command>...<command>}.
96
Такой блок эквивалентен одиночной команде и допустим везде, где допустима одиночная команда.
97
После каждой команды для совместимости с Си рекомендуется (но не требуется) ставить точку с запятой.
8 dimkam 98
 
230 alone 99
В одной строке может быть сколько угодно команд. Перевод строки между любыми словами ни на что не влияет.
100
Номера строк в исходном тексте не пишутся. Поэтому при ошибках выводится номер строки исходного текстового файла (первая строка имеет номер 1).
8 dimkam 101
 
230 alone 102
Стандартные комментарии оформляются как /**комментарий*/. Если впереди только одна звёздочка, то это не комментарий.
103
Стандартные комментарии не могут быть вложенными.
104
Есть также стандартные однострочные комментарии от // до конца строки.
105
Нестандартные однострочные комментарии: от ;; до конца строки.
106
Также игнорируются строки, которые начинаются с #, кроме реализованных команд с # (см. ниже).
107
Комментарии можно ставить между любыми словами, кроме следующих случаев:
108
- после первого слова команды (даже для команд, определяемых по формату, даже между меткой и двоеточием и между <varname> и знаком '=');
109
- внутри размера массива при его объявлении, то есть так нельзя: var int a[100/**комментарий*/];
110
- между именем переменной и квадратной скобкой индекса массива, то есть так нельзя: a/**комментарий*/[10].
111
- между именем типа и *.
112
Все комментарии при компиляции передаются в ассемблерный текст тоже в виде комментариев (если задана соответствующая опция компилятора, см. ниже).
8 dimkam 113
 
230 alone 114
Полное имя переменной (которое используется в ассемблере) строится из имени текущей области видимости (в текущей версии пустое), имени самой переменной и постфикса.
115
Полное имя "__sys._petyamodule._pet" означает: область видимости "__sys._petyamodule", переменная "_pet", заданная в исходном тексте (нет точки в конце).
116
Полное имя "__globalarr" означает: глобальная переменная "__globalarr", заданная в исходном тексте (нет точки в конце).
117
Полное имя "__sys.mainproc.A." означает: область видимости "__sys.mainproc", переменная "A.", созданная автоматически (отмечено точкой ".").
118
Таким образом, автоматически созданные переменные не пересекаются по именам с переменными, заданными в исходном тексте.
119
Так же строятся полные имена заголовков функций (без точки в конце) и меток для перехода (пользовательские без точки, автоматические с точкой в конце).
8 dimkam 120
 
230 alone 121
Переменные и прочие имена доступны из языка следующим образом:
122
i для доступа к переменной i, определённой в текущей области видимости (то есть в текущей функции) или к глобальной переменной.
123
func2() для доступа к функции func2(), определённой снаружи текущей области видимости (то есть в текущем модуле).
124
//_submodule._v для доступа к переменной _v, определённой в дочерней области видимости _submodule.
125
//Не имеет смысла называть модули без подчёркивания - они будут недоступны из внешнего модуля.
126
//_submodule.proc2() для доступа к процедуре proc2(), определённой в дочерней области видимости _submodule.
127
//__sys._anothermodule.func5() для доступа к функции func5(), определённой в модуле _anothermodule, включенном в глобальный модуль __sys.
8 dimkam 128
 
230 alone 129
Автоматически созданные переменные недоступны из языка.
8 dimkam 130
 
230 alone 131
Идентификаторы (имена переменных, процедур, функций, меток) должны начинаться с буквы (или знака подчёркивания для глобальных переменных и глобальных процедур/функций) и состоять из букв, цифр и знаков подчёркивания. Полное имя переменной не должно быть длиннее 79 знаков. Разрешается использовать русские буквы в идентификаторах. Русские буквы остаются в том же виде, как они закодированы в исходном тексте (в кодировке cp866, cp1251 или utf8).
8 dimkam 132
 
230 alone 133
Имеются следующие типы данных:
637 alone 134
* BYTE (имеет размер 1 байт, без знака)
135
* BOOL (допустимы только значения +TRUE и +FALSE, размер не регламентируется)
136
* CHAR (имеет размер 1 байт, знаковость не регламентируется)
137
* INT (знаковое целое, имеет размер в одно слово процессора)
138
* UINT (беззнаковое целое, имеет размер в одно слово процессора)
139
* LONG (беззнаковое длинное целое, имеет размер в два слова процессора)
140
[* FLOAT (пока клон LONG, кроме таргета Script - там работает как double)]
141
* PBYTE,PBOOL,PCHAR,PINT,PUINT,PLONG,[PFLOAT], <typename>* (указатель - имеет размер в одно слово процессора)
142
* STRUCT <structname> (структура <structname> - только для константных структур и +sizeof(STRUCT <structname>))
143
* STRUCT <structname>* (указатель на структуру <structname>)
8 dimkam 144
 
637 alone 145
Тип BOOL в текущей версии имеет размер 1 байт, логические значения следует писать +TRUE и +FALSE (в текущей реализации равны 0xff и 0x00, но не рекомендуется смешивать логические значения с числовыми).
230 alone 146
Любое значение, отличное от FALSE, воспринимается как TRUE, но не рекомендуется использовать этот факт для будущей совместимости.
8 dimkam 147
 
230 alone 148
Узнать размер типа, переменной простого типа или структуры в байтах можно с помощью +sizeof(<type>). Выражение +sizeof(<type>*) выдаёт размер указателя.
8 dimkam 149
 
637 alone 150
Разрешается использовать необъявленные константы в форме +<variable>, если имя начинается со знака подчёркивания '_'. В этом случае константа получает тип BYTE (иначе BOOL). Рекомендуется использовать такую запись только для констант из enum.
8 dimkam 151
 
230 alone 152
В выражениях строго проверяются типы. В любой операции с двумя операндами типы операндов должны совпадать.
8 dimkam 153
 
230 alone 154
Приведение типов выглядит так:
8 dimkam 155
(<type>)<value>
156
 
230 alone 157
Поскольку наш язык не допускает разные типы в одном операторе, то для смещения указателя на N байт вперёд используется выражение:
8 dimkam 158
(<type>)((UINT)<pointername> + N)
230 alone 159
Или для PBYTE:
8 dimkam 160
&<pointername>[N]
230 alone 161
Для получения указателя на массив используется выражение:
8 dimkam 162
(PCHAR)<arrayname>
230 alone 163
При использовании вызова функции в качестве параметра надо ставить правильный тип указателя (указатель не равен массиву, в отличие от Си).
8 dimkam 164
 
230 alone 165
Чтение по указателю допускается только с непосредственным приведением типа: *(<pointertype>)<pointervalue>
8 dimkam 166
 
230 alone 167
Вызов функций оформляется как <procname>([<expression>,...]).
168
Процедуры и функции технически имеют плавающее число параметров, но не рекомендуется использовать это поведение.
8 dimkam 169
 
230 alone 170
В выражениях <expression> имеются следующие приоритеты операций:
171
1. Индексные квадратные скобки: arr[] или pointer[]
172
2. Префиксы (+, -, ~ (инверсия), ! (логическое отрицание), & (взятие адреса переменной &<variable>, процедуры/функции &<func>, элемента массива &<array>[<expression>], поля структуры &(<structname>-><field>)), * (чтение по указателю)).
173
3. Умножение, деление, &, &&.
174
4. Сложение, вычитание, |, ^, ||, -> (адресация элемента структуры по указателю).
637 alone 175
5. Сравнения и сдвиги (<<, >>). Сравнения и сдвиги работают только для типов BYTE, CHAR, INT, UINT. Сдвиги - также для LONG. Для BOOL разрешены только сравнения на равенство и неравенство. Сравнение на равенство можно писать == или =, но второй вариант несовместим с Си.
8 dimkam 176
 
230 alone 177
В выражениях допустимы следующие виды значений:
178
* идентификатор переменной - получает тип по типу переменной.
637 alone 179
* целая числовая константа без знака - получает тип BYTE (если запись в стиле 0xff с не более чем 2 цифрами или в стиле 0b111 с не более чем 8 цифрами), LONG (если в конце стоит L) или UINT (в остальных случаях).
180
* целая числовая константа со знаком (+ или -) - получает тип INT.
181
* числовая константа с плавающей точкой - получает тип FLOAT (который пока не поддерживается).
230 alone 182
* символьная константа 'c' или '\<символ>' (допустимы только '\n', '\r', '\t', '\0', '\'', '\"', '\\'), где <символ> - один символ - получает тип char.
637 alone 183
* строковая константа "строка" - получает тип PCHAR. Допускается запись строковых констант в виде "str1""str2" (между ними допустим перевод строки) для наглядности и для избегания переполнения буфера строки (79 символов) в компиляторе. Строковые константы создаются автоматически с нулевым кодом в конце.
184
* константное выражение +(expr) - получает тип по левому контексту.
8 dimkam 185
 
230 alone 186
Целые числовые константы могут быть десятичные (100), шестнадцатеричные (0x10), двоичные (0b11), восьмеричные (0o177 или как вариант 0177 с выдачей предупреждения из-за двусмысленности записи).
8 dimkam 187
 
230 alone 188
Команды, которые определяются по формату:
8 dimkam 189
 
230 alone 190
* <labelname><:> - определить метку для перехода. Метка должна быть уникальной внутри текущей области видимости. Подчёркивание добавлено, чтобы метку было лучше видно в тексте программы.
191
* <label>([<expression>,...]) - вызвать процедуру. Нельзя ставить пробел перед открывающей скобкой (ср. формат if).
192
* <var>=<expression> - вычислить и записать в переменную. Тип выражения должен соответствовать типу переменной. Получить в указатель адрес массива можно так: poi=(PBYTE)arr.
193
* <var><[><expression><]>=<expression> - вычислить и записать в ячейку массива. Таким же образом можно писать в массив, адрес которого передан как указатель. Будьте осторожны, границы массива не проверяются!
194
Доступ к ячейкам массива на чтение делается так же: <var><[><expression><]> (в том числе если адрес массива передан как указатель).
195
* <var>-><field>=<expression> - вычислить и записать в поле структуры (которая лежит по указателю <var>). Допускаются цепочки ->.
8 dimkam 196
 
230 alone 197
Команды, которые начинаются с ключевого слова:
8 dimkam 198
 
230 alone 199
* const - определить константу: const<type><variable>[=<constnum>], где <constnum>::=[-|+]<num>|'<char>'|"<string>"["<string>"...] или для массивов/структур: const<type><variable><[><expr><]>={<constnum>[,<constnum>...]}
200
Пропуск значения или списка значений нужен для использования внешних констант (не из текущего компилируемого модуля). Список значений для массива должен соответствовать числу значений в массиве (не проверяется).
201
Нельзя определять два раза одну и ту же константу со значением (TODO проверять в ассемблере). См. выше про необъявленные константы.
202
* extern - описать тип внешней переменной: extern<type><variable> - допускается только снаружи процедур и функций (не проверяется).
203
* var - определить переменную: var<type><variable>[=<expression>] - если с присваиванием, то допускается только внутри процедур или функций (не проверяется). Это именно присваивание, а не определение начального значения переменной. Нельзя присваивать массивы (не проверяется). В рекурсивных процедурах и функциях присваивание в var запрещено (не проверяется), а после блока всех var всё последующее тело функции должно быть в фигурных скобках {} (не проверяется), иначе переменные не будут правильно восстанавливаться при рекурсии.
204
* var с квадратными скобками - определить массив фиксированного размера: var<type><variable><[><expression><]> - ячейки массива нумеруются с 0, то есть в массиве a[10] не существует ячейки с индексом 10. Индекс должен иметь тип byte или uint.
476 alone 205
* enum - определить последовательный ряд констант: enum{<enumconstname>[=<number>],<enumconstname>[=<number>]...} - первая константа получит значение 0, вторая 1 и т.д., =<number> меняет этот счётчик. Эти константы невидимы как переменные, поэтому для использования их надо либо объявить через const, либо использовать +<enumconstname> (см. выше про необъявленные константы). Разрешена запятая после последнего элемента.
637 alone 206
* evar {UINT var1 = 1, INT var2 = 2, FLOAT var3} и т.п. создаёт переменные заданого типа с заданными адресами.
230 alone 207
* poke* - вычислить и записать в память с нужным типом: poke*<pointervalue>=<expression> - ключевое слово нужно, чтобы можно было пропускать ; в конце операторов.
208
[* module - определить модуль (область видимости): module<label><command> - команда <command> создаётся в области видимости внутри текущей области видимости (например, если была область видимости mainmodule, то внутри команды "module submodule{...}" будет область видимости mainmodule.submodule. Можно повторно определять одну и ту же область видимости, чтобы добавлять туда что-то новое.]
209
* proc - определить процедуру: proc<procname>[recursive][forward]([<type><par>,...])[<command>] - тоже создаёт область видимости внутри текущей области видимости. Поэтому <procname> должно быть уникальным внутри текущей области видимости. Если есть слово forward, то тело процедуры/функции не создаётся, и <command> не нужна (используется при использовании внешних процедур/функций или если их тело описано ниже вызова). Если есть слово recursive, то локальные переменные сохраняются при входе-выходе в процедуру/функцию, а при вызове сохраняются старые значения параметров. Внутри рекурсивной процедуры/функции нельзя объявлять массивы (не проверяется).
210
* func - определить функцию: func<type><funcname>[recursive][forward]([<type><par>,...])[<command>] - тоже создаёт область видимости внутри текущей области видимости. Поэтому <funccname> должно быть уникальным внутри текущей области видимости. См. выше про слова recursive и forward.
211
* if - альтернатива: if (<boolexpression>) <command>[else<command>]; - ';' против ошибки "if (expr); cmd" и против ошибки вложенных неполных альтернатив. Пробел после if обязателен (ср. формат вызова процедуры). При вложенных if достаточно одного ';'.
8 dimkam 212
*TODO ifnot
213
*TODO ifz
214
*TODO ifnz
230 alone 215
* while - цикл с предусловием: while (<boolexpression>) <command>[;] - ';' против ошибки "while(expr);cmd".
8 dimkam 216
*TODO whilenot
217
*TODO whilez
218
*TODO whilenz
230 alone 219
* repeat - цикл с постусловием: repeat<command>until (<boolexpression>) - если сделать скобки необязательными, то не получится определить "логическое выражение верхнего уровня", которое можно оставить во флаге.
8 dimkam 220
*TODO untilnot
221
*TODO untilz
222
*TODO untilnz
230 alone 223
* break - выйти из цикла while или repeat или из блока switch: параметров не имеет, просто break.
224
* return - вернуть значение из функции: return<expression> - должна быть последней командой в функции. Тип возвращаемого значения должен соответствовать типу функции.
225
* goto - перейти на метку: goto<labelname> - разрешается только внутри текущей процедуры или функции.
226
* call - вызвать процедуру по указателю: call (<expression>) - тип выражения - любой указатель или UINT (это не проверяется).
227
* asm - ассемблерная вставка: asm(" cmd1"" cmd2""label1"...) - каждая команда генерируется как отдельная строка. Нельзя писать команды без пробелов или табуляций вначале - токенизатор и ассемблер их не поймут.
228
* inc - увеличить значение переменной на единицу: inc <var>
229
* dec - уменьшить значение переменной на единицу: dec <var>
230
* struct - объявить структуру: struct<structname>{<type1><field1>[;]<type2><field2>[;]...} - допускается использование в структуре указателей на структуры, объявленные выше, и на саму себя (для совместимости с Си надо в объявлении структуры поля, являющиеся указателями на структуры, предварять словом struct). Потом можно объявить указатель на структуру: var struct <structname>* <structpointername> - и использовать поля структуры: <structpointername>-><field>
231
* switch - блок множественного ветвления по значению типа byte:
8 dimkam 232
switch (<byteexpr>){
233
case <byteconst>: [<commands>]
234
case <byteconst>: [<commands>]
235
...
236
default: [<commands>]
237
};
230 alone 238
Разрешается только один switch в процедуре/функции. Все названия веток <byteconst> должны быть описаны в const или enum. Поля "case <byteconst>:" и "default:" (ветка по умолчанию) эквивалентны меткам (label), поэтому они могут стоять в произвольных местах, а автоматический выход из веток не предусмотрен. Для этого можно использовать goto или break (break здесь выходит из switch).
239
* #include "filename" - вложенно включить текст из другого файла. Используется для подключения внешних определений (дублирования на данный момент запрещены).
240
* #define <constname> <value> или #define <costname> (<type>)(<expr>) - определить константу совместимо с Си. В отличие от const, можно преопределять. Требуется для констант в заголовочных файлах и констант размера массивов, можно и для других случаев.
241
# #undef <constname> - удалить ранее определённую константу (или любой другой идентификатор, но это будет несовместимо с Си).
476 alone 242
* условная компиляция (разрешается вложенная): #ifdef <defined_const> ... [#else] ... #endif или #ifndef <defined_const> ... [#else] ... #endif.
230 alone 243
* export - ставится перед определением (процедуры/функции, переменной, константного массива/структуры), смещение адреса которого нужно экспортировать в файл filename.D_.
244
* typedef <type> <typename> - определить новый тип на основе старого. Для структурных типов надо писать слева слово struct для совместимости с Си.
8 dimkam 245
 
230 alone 246
Все команды с # должны начинаться с начала строки и занимать всю строку.
8 dimkam 247
 
230 alone 248
В условиях (if, while, until) имеется оптимизация сравнений за счёт проверки, что они осуществляются на 1-м уровне вложенности выражения (скобки не учитываются - они являются частью синтаксиса команды). Поэтому на этом же уровне нельзя писать другие операции (например, нельзя a==b==c, можно (a==b)==c). Это не проверяется?
249
В вычислениях (присваивание, var, return, параметры вызовов) сравнения можно писать только в скобках, чтобы они не оказались на 1-м уровне вложенности (например, нельзя a = b==c, можно a = (b==c)).
8 dimkam 250
 
230 alone 251
Рекомендуемый стиль оформления условий:
637 alone 252
IF (cond1) do1();
253
IF (cond2) {
8 dimkam 254
  do2();
637 alone 255
}ELSE IF (cond3) {
8 dimkam 256
  if (cond4) {do3();
637 alone 257
  }ELSE do4();
8 dimkam 258
};
637 alone 259
IF (cond5) {
8 dimkam 260
  do5();
637 alone 261
}ELSE IF (cond6) {
8 dimkam 262
  do6();
637 alone 263
}ELSE {
8 dimkam 264
  do7();
265
};
266
 
230 alone 267
Рекомендуется все ключевые слова языка писать большими буквами, а в текущей версии - типы и STRUCT обязательно большими буквами.
268
Чтобы скомпилировать такой же исходник с помощью компилятора Си, нужно использовать #include "nedodefs.h".
8 dimkam 269
 
230 alone 270
Такой синтаксис - один из вариантов, получившихся из следующих требований:
271
- при анализе команд использовать только левый контекст;
272
- любая команда определяется без поиска по меткам (зарезервированных слов нет);
273
- при этом должна обеспечиваться совместимость с компилятором Си.
8 dimkam 274
 
230 alone 275
        Структура проекта
8 dimkam 276
 
230 alone 277
Проект состоит из модулей на NedoLang (могут включать другие модули через #include) и на ассемблере (могут включать другие ассемблерные модули через include). Модули по одному передаются в компилятор (кроме включаемых через #include), потом все ассемблерные файлы надо токенизировать, потом надо вызвать NedoAsm с именем стартап-файла *.s.
8 dimkam 278
 
230 alone 279
Стартап-файл - ассемблерный файл с запускающим кодом, должен включать (через include "filename.ast") остальные файлы проекта. В реальности вместо filename.ast будет грузиться filename.A_ и т.п.
8 dimkam 280
 
230 alone 281
nedolang.exe - компилятор, имеет следующие параметры:
282
filename1.c filename2.c ... - компилировать перечисленные модули по одному.
283
-C - включить выдачу комментариев (для компиляции).
284
-H - включить выдачу подробного лога (для компиляции).
285
Выходные файлы компилятора:
286
*.ast - ассемблерный текст с кодом
287
*.var - ассемблерный текст с данными
288
err.f - ошибки компиляции
289
[label.f - метки во внутреннем формате]
8 dimkam 290
 
230 alone 291
nedotok.exe - токенизатор, вызывается так:
20 dimkam 292
nedotok filename1.ast filename2.var filename3.s filename4.i ...
230 alone 293
(выходные файлы будут называться filename1.A_, filename2.V_ и т.п.).
8 dimkam 294
 
230 alone 295
nedoasm.exe - ассемблер, вызывается так:
8 dimkam 296
nedoasm filename.A_
230 alone 297
Выходные файлы ассемблера:
298
filename.bin - все сгенерированные байты кода и данных подряд
299
filename.org - данные релокации (в формате: 2 байта смещение, где лежит релоцируемый адрес)
300
[label0.f..label7.f - метки во внутреннем формате]
301
filename.pst - пост-метки во внутреннем формате (пока не поддерживается)
302
asmerr.f - ошибки ассемблирования
303
filename.D_ - токенизированный файл деклараций (команды export label в ассемблере)
304
Ассемблер выгружает код подряд, поэтому допустим только один ORG - начальный. Выравнивать данные можно через DS -$&mask.
8 dimkam 305
 
230 alone 306
nedoexp.exe - детокенизатор (отладочный экспорт токенизированного ассемблера), вызывается так:
8 dimkam 307
nedoexp filename.A_
230 alone 308
(выходной файл exp.f)
8 dimkam 309
 
230 alone 310
        Библиотеки:
8 dimkam 311
 
230 alone 312
- Ассемблерный файл lib.i содержит стандартные математические функции (умножение, деление, сдвиги) для Z80.
313
- Заголовочный файл str.h содержит функции работы со строками. Для его использования подключайте в стартапе под Z80 str.i (или же вместо него str.c компилируйте в str.ast, str.var и подключайте их в стартапе).
314
- Заголовочный файл io.h одержит функции работы с файлами. Для его использования подключайте в стартапе под Z80 iofast.i под TR-DOS или io_os.i под NedoOS (или же вместо него io.c под TR-DOS без функций низкого уровня компилируйте в io.ast, io.var и подключайте их в стартапе).
315
- runtime.h, runtime.i - необязательная рантайм-библиотека для Z80 (прерывания, порты).
316
- sprite.h, sprite.i - спрайтовая библиотека для Z80.
317
- print.h, print.i (print_os.i для NedoOS) - библиотека вывода текста для Z80 (setxy, prchar, nprintf).
8 dimkam 318
 
230 alone 319
        Утилиты для Windows:
8 dimkam 320
 
230 alone 321
- nedotrd - работа с образом диска в формате TRD. Можно перевести на NedoLang, если в файловой библиотеке поддержать ftell(pos)/fseek.
322
- nedores - конвертор графических ресурсов. Пока затруднительно перевести на NedoLang из-за размера массива.
323
- nedopad - обрезка или дополнение файла до заданного размера. Можно перевести на NedoLang.
324
- _gui - простейший интерфейс ввода и компиляции исходника на NedoLang (можно с автоматической перекомпиляцией в процессе ввода) с просмотром ошибок и результата в ассемблерном виде.
8 dimkam 325
 
230 alone 326
Утилиты на NedoLang:
327
- nedodefb - перевод файла в ассемблерное шестнадцатеричное представление с обрезкой или дополнением (пока только для Z80). Можно перевести на NedoLang. Необязательно при использовании предыдущей утилиты.
328
- nedodiff - сравнение двух файлов (пока только для Z80, т.к. использует print.i).
329
- batch - интерпретатор командных файлов (пока только для Z80, лежит по адресу 64000).
330
- nedodel - удаление файла.
331
- movedisk - уплотнение образа диска после удаления файлов.
637 alone 332
- diff - сравнение двух файлов.
8 dimkam 333
 
230 alone 334
При указании путей в #include, include и в командной строке надо использовать прямую косую черту '/'.
335
Результат компиляции кладётся в ту же директорию, где лежит исходный файл.
8 dimkam 336
 
230 alone 337
Формат ассемблерного текста зависит от архитектуры целевого процессора.
8 dimkam 338
 
230 alone 339
Поддерживаются директивы:
340
- db <byte>,<byte>... (dcb для ARM Thumb) - скомпилировать байты
341
- dw <word>,<word>... (dcd для ARM Thumb) - скомпилировать слова
342
- dl <long>,<long>... (dcq для ARM Thumb) - скомпилировать двойные слова
343
- ds <size>[,<byte>] (space для ARM Thumb) - скомпилировать пустой блок заданного размера, можно 0
344
- org <addr> - указать адрес размещения программы, с которого она будет работать
345
- align <2^n> (для ARM Thumb) - пропустить байты для выравнивания адреса размещения на адрес, кратный параметру (того же можно добиться с помощью ds -$&<2^n-1>
346
- end (для ARM Thumb - ничего не делает)
347
- include "filename.ast" - подключить исходник с заданным именем. Фактически подключается токенизированный filename.A_. Разрешается вложенность
348
- incbin "filename" - подключить бинарный файл
349
- <label>=<expression> - присвоить метку (можно переприсвоить)
350
- <label> equ <expression> - присвоить метку (можно переприсвоить - todo запретить)
351
- export <label> - выгрузить значение метки в файл filename.D_ (токенизированный) в виде <label>=_+<labelvalue>. Этот файл можно включать в ассемблерный текст через include "filename.dcl".
8 dimkam 352
- todo disp
353
- todo ent
354
 
230 alone 355
Текущий адрес компиляции можно получить с помощью знака $.
8 dimkam 356
 
230 alone 357
Определяемая метка должна стоять в начале строки.
8 dimkam 358
 
230 alone 359
Разрешается писать несколько команд в строке через пробел (через двоеточие пока не работает).
8 dimkam 360
 
230 alone 361
Ассемблер двухпроходный. Кодогенерация происходит на втором проходе. На момент генерации каждой строчки уже должны быть вычислены все используемые метки, иначе выводится ошибка.
8 dimkam 362
 
230 alone 363
dw $,$ работает как dw $ dw $