|
4 | 4 |
|
5 | 5 | /* addlabel() adds a label to the collection of labels, to be used by other functions when a label reference is made. */ |
6 | 6 | /* Additionally, if there are outstanding "queries" for a certain label (if the label has been used before it has been declared) it replaces the "unknown address" address in an instruction with the address of the label on declaration */ |
7 | | -void addlabel(char *outbuf, label **labels, label **unknownlabels, unsigned long long *numlabels, unsigned long long numunknownlabels, char *labelstr, unsigned long long bits, unsigned short int baseaddr) |
| 7 | +void addlabel(char *outbuf, label **labels, label **unknownlabels, unsigned long long *numlabels, unsigned long long *numunknownlabels, char *labelstr, unsigned long long bits, unsigned short int baseaddr) |
8 | 8 | { |
9 | 9 | /* This is the pointer to the label string, which is used for comparison and assigned to it's element in the collection when we are finished. */ |
10 | 10 | char *tempstr = NULL; |
@@ -102,19 +102,34 @@ void addlabel(char *outbuf, label **labels, label **unknownlabels, unsigned long |
102 | 102 | if((*unknownlabels) != NULL) |
103 | 103 | { |
104 | 104 | /* Check every unknown label. */ |
105 | | - for(i = 0; i < numunknownlabels; i++) |
| 105 | + for(i = 0; i < (*numunknownlabels); i++) |
106 | 106 | { |
107 | 107 | /* If the unknown label name exits (otherwise it would be hard to identify it)... */ |
108 | 108 | if((*unknownlabels)[i].str != NULL && strcmp((*unknownlabels)[i].str, "")) |
109 | 109 | { |
110 | 110 | /* Check if the name of the unknown label is the same as the label that we just had declared. */ |
111 | 111 | if(!strcmp((*unknownlabels)[i].str, tempstr)) |
112 | 112 | { |
113 | | - /* If it is, then take stock of both the address it was referenced. If a label is referencing a label, we need to move 1 nibble back (as there is no instruction, just 4 nibbles). Cheaper than doing an if below. */ |
114 | | - unsigned short int instaddress = (*unknownlabels)[i].addr - (*unknownlabels)[i].type; |
115 | | - /* And the address the label points to plus the requested offset. We need to add one nibble if it is an instruction referencing a nibble as we moved one back above. */ |
116 | | - unsigned short int labeladdr = (*labels)[(*numlabels) - 1].addr + (*unknownlabels)[i].offset + (*unknownlabels)[i].type; |
117 | 113 |
|
| 114 | + /* If it is, then take stock of both the address it was referenced. If a label is referencing a label, we need to move 1 nibble back (as there is no instruction, just 4 nibbles). Cheaper than doing an if below. */ |
| 115 | + unsigned short int instaddress = (*unknownlabels)[i].addr - ((*unknownlabels)[i].type & 1); |
| 116 | + /* And the address the label points to plus the requested offset. We need to add one nibble if it is an instruction referencing a nibble as we moved one back above. */ |
| 117 | + unsigned short int labeladdr = (*labels)[(*numlabels) - 1].addr + (*unknownlabels)[i].offset + ((*unknownlabels)[i].type & 1); |
| 118 | + /* If we are doing an address of operation... */ |
| 119 | + if(((*unknownlabels)[i].type & 2)) |
| 120 | + { |
| 121 | + /* If N_START is not defined, we don't know how to load just a number. Wait until we do by storing a label to be found later... */ |
| 122 | + if(N_START == 0xFFFF) |
| 123 | + { |
| 124 | + char *nstr = calloc(1, 6); |
| 125 | + sprintf(nstr, "N_[%X]", ((labeladdr >> (3 - (*unknownlabels)[i].addroffset) & 0xF))); |
| 126 | + labeladdr = findlabel(unknownlabels, labels, nstr, (*numlabels), numunknownlabels, bits, ((*unknownlabels)[i].type) & 1); |
| 127 | + } |
| 128 | + else |
| 129 | + { |
| 130 | + labeladdr = ((labeladdr >> (3 - (*unknownlabels)[i].addroffset) & 0xF)) + N_START; |
| 131 | + } |
| 132 | + } |
118 | 133 | /* The address it was referenced at is actually the opcode of the instruction, so go up one nibble to point to the address section. */ |
119 | 134 | instaddress++; |
120 | 135 | /* Since the instaddress is actually what nibble is being addressed, we correctly address a byte every 2 nibbles. */ |
@@ -166,7 +181,8 @@ unsigned short int findlabel(label **unknownlabels, label **labels, char *labels |
166 | 181 | /* tempaddress is what is assigned to the return value of strtol. We use this value if we find that the token after the assembly instruction is actually a number. */ |
167 | 182 | unsigned short int tempaddress = address; |
168 | 183 | /* offset stores the offset in nibbles from the specific label. */ |
169 | | - unsigned short int offset = 0; |
| 184 | + unsigned short int offset = 0; |
| 185 | + unsigned short int addroffset = 0; |
170 | 186 |
|
171 | 187 | if(type > 1) |
172 | 188 | { |
@@ -198,9 +214,76 @@ unsigned short int findlabel(label **unknownlabels, label **labels, char *labels |
198 | 214 | break; |
199 | 215 | } |
200 | 216 | tempstr[i] = labelstr[i]; |
201 | | - } |
202 | | - |
| 217 | + } |
203 | 218 | tempstr[i] = '\0'; |
| 219 | + |
| 220 | + /* Check to see if this is an address of operation */ |
| 221 | + if(tempstr[0] == '&') |
| 222 | + { |
| 223 | + /* The formatting for this operation is very specific and we can find failures in multiple levels of parsing */ |
| 224 | + /* Have one value we set */ |
| 225 | + unsigned char formatcorrect = 0; |
| 226 | + |
| 227 | + /* The second character must be a ( */ |
| 228 | + if(tempstr[1] == '(') |
| 229 | + { |
| 230 | + /* Go until we find the ), which encompasses the label we are taking the address of */ |
| 231 | + for(i = 2; i < strlen(tempstr); i++) |
| 232 | + { |
| 233 | + if(tempstr[i] == ')') |
| 234 | + { |
| 235 | + /* If the ) is right beside the end of the string, it means that it is in the form &(LABEL). This is ok */ |
| 236 | + if(tempstr[i+1] == '\0') |
| 237 | + { |
| 238 | + formatcorrect = 1; |
| 239 | + } |
| 240 | + /* If the ) is right beside [, the string should be in the form &(LABEL)[ADDRESS_OFFSET] */ |
| 241 | + else if(tempstr[i+1] == '[') |
| 242 | + { |
| 243 | + /* Try to convert the offset */ |
| 244 | + addroffset = estrtol(tempstr + ((i + 2) * sizeof(char)), &endptr, NSTDHEX); |
| 245 | + /* If the value is valid (there is a convertable number)... */ |
| 246 | + if(tempstr != endptr) |
| 247 | + { |
| 248 | + /* And if the first invalid character was ] and then the string ends, this is correctly in the form &(LABEL)[ADDRESS_OFFSET] */ |
| 249 | + if(endptr[0] == ']' && endptr[1] == '\0') |
| 250 | + { |
| 251 | + /* However, the offset must be between 0 and 3 as addresses are 4 nibbles. */ |
| 252 | + if(addroffset > 3 || addroffset < 0) |
| 253 | + { |
| 254 | + fprintf(stderr, "Line %llu: The offset of an address of operation must be between 0 and 4.\n", FILELINE); |
| 255 | + exit(51); |
| 256 | + } |
| 257 | + formatcorrect = 1; |
| 258 | + } |
| 259 | + } |
| 260 | + } |
| 261 | + } |
| 262 | + if(formatcorrect) |
| 263 | + { |
| 264 | + /* Bitwise or ADDROF (which is 2) to the type. We can use this in addlabel to know if we are doing an address of operation. */ |
| 265 | + type |= ADDROF; |
| 266 | + /* Strip the address of parts from this string so we can use the rest of the function to correctly fill the string, address and offset parts of the unknownlabel structure. */ |
| 267 | + for(i = 2; i < strlen(tempstr); i++) |
| 268 | + { |
| 269 | + if(tempstr[i] == ')') |
| 270 | + { |
| 271 | + tempstr[i-2] = '\0'; |
| 272 | + break; |
| 273 | + } |
| 274 | + tempstr[i-2] = tempstr[i]; |
| 275 | + } |
| 276 | + } |
| 277 | + } |
| 278 | + } |
| 279 | + /* If the string has not passed all the trials, punish the user. */ |
| 280 | + if(formatcorrect = 0) |
| 281 | + { |
| 282 | + fprintf(stderr, "Line %llu: Format of an address of operation must be &(LABEL[OFFSET])[ADDRESS_OFFSET].\n", FILELINE); |
| 283 | + exit(52); |
| 284 | + } |
| 285 | + } |
| 286 | + |
204 | 287 | /* Search for the square brackets to determine label offset */ |
205 | 288 | for(i = 0; i < strlen(tempstr); i++) |
206 | 289 | { |
|
0 commit comments