forked from jamesots/maz
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathNOTES
140 lines (106 loc) · 4.08 KB
/
NOTES
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
Libraries/intermediate files can be JSON
Can read settings from a local file, a system wide file or a file specified on the command line
Have option to change JR to JP if out of range
Make sure error messages are actually useful
Compile all the file into a list of compiled objects.
Create a map of symbols
Calculate symbol values
Throw error if symbol values can't be caluclated (circular refs, etc)
Below, 'more' cannot be calculated.
start:
jp more
ds more-start
more:
ret
Are there any other instructions or directives which change the size of the data? Maybe only a ds directive needs to disallow forward references — so calculate its size as we go. Although a later 'equ' would be valid:
start:
jp more
ds size
more:
ret
size: equ 100
----------------------
How compilation works
1. parse
2. getMacros
3. expandMacros
4. getSymbols
5. assignPCandEQU
6. evaluateSymbols
7. updateBytes
1. parse
This uses the pegjs grammar to produce an abstract syntax tree.
(It's not a tree).
There are several types of objects which are created, which can
be detected by seeing if each of the following attributes is
truthy on the object:
* label
The value of 'label' is the name of the label
* block
The start of a block. No other attributes to start with.
Later, prefix is added.
* endblock
The endof a block. No other attributes to start with.
Later, prefix is added. (Is it needed?)
* macrodef
The value of 'macrodef' is the name of the macro.
Also has args, which is an array of strings.
* endmacro
The end of a macro definition. Is also added later to mark
the end of an expanded macro.
* macrocall
The value of 'macrocall' is the name of the macro to call.
Has params, which is an array of parameter values, which
may be number, strings, or expressions.
* equ
The value of 'equ' is a number or an expression. The value
is assigned to all immediately preceding labels (later).
* bytes (an instruction)
A Z80 instruction has a bytes array, which contains the
bytes to store in memory. If there are expressions to evaluate,
they are in place of a byte. If it's an 8 bit value it takes
up a single space, if it's a 16 bit value it is followed by
a null. e.g. [1, 2, {expression: 'a + b'}, null]
2. getMacros
Macros are found in the ast and a map from macro name to the
ast for the macro is returned.
3. expandMacros
Wherever a macrocall element is found, the expanded attribute is
added to it, and the macro's ast content is inserted after the
macrocall. The endmacro element is added after this.
4. getSymbols
This gets a map of symbols, and updates the ast so that
block, endblock, macrodef and endmacro elements have prefix
attributes, and updates label names to have appropriate prefixes.
If a label is inside a block or macro then it is assigned a prefix. The
first block gets the prefix '%0_', so a variable in that block
might be '%0_one'. If there is a nested block, it gets the prefix
'%1_%0_'. The block numbers keep increasing, so another subsequent
nested block at the same level might be '%2_%0_', and a later
top level block would then be '%3_'. This is so that block scoped
variables will have unique names.
The parameters to a macro are added a symbols with the macro's prefix,
and their values are also initialized.
EXPRESSIONS
This might all be lies:
can always use a char instead of a number, and get its ascii value
zmac gets an error on overflow - if trying to use value in wrong place (i.e. 16 bit in 8 bit space)
! string:error; number:0 -> 1, all other values -> 0; char:convert to number first???
~ string:error, or invert all bytes? number:invert char:convert to number first
+ string:error, or parse as number? number:leave as is char:convert to number
- string:error number:negate char:convert to number first
* string/string:error; string/number: repeat string; number/number: multiply
/ string/string:error; string/number: error; number/number: divide
% string/string:error; string/number: error; number/number: modulus
+ string/string:concat; string/number:
-
<<
>>
< > <= >=
== = != <>
&
^
|
&&
||
?: