]>
Commit | Line | Data |
---|---|---|
1c79356b A |
1 | /* |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
ff6e181a A |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
1c79356b | 12 | * |
ff6e181a A |
13 | * The Original Code and all software distributed under the License are |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
1c79356b A |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
ff6e181a A |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
1c79356b A |
20 | * |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
23 | /* | |
24 | * @OSF_COPYRIGHT@ | |
25 | */ | |
26 | /* | |
27 | * HISTORY | |
28 | * | |
29 | * Revision 1.1.1.1 1998/09/22 21:05:48 wsanchez | |
30 | * Import of Mac OS X kernel (~semeria) | |
31 | * | |
32 | * Revision 1.1.1.1 1998/03/07 02:26:09 wsanchez | |
33 | * Import of OSF Mach kernel (~mburg) | |
34 | * | |
35 | * Revision 1.1.2.1 1997/03/27 18:46:52 barbou | |
36 | * Created. | |
37 | * [1997/03/27 13:58:42 barbou] | |
38 | * | |
39 | * $EndLog$ | |
40 | */ | |
41 | ||
42 | /* makedis.c - make a disassembler. */ | |
43 | ||
44 | /* , | |
45 | By Eamonn McManus <emcmanus@gr.osf.org>, April 1995. | |
46 | Copyright 1995 by Eamonn McManus. Non-commercial use is permitted. */ | |
47 | ||
48 | /* DESCRIPTION | |
49 | ||
50 | This program generates a disassembler in C from a file describing the | |
51 | opcodes of the machine in question. Lines in the description file are | |
52 | either comments beginning with #, or contain three fields, with the | |
53 | first two being terminated by space and the third containing the rest | |
54 | of the line. Long logical lines can be split onto several physical | |
55 | lines by ending each one except the last with a \. A logical line | |
56 | can also be split immediately after a |. Unlike \, | is considered | |
57 | part of the logical line. Leading spaces on continuation lines | |
58 | following either \ or | are ignored. | |
59 | ||
60 | Here is a concise description of the meanings of the three fields. | |
61 | Examples later will make it clearer what they are used for. | |
62 | ||
63 | The first field of the three is a function name. This will produce | |
64 | a function or array of the same name in the C output, so it should | |
65 | not conflict with other identifiers or C keywords. By default the | |
66 | function named returns a string (a (char *) in C), but if the first | |
67 | field is preceded by %, the function returns an unsigned long | |
68 | integer. | |
69 | ||
70 | The second field describes the arguments of the function. It consists | |
71 | of two parts, either but not both of which may be omitted. The first | |
72 | part is a string which is a bitmask describing the first argument of | |
73 | the function. Each character of the string represents one bit, | |
74 | with the least significant bit being the last. A character can be | |
75 | 0 or 1, representing that constant value, or a letter, representing | |
76 | part of a bitfield. A given bitfield consists of all of the | |
77 | contiguous bits containing the same letter. Upper and lower case | |
78 | letters are considered different. | |
79 | ||
80 | The second part of the second field is a list of parameters | |
81 | describing the parameters of the function, or the parameters after | |
82 | the first if the bitfield part was present. The list is contained | |
83 | in parentheses () and the individual parameters are separated by | |
84 | commas. Spaces are not allowed. Each parameter name is a single | |
85 | letter, optionally preceded by %. The parameter is an unsigned | |
86 | long integer if % is present, otherwise a string. Again, upper and | |
87 | lower case parameter names are different. | |
88 | ||
89 | The third field describes the value of the function. If a bitmask | |
90 | is present in the second field and it contains constant bits (0s or | |
91 | 1s), then the third field is the value of the function only in the | |
92 | case where its first argument contains matching values in those bit | |
93 | positions. There can be many different lines naming the same | |
94 | function but with different bitpatterns. The generated C code will | |
95 | arrange to return the value corresponding to the pattern that | |
96 | matches the actual first argument of the function when it is | |
97 | called. This argument should not have bits set in positions beyond | |
98 | those present in the bitpattern. | |
99 | ||
100 | It is only allowed for two different lines to name the same function | |
101 | if there is a bitstring in the second field. It is not allowed for | |
102 | two such lines to specify exactly the same constant bit values. But | |
103 | it is allowed for a line to have all the same constant bit values as | |
104 | another plus some extra constant values. In this case the more | |
105 | specific line applies when all of its constant bits match, and | |
106 | otherwise the less specific line applies. | |
107 | ||
108 | Apart from the contents of the bitstring, the second field must be | |
109 | identical on every line referring to a given function, and the | |
110 | bitstring must always be of the same length. | |
111 | ||
112 | For string-valued functions, the third field is the string value. | |
113 | For integer-valued functions, it is a C integer expression | |
114 | generating the value. In both cases there may be several special | |
115 | values: | |
116 | ||
117 | - A $ followed by a single letter is replaced by the value of the | |
118 | argument or bitfield with that name. The value of a bitfield is | |
119 | shifted as if that bitfield were in the least-significant bit | |
120 | position. Thus, a single-bit field always has value 0 or 1. | |
121 | ||
122 | - A $ followed by the name of a function and an argument list in | |
123 | parentheses () is replaced by the value returned by the function | |
124 | with those arguments. An integer value cannot be inserted into a | |
125 | string without being converted by a function, nor can a string | |
126 | value be used in an integer expression. | |
127 | ||
128 | - A $ followed by a bitstring enclosed in [] is replaced by the | |
129 | value of that bitstring. The bitstring has the same syntax as in | |
130 | the second field, described above. Each contiguous sequence of | |
131 | the same repeated letter in the bitstring is replaced by the | |
132 | value of the argument or bitfield-argument with that name, | |
133 | shifted into the appropriate position. | |
134 | ||
135 | - A list of strings, separated by |, enclosed in | |
136 | {}, and followed by an integer expression enclosed in [], is | |
137 | replaced by the string in the list whose number matches the value | |
138 | of the expression. The first string in the list is numbered 0. | |
139 | If there is no string corresponding to the value of the | |
140 | expression, the behaviour is undefined. The strings in the list | |
141 | may themselves contain $ or {} operations. | |
142 | ||
143 | - A \ followed by any character is replaced by that | |
144 | character, without regard to any meaning it may usually have. | |
145 | This is used to obtain strings containing characters such as | |
146 | {, $, or \. The use of backslash to split long logical | |
147 | lines takes precedence over this use, so \\ should not appear | |
148 | at the end of a line. | |
149 | ||
150 | The third field may also be a lone colon ":", in which case the | |
151 | function is assumed to be defined externally and only a function | |
152 | declaration (prototype) is generated. | |
153 | ||
154 | ||
155 | EXAMPLES | |
156 | ||
157 | Here are some examples from the description file for the Z80 | |
158 | microprocessor. This processor has 8-bit opcodes which are | |
159 | disassembled by a generated function "inst" which looks like this: | |
160 | ||
161 | typedef unsigned long bits; | |
162 | char *inst(bits code) {...} | |
163 | ||
164 | The simplest sort of line in the description file is one that looks | |
165 | like this: | |
166 | ||
167 | inst 01110110 halt | |
168 | ||
169 | The first field names the function, "inst". The second field | |
170 | implies that that function has exactly one argument which is an | |
171 | integer, and that this line specifies the value of the function | |
172 | when this integer has the binary value 01110110 (hex 0x76). This | |
173 | value will be the string "halt". | |
174 | ||
175 | A more complex line is one looking like this: | |
176 | ||
177 | inst 001aa111 {daa|cpl|scf|ccf}[$a] | |
178 | ||
179 | This line is compatible with the previous one, because it has the | |
180 | same number of bits and the constant bits are different. It | |
181 | specifies the value of inst when its argument looks like | |
182 | 001aa111, i.e., for the binary values | |
183 | 00100111, | |
184 | 00101111, | |
185 | 00110111, and | |
186 | 00111111. The value of $a for these four values will be | |
187 | respectively binary 00, 01, 10, 11, i.e., 0 to 3. The | |
188 | corresponding values of the inst function will be "daa", "cpl", | |
189 | "scf", and "ccf". | |
190 | ||
191 | The description defines a helper function "reg8" like this: | |
192 | ||
193 | reg8 rrr {b|c|d|e|h|l|(hl)|a}[$r] | |
194 | ||
195 | This simply selects one of the eight strings between {} depending | |
196 | on the value of the argument, which is assumed to be a three-bit | |
197 | value. This could just as easily have been written: | |
198 | ||
199 | reg8 (%r) {b|c|d|e|h|l|(hl)|a}[$r] | |
200 | ||
201 | The generated C code is the same -- in each case makedis realises | |
202 | that the function can be represented by an array rather than | |
203 | compiling a C function. | |
204 | ||
205 | The reg8 function is used in lines like this one: | |
206 | ||
207 | inst 01rrrsss ld $reg8($r),$reg8($s) | |
208 | ||
209 | Thus if the argument to inst is | |
210 | 01010011 | |
211 | then $r is 010 (2) and $s is 011 (3). Since reg8(2) is "d" and | |
212 | reg8(3) is "e", the value of inst with this argument will be the | |
213 | string "ld d,e". | |
214 | ||
215 | Note that the opcode for "halt" given above matches this pattern, | |
216 | but because the bitpattern for "halt" is more specific (has more | |
217 | constant bits) it is the one chosen when the argument is 01110110. | |
218 | ||
219 | The description also uses an external C function "hexprint" defined | |
220 | like this: | |
221 | ||
222 | char *hexprint(bits digits, bits n) { | |
223 | char *p = dis_alloc(digits + 1); | |
224 | sprintf(p, "%0*lx", (int) digits, n); | |
225 | return p; | |
226 | } | |
227 | ||
228 | The value of this function is a string containing the number n | |
229 | spelt out in hex with "digits" digits. In the description | |
230 | file this function is declared like this: | |
231 | ||
232 | hexprint (%w,%n) : | |
233 | ||
234 | The names of the parameters are not important in this case as long | |
235 | as they are letters and are different from each other. | |
236 | ||
237 | The hexprint function is used in lines like this one: | |
238 | ||
239 | inst 11vvv111 rst $hexprint(2,$v << 3) | |
240 | ||
241 | If the argument to inst is | |
242 | 11011111 | |
243 | then $v is 011 (3) and the arguments to hexprint are 2 and (3 << 3), | |
244 | i.e., 0x18. So the value of inst with this argument will be the | |
245 | string "rst 18". | |
246 | ||
247 | Instead of writing $v << 3, it would be possible to write | |
248 | $[00vvv000]. For instance when $v is binary 011, this becomes | |
249 | 00011000. The leading 0s could be omitted. | |
250 | ||
251 | The $[...] operation is particularly useful for moving bits around. | |
252 | For instance, the HP PA-RISC opcodes contain bits assigned to | |
253 | apparently random parts of the instruction word. One of the helper | |
254 | functions in its description file looks like this: | |
255 | ||
256 | im21l aaaaabbccddddddddddde l'$hex($[edddddddddddbbaaaaacc00000000000]) | |
257 | ||
258 | So 111110011000000000001 produces 10000000000000111111100000000000. | |
259 | ||
260 | The $[...] operation can also be used to spell out binary constants, | |
261 | since C has no syntax for this. | |
262 | ||
263 | ||
264 | ...More to come... */ | |
265 | ||
266 | /* To do: | |
267 | - More error detection, e.g., bitstring or arg not used in entry. | |
268 | - Better error recovery -- nearly all errors are currently fatal. | |
269 | - Clean up type handling, which is somewhat haphazard. It works but there | |
270 | is stuff that is surely redundant. | |
271 | - Make generated functions void by default, with $ prefix to indicate | |
272 | string-value. In a void function, instead of returning a string (or | |
273 | integer) it would be output via a user-supplied function. | |
274 | - Further optimise and tidy generated code, e.g.: arrays of one-character | |
275 | strings could be replaced by arrays of characters; switches with just | |
276 | one case could be replaced by ifs. | |
277 | */ | |
278 | ||
279 | #include <assert.h> | |
280 | #include <ctype.h> | |
281 | #include <errno.h> | |
282 | #include <limits.h> | |
283 | #include <stdio.h> | |
284 | #include <stdlib.h> | |
285 | #include <string.h> | |
286 | ||
287 | #ifndef LONG_BIT | |
288 | #define LONG_BIT (CHAR_BIT * sizeof (long)) | |
289 | #endif /* LONG_BIT */ | |
290 | ||
291 | #define MAXfunction 32 /* Max function name length. */ | |
292 | #define MAXBITS LONG_BIT /* Max bitstring length. */ | |
293 | typedef unsigned long bits; | |
294 | enum type {T_ERROR, T_UNKNOWN, T_INTEGER, T_STRING}; | |
295 | const char *const typename[] = {"error", "unknown", "integer", "string"}; | |
296 | enum walkstringop {COUNTARRAYS, DECLAREARRAYS, COMPILEARRAYS}; | |
297 | char *bitstype = "unsigned long"; | |
298 | ||
299 | int maxfunctionname, maxargwidth; | |
300 | char *progname = "makedis"; | |
301 | char **global_argv; | |
302 | char *filename; | |
303 | char *headerfilename; | |
304 | FILE *headerfile; | |
305 | int lineno; | |
306 | int indentation; | |
307 | int debug, dump, warnings; | |
308 | ||
309 | /* componentbits has a 1 bit for every possible number of strings we may want | |
310 | to concatenate together at some stage. A separate C function is compiled | |
311 | for each such case. */ | |
312 | bits componentbits; | |
313 | ||
314 | ||
315 | struct entry; | |
316 | struct arg; | |
317 | struct string; | |
318 | struct functioncall; | |
319 | struct array; | |
320 | struct bits; | |
321 | struct bitsplice; | |
322 | ||
323 | ||
324 | int main(int argc, char **argv); | |
325 | int makedis(FILE *f, char *fname); | |
326 | struct function *findfunction(char *function); | |
327 | int parseextern(struct function *fp, FILE *f); | |
328 | struct function *makefunction(char *function); | |
329 | int parsebits(struct function *fp, char *bitstring, int nbits); | |
330 | int parseentrybits(struct entry *ep, char *bitstring, int nbits, int issplice); | |
331 | int parsecontrol(char *name, char *value); | |
332 | int parseargs(struct function *fp, FILE *f, int *cp); | |
333 | int parsestring(struct function *fp, char *str); | |
334 | enum type makestring(struct function *fp, struct string **stringlink, | |
335 | char **stringp, char *magic, enum type targettype); | |
336 | int parsedollar(struct function *fp, char **stringp, struct string *sp); | |
337 | int parsebitsplice(struct function *fp, char *bitstring, int nbits, | |
338 | struct string *sp); | |
339 | int findvariable(struct function *fp, int name, struct string *sp); | |
340 | int parsefunctioncall(struct function *fp, char *start, char **stringp, | |
341 | struct string *sp); | |
342 | int parsearray(struct function *fp, char **stringp, struct string *sp, | |
343 | enum type t); | |
344 | void dumpfunctions(void); | |
345 | void dumpfunction(struct function *fp); | |
346 | void showentry(FILE *f, struct function *fp, struct entry *ep, bits highlight); | |
347 | void showbits(FILE *f, struct entry *ep, int nbits, bits highlight); | |
348 | void showargs(FILE *f, struct arg *ap, int fieldwidth); | |
349 | void showstring(FILE *f, struct string *sp); | |
350 | void showstringelement(FILE *f, struct string *sp); | |
351 | void showfunctioncall(FILE *f, struct functioncall *fcp); | |
352 | void showarray(FILE *f, struct array *ap); | |
353 | int outputfunctions(void); | |
354 | void outputidentity(FILE *f); | |
355 | int outputdeclarations(void); | |
356 | void outputconcats(void); | |
357 | void outputconcat(int n); | |
358 | void outputconcatheader(FILE *f, int n); | |
359 | void findarrays(void); | |
360 | int checkfixedlength(struct array *ap); | |
361 | int outputfunction(struct function *fp); | |
362 | void functionarray(struct function *fp); | |
363 | void functionheader(FILE *f, struct function *fp); | |
364 | int simplearray(struct array *ap); | |
365 | void compiletype(FILE *f, enum type *tp); | |
366 | int functionswitch(struct function *fp, bits mask, bits value); | |
367 | int compilestring(int assignto, struct string *sp, enum type type); | |
368 | int compilecheckedstring(int assignto, struct string *sp, enum type type); | |
369 | void compileassign(int assignto); | |
370 | void compiletemp(int tempno); | |
371 | void compiletext(char *s); | |
372 | int compileconcat(struct string *sp, enum type type); | |
373 | int compilenull(enum type type); | |
374 | int compilesimple(struct string *sp, enum type type); | |
375 | int compilearrayref(struct array *ap); | |
376 | int compilefunctioncall(struct string *sp); | |
377 | int walkstring(struct string *sp, enum walkstringop op, int tempno); | |
378 | int compilearray(struct array *ap); | |
379 | void compilesimplearray(enum type *tp, char *name, int num, struct array *ap); | |
380 | void declarearray(struct array *ap); | |
381 | void compilebitstring(struct bits *bp); | |
382 | void compilebitsplice(struct bitsplice *splicep); | |
383 | int bitcount(bits x); | |
384 | bits allbitsset(int nbits); | |
385 | void findent(FILE *f); | |
386 | void indent(void); | |
387 | void *xrealloc(char *oldp, size_t size); | |
388 | void *xmalloc(size_t size); | |
389 | void *xstrdup(char *s); | |
390 | int prematureeof(void); | |
391 | ||
392 | ||
393 | int main(int argc, char **argv) { | |
394 | int i; | |
395 | FILE *f; | |
396 | ||
397 | global_argv = argv; | |
398 | if (argc > 0) | |
399 | progname = argv[0]; | |
400 | for (i = 1; i < argc && argv[i][0] == '-'; i++) { | |
401 | switch (argv[i][1]) { | |
402 | case 'h': | |
403 | if (++i >= argc) | |
404 | goto Usage; | |
405 | headerfilename = argv[i]; break; | |
406 | case 'd': | |
407 | debug = 1; break; | |
408 | case 'D': | |
409 | dump = 1; break; | |
410 | case 'w': | |
411 | warnings = 1; break; | |
412 | default: | |
413 | Usage: | |
414 | fprintf(stderr, "Usage: %s [file]\n", progname); | |
415 | return 1; | |
416 | } | |
417 | } | |
418 | if (i == argc) | |
419 | return makedis(stdin, "<stdin>"); | |
420 | if (i + 1 != argc) | |
421 | goto Usage; | |
422 | if ((f = fopen(argv[i], "r")) == NULL) { | |
423 | fprintf(stderr, "%s: %s: %s\n", progname, argv[i], strerror(errno)); | |
424 | return 1; | |
425 | } | |
426 | return makedis(f, argv[i]); | |
427 | } | |
428 | ||
429 | ||
430 | int makedis(FILE *f, char *fname) { | |
431 | int c, i; | |
432 | char function[MAXfunction], bitstring[MAXBITS]; | |
433 | static char *string = NULL; | |
434 | int stringlen = 0; | |
435 | struct function *fp; | |
436 | ||
437 | filename = fname; | |
438 | lineno = 1; | |
439 | /* Loop for every line in the description. */ | |
440 | while (1) { | |
441 | /* Ignore initial spaces and newlines. */ | |
442 | while (isspace(c = getc(f))) | |
443 | if (c == '\n') | |
444 | lineno++; | |
445 | if (c == EOF) | |
446 | break; | |
447 | ||
448 | /* Ignore comments. # only allowed at start of line. */ | |
449 | if (c == '#') { | |
450 | while ((c = getc(f)) != '\n') | |
451 | if (c == EOF) | |
452 | return prematureeof(); | |
453 | lineno++; | |
454 | continue; | |
455 | } | |
456 | ||
457 | /* Read function name, terminated by space. */ | |
458 | for (i = 0; i < sizeof function && !isspace(c); i++, c = getc(f)) { | |
459 | if (c == EOF) | |
460 | return prematureeof(); | |
461 | function[i] = c; | |
462 | } | |
463 | if (i >= sizeof function) { | |
464 | fprintf(stderr, "%s: %s(%d): function name is too long: %.*s\n", | |
465 | progname, filename, lineno, i, function); | |
466 | return 1; | |
467 | } | |
468 | function[i] = '\0'; | |
469 | ||
470 | /* Skip to next field. */ | |
471 | while (isspace(c) && c != '\n') | |
472 | c = getc(f); | |
473 | ||
474 | /* If not a control statement, read bitstring and/or arguments. */ | |
475 | if (function[0] == ':') | |
476 | fp = 0; /* Silence gcc. */ | |
477 | else { | |
478 | fp = makefunction(function); | |
479 | if (fp == NULL) | |
480 | return 1; | |
481 | ||
482 | /* Read optional bitstring. */ | |
483 | for (i = 0; i < sizeof bitstring && isalnum(c); i++, c = getc(f)) { | |
484 | if (c == EOF) | |
485 | return prematureeof(); | |
486 | bitstring[i] = c; | |
487 | } | |
488 | if (isalnum(c)) { | |
489 | fprintf(stderr, "%s: %s(%d): bit string is too long: %.*s\n", | |
490 | progname, filename, lineno, i, bitstring); | |
491 | return 1; | |
492 | } | |
493 | if (parsebits(fp, bitstring, i) != 0) | |
494 | return 1; | |
495 | ||
496 | /* Read optional arguments. */ | |
497 | if (parseargs(fp, f, &c) != 0) | |
498 | return 1; | |
499 | ||
500 | /* Skip to next field. */ | |
501 | while (isspace(c) && c != '\n') | |
502 | c = getc(f); | |
503 | ||
504 | /* : indicates an external (C) function. */ | |
505 | if (c == ':') { | |
506 | if (parseextern(fp, f) != 0) | |
507 | return 1; | |
508 | continue; | |
509 | } | |
510 | } | |
511 | ||
512 | /* Read associated text. */ | |
513 | i = 0; | |
514 | while (1) { | |
515 | for ( ; c != '\n'; i++, c = getc(f)) { | |
516 | if (c == EOF) | |
517 | return prematureeof(); | |
518 | if (i >= stringlen) { | |
519 | stringlen = stringlen * 2 + 16; | |
520 | string = xrealloc(string, stringlen); | |
521 | } | |
522 | string[i] = c; | |
523 | } | |
524 | lineno++; | |
525 | if (i > 0) { | |
526 | switch (string[i - 1]) { | |
527 | case '\\': | |
528 | i--; | |
529 | /* Fall in... */ | |
530 | case '|': | |
531 | while (isspace(c = getc(f)) && c != '\n') ; | |
532 | continue; | |
533 | } | |
534 | } | |
535 | break; | |
536 | } | |
537 | if (i >= stringlen) { | |
538 | stringlen = stringlen * 2 + 16; | |
539 | string = xrealloc(string, stringlen); | |
540 | } | |
541 | string[i] = '\0'; | |
542 | ||
543 | /* Parse the line just read. */ | |
544 | if (function[0] == ':') { | |
545 | if (parsecontrol(function + 1, string) != 0) | |
546 | return 1; | |
547 | } else { | |
548 | if (parsestring(fp, string) != 0) | |
549 | return 1; | |
550 | } | |
551 | } | |
552 | if (dump) | |
553 | dumpfunctions(); | |
554 | return outputfunctions(); | |
555 | } | |
556 | ||
557 | ||
558 | /* A function in the description file. nbits and nargs are -1 until the | |
559 | real values are known. */ | |
560 | struct function { | |
561 | struct function *next; | |
562 | char *name; | |
563 | enum type type; | |
564 | int nbits; /* Number of bits in the bitpattern, 0 if none. */ | |
565 | int nargs; /* Number of (x,y,...) parameters, 0 if none. */ | |
566 | char isarray; /* Will be represented by a C array. */ | |
567 | int fixedlength; /* If a C array, will be a char [][N] not a char *[]. */ | |
568 | struct entry *first, *last; | |
569 | /* Links to the value(s) supplied. */ | |
570 | struct arg *args; /* List of (x,y,...) names and types. */ | |
571 | }; | |
572 | struct function *functions; | |
573 | ||
574 | ||
575 | /* Find the function with the given name. If not found, create a structure | |
576 | for it, fill it out with a template, and return that. */ | |
577 | struct function *findfunction(char *name) { | |
578 | struct function *fp; | |
579 | ||
580 | for (fp = functions; fp != NULL; fp = fp->next) { | |
581 | if (strcmp(fp->name, name) == 0) | |
582 | return fp; | |
583 | } | |
584 | if (strlen(name) > maxfunctionname) | |
585 | maxfunctionname = strlen(name); | |
586 | fp = xmalloc(sizeof *fp); | |
587 | fp->next = functions; | |
588 | functions = fp; | |
589 | fp->name = xstrdup(name); | |
590 | fp->type = T_UNKNOWN; | |
591 | fp->nbits = fp->nargs = -1; /* nbits will be set correctly later. */ | |
592 | fp->isarray = 0; | |
593 | fp->first = fp->last = NULL; | |
594 | return fp; | |
595 | } | |
596 | ||
597 | ||
598 | /* Parse an external (C) function declaration. This will look something like: | |
599 | malloc (%s) : | |
600 | We're called just after seeing the ':'. | |
601 | Return 0 if parsing is successful, 1 otherwise. */ | |
602 | int parseextern(struct function *fp, FILE *f) { | |
603 | int c; | |
604 | ||
605 | if ((c = getc(f)) != '\n') { | |
606 | fprintf(stderr, | |
607 | "%s: %s(%d): extern declaration should be a lone `:'\n", | |
608 | progname, filename, lineno); | |
609 | return 1; | |
610 | } | |
611 | if (fp->nbits != 0) { | |
612 | fprintf(stderr, | |
613 | "%s: %s(%d): extern functions should not have bitstrings\n", | |
614 | progname, filename, lineno); | |
615 | return 1; | |
616 | } | |
617 | free(fp->first); | |
618 | fp->first = fp->last = NULL; | |
619 | return 0; | |
620 | } | |
621 | ||
622 | ||
623 | /* A value supplied for a function (the third field in a description line). | |
624 | In general there can be any number of such values, differing in the | |
625 | bitpattern supplied. The mask and value fields describe the constant | |
626 | bits in the bitpattern: mask indicates which bits they are and value | |
627 | indicates the values of those bits. So this entry matches | |
628 | ((x & mask) == value). */ | |
629 | struct entry { | |
630 | struct entry *next; | |
631 | bits mask, value; | |
632 | struct bits *bits; /* List of named bitfields. */ | |
633 | struct string *string; /* Value of function when bitpattern matched. */ | |
634 | char done; /* This entry has already been compiled. */ | |
635 | }; | |
636 | ||
637 | ||
638 | /* We've just seen a definition of function "name". Make a structure for it | |
639 | if necessary, and a template entry that will describe the value given here. | |
640 | */ | |
641 | struct function *makefunction(char *name) { | |
642 | struct function *fp; | |
643 | struct entry *ep = xmalloc(sizeof *ep); | |
644 | enum type type; | |
645 | ||
646 | if (name[0] == '%') { | |
647 | name++; | |
648 | type = T_INTEGER; | |
649 | } else | |
650 | type = T_STRING; | |
651 | fp = findfunction(name); | |
652 | if (fp->type == T_UNKNOWN) | |
653 | fp->type = type; | |
654 | else if (fp->type != type) { | |
655 | fprintf(stderr, "%s: %s(%d): function %s previously declared as %s, " | |
656 | "here as %s\n", progname, filename, lineno, name, | |
657 | typename[fp->type], typename[type]); | |
658 | return NULL; | |
659 | } | |
660 | ep->next = NULL; | |
661 | ep->bits = NULL; | |
662 | ep->done = 0; | |
663 | if (fp->first != NULL) | |
664 | fp->last->next = ep; | |
665 | else | |
666 | fp->first = ep; | |
667 | fp->last = ep; | |
668 | return fp; | |
669 | } | |
670 | ||
671 | ||
672 | /* A named bitfield within the bitpattern of a function entry, or within a | |
673 | $[...] bitsplice. The mask covers the bitfield and the shift says how | |
674 | many 0 bits there are after the last 1 in the mask. */ | |
675 | struct bits { | |
676 | struct bits *next; | |
677 | int shift; | |
678 | bits mask; | |
679 | char name; | |
680 | }; | |
681 | ||
682 | ||
683 | /* Parse the bitstring supplied for the given function. nbits says how many | |
684 | bits there are; it can legitimately be 0. Return value is 0 on success. */ | |
685 | int parsebits(struct function *fp, char *bitstring, int nbits) { | |
686 | if (fp->nbits < 0) | |
687 | fp->nbits = nbits; | |
688 | else if (fp->nbits != nbits) { | |
689 | fprintf(stderr, "%s: %s(%d): bit string of length %d;\n", | |
690 | progname, filename, lineno, nbits); | |
691 | fprintf(stderr, " function %s has bit strings of length %d\n", | |
692 | fp->name, fp->nbits); | |
693 | return 1; | |
694 | } | |
695 | return parseentrybits(fp->last, bitstring, nbits, 0); | |
696 | } | |
697 | ||
698 | ||
699 | /* Parse a bitstring that is the pattern for a function entry or that is in a | |
700 | $[...] bitsplice. Put the result in ep. Return value is 0 on success. */ | |
701 | int parseentrybits(struct entry *ep, char *bitstring, int nbits, int issplice) { | |
702 | int i, j; | |
703 | char bit; | |
704 | bits mask, value, entrymask; | |
705 | struct bits *bp; | |
706 | ||
707 | mask = value = 0; | |
708 | for (i = 0; i < nbits; i++) { | |
709 | bit = bitstring[nbits - 1 - i]; | |
710 | switch (bit) { | |
711 | case '1': | |
712 | value |= 1 << i; | |
713 | /* Fall in... */ | |
714 | case '0': | |
715 | mask |= 1 << i; | |
716 | continue; | |
717 | } | |
718 | if (!isalpha(bit)) { | |
719 | fprintf(stderr, "%s: %s(%d): invalid character in bitstring: %c\n", | |
720 | progname, filename, lineno, bit); | |
721 | return 1; | |
722 | } | |
723 | if (!issplice) { | |
724 | for (bp = ep->bits; bp != NULL; bp = bp->next) { | |
725 | if (bp->name == bit) { | |
726 | fprintf(stderr, | |
727 | "%s: %s(%d): bitstring name %c used twice\n", | |
728 | progname, filename, lineno, bit); | |
729 | return 1; | |
730 | } | |
731 | } | |
732 | } | |
733 | entrymask = 1 << i; | |
734 | for (j = i + 1; j < nbits && bitstring[nbits - 1 - j] == bit; j++) | |
735 | entrymask |= 1 << j; | |
736 | bp = xmalloc(sizeof *bp); | |
737 | bp->shift = i; | |
738 | bp->mask = entrymask; | |
739 | bp->name = bit; | |
740 | bp->next = ep->bits; | |
741 | ep->bits = bp; | |
742 | i = j - 1; | |
743 | } | |
744 | ep->mask = mask; | |
745 | ep->value = value; | |
746 | return 0; | |
747 | } | |
748 | ||
749 | ||
750 | /* Parse a control line. This looks something like: | |
751 | :bitstype unsigned int | |
752 | in which case we will be called with name "bitstype" and | |
753 | value "unsigned int". */ | |
754 | int parsecontrol(char *name, char *value) { | |
755 | if (strcmp(name, "bitstype") == 0) | |
756 | bitstype = xstrdup(value); | |
757 | else { | |
758 | fprintf(stderr, "%s: %s(%d): unrecognised control keyword %s\n", | |
759 | progname, filename, lineno, name); | |
760 | return 1; | |
761 | } | |
762 | return 0; | |
763 | } | |
764 | ||
765 | ||
766 | /* A parameter to a function, e.g., x in: | |
767 | %f aaa(%x) $a + $x */ | |
768 | struct arg { | |
769 | struct arg *next; | |
770 | enum type type; | |
771 | char name; | |
772 | }; | |
773 | ||
774 | ||
775 | /* Parse the parameters (x,y,...) to a function and put the result in fp. | |
776 | The entry that is being built is fp->last. cp points to the opening | |
777 | (; if it does not point to a ( then there are no parameters. If | |
778 | this is the first entry for the function, fp->nargs will be -1 and | |
779 | we will build up an argument list. Otherwise, fp->nargs will be | |
780 | >= 0 and we will only check that the arguments here are consistent | |
781 | with what went before. Return value is 0 on success. */ | |
782 | int parseargs(struct function *fp, FILE *f, int *cp) { | |
783 | struct arg **arglink, *ap; | |
784 | struct bits *bp; | |
785 | int nargs, width; | |
786 | char name; | |
787 | enum type t; | |
788 | ||
789 | arglink = &fp->args; | |
790 | width = nargs = 0; | |
791 | if (*cp == '(') { | |
792 | *cp = getc(f); | |
793 | if (*cp != ')') { | |
794 | width = 1; | |
795 | while (1) { | |
796 | nargs++; | |
797 | width += 2; | |
798 | if (fp->nargs >= 0 && nargs > fp->nargs) { | |
799 | fprintf(stderr, | |
800 | "%s: %s(%d): %d arg(s) instead of %d for %s\n", | |
801 | progname, filename, lineno, nargs, fp->nargs, | |
802 | fp->name); | |
803 | return 1; | |
804 | } | |
805 | t = T_STRING; | |
806 | if (*cp == '%') { | |
807 | width++; | |
808 | t = T_INTEGER; | |
809 | *cp = getc(f); | |
810 | } | |
811 | name = *cp; | |
812 | if (!isalpha(name)) { | |
813 | fprintf(stderr, | |
814 | "%s: %s(%d): argument should be letter: %c\n", | |
815 | progname, filename, lineno, name); | |
816 | return 1; | |
817 | } | |
818 | for (bp = fp->last->bits; bp != NULL; bp = bp->next) { | |
819 | if (bp->name == name) { | |
820 | fprintf(stderr, | |
821 | "%s: %s(%d): %c is a bitstring and an arg\n", | |
822 | progname, filename, lineno, name); | |
823 | return 1; | |
824 | } | |
825 | } | |
826 | if (fp->nargs >= 0) { | |
827 | if ((*arglink)->name != name) { | |
828 | fprintf(stderr, | |
829 | "%s: %s(%d): arg %d of %s is %c not %c\n", | |
830 | progname, filename, lineno, nargs, fp->name, | |
831 | (*arglink)->name, name); | |
832 | return 1; | |
833 | } | |
834 | if ((*arglink)->type != t) { | |
835 | fprintf(stderr, | |
836 | "%s: %s(%d): arg %c of %s: inconsistent type\n", | |
837 | progname, filename, lineno, name, fp->name); | |
838 | return 1; | |
839 | } | |
840 | } else { | |
841 | for (ap = fp->args; ap != *arglink; ap = ap->next) { | |
842 | if (ap->name == name) { | |
843 | fprintf(stderr, | |
844 | "%s: %s(%d): argument name %c used twice\n", | |
845 | progname, filename, lineno, name); | |
846 | return 1; | |
847 | } | |
848 | } | |
849 | *arglink = xmalloc(sizeof **arglink); | |
850 | (*arglink)->name = name; | |
851 | (*arglink)->type = t; | |
852 | } | |
853 | arglink = &(*arglink)->next; | |
854 | *cp = getc(f); | |
855 | if (*cp == ')') | |
856 | break; | |
857 | if (*cp != ',') { | |
858 | fprintf(stderr, | |
859 | "%s: %s(%d): bad character in argument list: %c\n" | |
860 | " (arguments must be single letters)\n", | |
861 | progname, filename, lineno, *cp); | |
862 | return 1; | |
863 | } | |
864 | *cp = getc(f); | |
865 | } | |
866 | } | |
867 | *cp = getc(f); | |
868 | } | |
869 | if (fp->nargs < 0) { | |
870 | fp->nargs = nargs; | |
871 | width += fp->nbits; | |
872 | if (width > maxargwidth) | |
873 | maxargwidth = width; | |
874 | } else if (fp->nargs != nargs) { | |
875 | fprintf(stderr, "%s: %s(%d): argument list of length %d;\n", | |
876 | progname, filename, lineno, nargs); | |
877 | fprintf(stderr, " function %s has argument lists of length %d\n", | |
878 | fp->name, fp->nargs); | |
879 | return 1; | |
880 | } | |
881 | *arglink = NULL; | |
882 | return 0; | |
883 | } | |
884 | ||
885 | ||
886 | /* Parse the string describing the value of this entry for our | |
887 | function. Return 0 on success. */ | |
888 | int parsestring(struct function *fp, char *str) { | |
889 | enum type t; | |
890 | ||
891 | t = makestring(fp, &fp->last->string, &str, NULL, fp->type); | |
892 | if (t == T_ERROR) | |
893 | return 1; | |
894 | if (fp->type != t && t != T_UNKNOWN) { | |
895 | fprintf(stderr, "%s: %s(%d): function %s has inconsistent types\n", | |
896 | progname, filename, lineno, fp->name); | |
897 | return 1; | |
898 | } | |
899 | return 0; | |
900 | } | |
901 | ||
902 | ||
903 | /* A parsed representation of the whole string describing a value of a | |
904 | function, or certain strings within that (e.g., array indices). This is a | |
905 | linked list of substrings whose type is given by the type field. */ | |
906 | struct string { | |
907 | struct string *next; | |
908 | enum elementtype { | |
909 | S_TEXT, S_BITSTRING, S_BITSPLICE, S_PARAMETER, S_FUNCTIONCALL, S_ARRAY | |
910 | } type; | |
911 | union value { /* The fields here correspond to the enum values. */ | |
912 | char *text; /* plain text */ | |
913 | struct bits *bits; /* $x where x is a bitfield */ | |
914 | struct bitsplice *bitsplice; /* $[...] */ | |
915 | struct arg *parameter; /* $x where x is a parameter */ | |
916 | struct functioncall *functioncall; /* $func(...) */ | |
917 | struct array *array; /* {...}[...] */ | |
918 | } value; | |
919 | }; | |
920 | ||
921 | /* The representation of a function call $func(...) in the description of a | |
922 | function value. */ | |
923 | struct functioncall { | |
924 | struct function *function; | |
925 | struct stringlist *args; | |
926 | }; | |
927 | ||
928 | /* The representation of an array selection {...|...}[...] in the description | |
929 | of a function value. tempno is used when constructing a C variable name | |
930 | that will contain the strings or numbers in an array. */ | |
931 | struct array { | |
932 | struct string *index; /* what's between [...] */ | |
933 | struct stringlist *elements; /* what's between {...} */ | |
934 | enum type type; /* the type of each element */ | |
935 | int tempno; | |
936 | }; | |
937 | ||
938 | /* A list of strings, being the list of arguments in a function call or the | |
939 | list of elements of an array. This is a linked list of linked lists. */ | |
940 | struct stringlist { | |
941 | struct stringlist *next; | |
942 | enum type type; | |
943 | struct string *string; | |
944 | }; | |
945 | ||
946 | ||
947 | /* The following are the only characters with special meaning at the top level | |
948 | of parsing of a function value. When parsing arrays or function calls, | |
949 | other characters become special. */ | |
950 | #define MAKESTRING_MAGIC "${"/*}*/ | |
951 | ||
952 | ||
953 | /* Parse a function return-value string or substring and make a struct string | |
954 | list for it. The string starts at *stringp and ends at a \0 or at any | |
955 | character in the `magic' string other than { or $. *stringp is updated | |
956 | to point to the terminating character. The parsed representation is put | |
957 | at *stringlink. `fp' is the function whose return value is being parsed. | |
958 | `targettype' is the expected type of the result, if known. | |
959 | The return value is the actual type. */ | |
960 | enum type makestring(struct function *fp, struct string **stringlink, | |
961 | char **stringp, char *magic, enum type targettype) { | |
962 | char *p, *q; | |
963 | struct string *sp, **firststringlink; | |
964 | int n, components; | |
965 | int parenlevel = 0; | |
966 | enum type t = targettype, newt; | |
967 | ||
968 | if (magic == NULL) | |
969 | magic = MAKESTRING_MAGIC; | |
970 | p = *stringp; | |
971 | firststringlink = stringlink; | |
972 | components = 0; | |
973 | while (*p != '\0') { | |
974 | sp = xmalloc(sizeof *sp); | |
975 | q = p; | |
976 | n = 0; | |
977 | do { | |
978 | if (strchr(magic, *q) != NULL) { | |
979 | if (*q != ')' || parenlevel == 0) | |
980 | break; | |
981 | } | |
982 | switch (*q) { | |
983 | case '(': | |
984 | parenlevel++; break; | |
985 | case ')': | |
986 | parenlevel--; break; | |
987 | case '\\': | |
988 | if (q[1] != '\0') | |
989 | q++; | |
990 | break; | |
991 | } | |
992 | n++; | |
993 | } while (*++q != '\0'); | |
994 | if (n > 0) { | |
995 | sp->type = S_TEXT; | |
996 | sp->value.text = q = xmalloc(n + 1); | |
997 | do { | |
998 | if (*p == '\\') | |
999 | p++; | |
1000 | *q++ = *p++; | |
1001 | } while (--n > 0); | |
1002 | *q = '\0'; | |
1003 | newt = t; | |
1004 | } else if (*p == '$') { | |
1005 | if (parsedollar(fp, &p, sp) != 0) | |
1006 | return T_ERROR; | |
1007 | switch (sp->type) { | |
1008 | case S_BITSTRING: | |
1009 | case S_BITSPLICE: | |
1010 | newt = T_INTEGER; | |
1011 | break; | |
1012 | case S_PARAMETER: | |
1013 | newt = sp->value.parameter->type; | |
1014 | break; | |
1015 | case S_FUNCTIONCALL: | |
1016 | newt = sp->value.functioncall->function->type; | |
1017 | break; | |
1018 | default: | |
1019 | fprintf(stderr, "makestring type %d\n", sp->type); | |
1020 | abort(); | |
1021 | } | |
1022 | } else if (*p == '{'/*}*/) { | |
1023 | if (parsearray(fp, &p, sp, t) != 0) | |
1024 | return T_ERROR; | |
1025 | newt = sp->value.array->type; | |
1026 | } else { | |
1027 | free(sp); | |
1028 | break; | |
1029 | } | |
1030 | if (t == T_UNKNOWN) | |
1031 | t = newt; | |
1032 | else if (newt != T_UNKNOWN && t != newt) { | |
1033 | if (stringlink == firststringlink) { | |
1034 | fprintf(stderr, "%s: %s(%d): expected %s type:\n", progname, | |
1035 | filename, lineno, typename[t]); | |
1036 | showstringelement(stderr, sp); | |
1037 | return T_ERROR; | |
1038 | } | |
1039 | *stringlink = NULL; | |
1040 | fprintf(stderr, "%s: %s(%d): mixed types in string:\n", | |
1041 | progname, filename, lineno); | |
1042 | showstring(stderr, *firststringlink); | |
1043 | fprintf(stderr, " -- %s\n", typename[t]); | |
1044 | showstringelement(stderr, sp); | |
1045 | fprintf(stderr, " -- %s\n", typename[newt]); | |
1046 | return T_ERROR; | |
1047 | } | |
1048 | *stringlink = sp; | |
1049 | stringlink = &sp->next; | |
1050 | components++; | |
1051 | } | |
1052 | *stringlink = NULL; | |
1053 | *stringp = p; | |
1054 | if (components >= MAXBITS) { | |
1055 | fprintf(stderr, "%s: %s(%d): excessively complicated string\n", | |
1056 | progname, filename, lineno); | |
1057 | return T_ERROR; | |
1058 | } | |
1059 | componentbits |= 1 << components; | |
1060 | return t; | |
1061 | } | |
1062 | ||
1063 | ||
1064 | /* Parse a $ operation at **stringp and update *stringp to point past it. | |
1065 | `fp' is the function whose return value is being parsed. The parsed | |
1066 | item will be put at *sp. Return 0 on success, nonzero on error. */ | |
1067 | int parsedollar(struct function *fp, char **stringp, struct string *sp) { | |
1068 | char *p, *start; | |
1069 | ||
1070 | p = *stringp; | |
1071 | assert(*p == '$'); | |
1072 | start = ++p; | |
1073 | if (*p == '[') | |
1074 | p++; | |
1075 | while (isalnum(*p) || *p == '_') | |
1076 | p++; | |
1077 | if (*start == '[') { | |
1078 | if (*p != ']') { | |
1079 | fprintf(stderr, "%s: %s(%d): missing ] or bad character in $[\n", | |
1080 | progname, filename, lineno); | |
1081 | return 1; | |
1082 | } | |
1083 | *stringp = p + 1; | |
1084 | return parsebitsplice(fp, start + 1, p - start - 1, sp); | |
1085 | } | |
1086 | if (p == start) { | |
1087 | fprintf(stderr, "%s: %s(%d): missing identifier after $\n", progname, | |
1088 | filename, lineno); | |
1089 | return 1; | |
1090 | } | |
1091 | if (p == start + 1) { | |
1092 | if (findvariable(fp, *start, sp) != 0) | |
1093 | return 1; | |
1094 | } else { | |
1095 | if (parsefunctioncall(fp, start, &p, sp) != 0) | |
1096 | return 1; | |
1097 | } | |
1098 | *stringp = p; | |
1099 | return 0; | |
1100 | } | |
1101 | ||
1102 | ||
1103 | /* The representation of a $[...] bitsplice. It is parsed into a | |
1104 | struct entry just as if it were a bitfield parameter, then analysed | |
1105 | into a chain of struct bitsplicebits. These in conjunction with | |
1106 | the constant portion of the struct entry will allow the bitsplice to | |
1107 | be compiled. Each bitsplicebits element represents either a numeric | |
1108 | argument to the current function, in which case it will be shifted | |
1109 | into place; or a bitfield name from the bitfield description of the | |
1110 | current function, in which case it will be shifted by the difference | |
1111 | between the position of the bitfield in the argument and the position | |
1112 | it occurs in the bitsplice. `shift' indicates how much to shift left | |
1113 | the associated value; if it is negative the value is shifted right. | |
1114 | For instance, in a function like this: | |
1115 | %oh xx00(%y) $[yyxx] | |
1116 | the bitsplicebits for y will have shift = 2 and value.arg pointing to y, | |
1117 | and those for x will have shift = -2 and value.mask = binary 1100. | |
1118 | As an optimisation, contiguous bitfields that are also contiguous in the | |
1119 | bitsplice will be combined. For instance: | |
1120 | %oh xxyy00 $[0xxyy0] | |
1121 | will compile the same code as: | |
1122 | %oh zzzz00 $[0zzzz0]. | |
1123 | As another optimisation, a bitfield that occupies the entire bitstring | |
1124 | for a function will be treated like a parameter in that it will not be | |
1125 | masked in the bitsplice. For instance: | |
1126 | %oh xxxxxx $[0xxxxxx0] | |
1127 | will compile the same code as: | |
1128 | %oh (%x) $[0xxxxxx0]. */ | |
1129 | struct bitsplice { | |
1130 | struct entry entry; | |
1131 | int nbits; | |
1132 | struct bitsplicebits *splice; | |
1133 | }; | |
1134 | struct bitsplicebits { | |
1135 | struct bitsplicebits *next; | |
1136 | int shift; | |
1137 | enum elementtype type; | |
1138 | union { | |
1139 | struct arg *arg; | |
1140 | bits mask; | |
1141 | } value; | |
1142 | }; | |
1143 | ||
1144 | ||
1145 | int parsebitsplice(struct function *fp, char *bitstring, int nbits, | |
1146 | struct string *sp) { | |
1147 | struct bitsplice *splicep; | |
1148 | struct bitsplicebits *bsp, *lastbsp, **bspp; | |
1149 | struct bits *bp; | |
1150 | int shift, nfrombits, ntobits; | |
1151 | bits allbits, b; | |
1152 | ||
1153 | splicep = xmalloc(sizeof *splicep); | |
1154 | splicep->nbits = nbits; | |
1155 | if (parseentrybits(&splicep->entry, bitstring, nbits, 1) != 0) | |
1156 | return 1; | |
1157 | bspp = &splicep->splice; | |
1158 | lastbsp = NULL; | |
1159 | for (bp = splicep->entry.bits; bp != NULL; bp = bp->next) { | |
1160 | if (findvariable(fp, bp->name, sp) != 0) | |
1161 | return 1; | |
1162 | shift = bp->shift; | |
1163 | if (sp->type == S_BITSTRING) { | |
1164 | nfrombits = bitcount(sp->value.bits->mask); | |
1165 | ntobits = bitcount(bp->mask); | |
1166 | if (warnings) { | |
1167 | if (nfrombits != ntobits) { | |
1168 | fprintf(stderr, "%s: %s(%d): warning: " | |
1169 | "bitstring $%c %ser than its place " | |
1170 | "in bitsplice\n", | |
1171 | progname, filename, lineno, bp->name, | |
1172 | (nfrombits > ntobits) ? "bigg" : "small"); | |
1173 | } | |
1174 | } | |
1175 | shift -= sp->value.bits->shift; | |
1176 | ||
1177 | /* See if this bitfield can be combined with a previous contiguous | |
1178 | bitfield. */ | |
1179 | if (lastbsp != NULL && lastbsp->type == S_BITSTRING | |
1180 | && lastbsp->shift == shift) { | |
1181 | lastbsp->value.mask |= sp->value.bits->mask; | |
1182 | continue; | |
1183 | } | |
1184 | } else { | |
1185 | assert(sp->type == S_PARAMETER); | |
1186 | if (sp->value.parameter->type != T_INTEGER) { | |
1187 | fprintf(stderr, | |
1188 | "%s: %s(%d): variable %c in $[...] should be integer\n", | |
1189 | progname, filename, lineno, sp->value.parameter->name); | |
1190 | return 1; | |
1191 | } | |
1192 | } | |
1193 | *bspp = bsp = xmalloc(sizeof *bsp); | |
1194 | bsp->type = sp->type; | |
1195 | bsp->shift = shift; | |
1196 | if (sp->type == S_PARAMETER) | |
1197 | bsp->value.arg = sp->value.parameter; | |
1198 | else | |
1199 | bsp->value.mask = sp->value.bits->mask; | |
1200 | bspp = &bsp->next; | |
1201 | lastbsp = bsp; | |
1202 | } | |
1203 | *bspp = NULL; | |
1204 | ||
1205 | /* Look for a spliced element that is the entire bitstring argument to | |
1206 | this function and therefore doesn't need to be masked. */ | |
1207 | allbits = allbitsset(fp->nbits); | |
1208 | for (bsp = splicep->splice; bsp != NULL; bsp = bsp->next) { | |
1209 | if (bsp->type == S_BITSTRING) { | |
1210 | for (b = bsp->value.mask; b != 0 && !(b & 1); b >>= 1) ; | |
1211 | if (b == allbits) | |
1212 | bsp->value.mask = 0; | |
1213 | } | |
1214 | } | |
1215 | sp->type = S_BITSPLICE; | |
1216 | sp->value.bitsplice = splicep; | |
1217 | return 0; | |
1218 | } | |
1219 | ||
1220 | ||
1221 | int findvariable(struct function *fp, int name, struct string *sp) { | |
1222 | struct bits *bp; | |
1223 | struct arg *ap; | |
1224 | ||
1225 | for (bp = fp->last->bits; bp != NULL; bp = bp->next) { | |
1226 | if (bp->name == name) { | |
1227 | sp->type = S_BITSTRING; | |
1228 | sp->value.bits = bp; | |
1229 | return 0; | |
1230 | } | |
1231 | } | |
1232 | for (ap = fp->args; ap != NULL; ap = ap->next) { | |
1233 | if (ap->name == name) { | |
1234 | sp->type = S_PARAMETER; | |
1235 | sp->value.parameter = ap; | |
1236 | return 0; | |
1237 | } | |
1238 | } | |
1239 | fprintf(stderr, "%s: %s(%d): undefined parameter %c\n", progname, filename, | |
1240 | lineno, name); | |
1241 | return 1; | |
1242 | } | |
1243 | ||
1244 | ||
1245 | int parsefunctioncall(struct function *fp, char *start, char **stringp, | |
1246 | struct string *sp) { | |
1247 | char *p; | |
1248 | struct functioncall *fcp; | |
1249 | struct stringlist **arglink, *arg; | |
1250 | enum type t; | |
1251 | ||
1252 | p = *stringp; | |
1253 | if (*p != '(') { | |
1254 | fprintf(stderr, "%s: %s(%d): missing ( after function %.*s\n", progname, | |
1255 | filename, lineno, p - start, start); | |
1256 | return 1; | |
1257 | } | |
1258 | sp->type = S_FUNCTIONCALL; | |
1259 | sp->value.functioncall = fcp = xmalloc(sizeof *fcp); | |
1260 | *p = '\0'; /* Ugly. */ | |
1261 | fcp->function = findfunction(start); | |
1262 | *p = '('; | |
1263 | arglink = &fcp->args; | |
1264 | if (*++p != ')') { | |
1265 | while (1) { | |
1266 | arg = xmalloc(sizeof *arg); | |
1267 | t = makestring(fp, &arg->string, &p, MAKESTRING_MAGIC ",)", | |
1268 | T_UNKNOWN); | |
1269 | if (t == T_ERROR) | |
1270 | return 1; | |
1271 | arg->type = t; | |
1272 | *arglink = arg; | |
1273 | arglink = &arg->next; | |
1274 | if (*p == ')') | |
1275 | break; | |
1276 | assert(*p == ','); | |
1277 | p++; | |
1278 | } | |
1279 | } | |
1280 | *arglink = NULL; | |
1281 | assert(*p == ')'); | |
1282 | *stringp = p + 1; | |
1283 | return 0; | |
1284 | } | |
1285 | ||
1286 | ||
1287 | int parsearray(struct function *fp, char **stringp, struct string *sp, | |
1288 | enum type t) { | |
1289 | char *p; | |
1290 | struct array *ap; | |
1291 | struct stringlist **elementlink, *element; | |
1292 | ||
1293 | p = *stringp; | |
1294 | assert(*p == '{'/*}*/); | |
1295 | sp->type = S_ARRAY; | |
1296 | sp->value.array = ap = xmalloc(sizeof *ap); | |
1297 | ap->tempno = -1; | |
1298 | elementlink = &ap->elements; | |
1299 | ap->type = t; | |
1300 | if (*++p != /*{*/'}') { | |
1301 | while (1) { | |
1302 | element = xmalloc(sizeof *element); | |
1303 | t = makestring(fp, &element->string, &p, | |
1304 | MAKESTRING_MAGIC /*{*/"|}", t); | |
1305 | if (t == T_ERROR) | |
1306 | return 1; | |
1307 | element->type = t; | |
1308 | if (ap->type == T_UNKNOWN) | |
1309 | ap->type = t; | |
1310 | else if (t != T_UNKNOWN && ap->type != t) { | |
1311 | fprintf(stderr, "%s: %s(%d): mixed types in array:\n", | |
1312 | progname, filename, lineno); | |
1313 | showstring(stderr, ap->elements->string); | |
1314 | fprintf(stderr, " -- %s\n", typename[ap->type]); | |
1315 | showstring(stderr, element->string); | |
1316 | fprintf(stderr, " -- %s\n", typename[t]); | |
1317 | return 1; | |
1318 | } | |
1319 | *elementlink = element; | |
1320 | elementlink = &element->next; | |
1321 | if (*p == /*{*/'}') | |
1322 | break; | |
1323 | assert(*p == '|'); | |
1324 | p++; | |
1325 | } | |
1326 | } | |
1327 | *elementlink = NULL; | |
1328 | assert(*p == /*{*/'}'); | |
1329 | if (*++p != '[') { | |
1330 | fprintf(stderr, "%s: %s(%d): missing [index] after array\n", | |
1331 | progname, filename, lineno); | |
1332 | return 1; | |
1333 | } | |
1334 | ++p; | |
1335 | t = makestring(fp, &ap->index, &p, MAKESTRING_MAGIC "]", T_INTEGER); | |
1336 | if (t == T_ERROR) | |
1337 | return 1; | |
1338 | if (t == T_STRING) { | |
1339 | fprintf(stderr, "%s: %s(%d): array index cannot be string:\n", | |
1340 | progname, filename, lineno); | |
1341 | showstring(stderr, ap->index); | |
1342 | return 1; | |
1343 | } | |
1344 | if (*p != ']') { | |
1345 | fprintf(stderr, "%s: %s(%d): [ without ]\n", progname, filename, | |
1346 | lineno); | |
1347 | return 1; | |
1348 | } | |
1349 | *stringp = p + 1; | |
1350 | return 0; | |
1351 | } | |
1352 | ||
1353 | ||
1354 | void dumpfunctions() { | |
1355 | struct function *fp; | |
1356 | ||
1357 | for (fp = functions; fp != NULL; fp = fp->next) | |
1358 | dumpfunction(fp); | |
1359 | } | |
1360 | ||
1361 | ||
1362 | void dumpfunction(struct function *fp) { | |
1363 | struct entry *ep; | |
1364 | ||
1365 | for (ep = fp->first; ep != NULL; ep = ep->next) | |
1366 | showentry(stderr, fp, ep, 0); | |
1367 | } | |
1368 | ||
1369 | ||
1370 | /* Entries are not shown exactly as they would be input, since \ would | |
1371 | need to be provided before some characters such as $ or {. But the | |
1372 | characters "|},]" pose a problem since a \ is only needed in certain | |
1373 | contexts and is annoying otherwise. It's not worth doing this right, | |
1374 | since it's only used for error messages. */ | |
1375 | void showentry(FILE *f, struct function *fp, struct entry *ep, bits highlight) { | |
1376 | if (fp->type == T_INTEGER) | |
1377 | putc('%', f); | |
1378 | fprintf(f, "%-*s ", maxfunctionname + 1, fp->name); | |
1379 | if (fp->nbits == 0 && fp->nargs == 0) | |
1380 | fprintf(f, "%-*s", maxargwidth, "()"); | |
1381 | else { | |
1382 | showbits(f, ep, fp->nbits, 0); | |
1383 | showargs(f, fp->args, maxargwidth - fp->nbits); | |
1384 | } | |
1385 | putc(' ', f); | |
1386 | showstring(f, ep->string); | |
1387 | putc('\n', f); | |
1388 | if (highlight != 0) { | |
1389 | fprintf(f, "%-*s ", maxfunctionname + 1, ""); | |
1390 | showbits(f, ep, fp->nbits, highlight); | |
1391 | putc('\n', f); | |
1392 | } | |
1393 | } | |
1394 | ||
1395 | ||
1396 | void showbits(FILE *f, struct entry *ep, int nbits, bits highlight) { | |
1397 | struct bits *bp; | |
1398 | bits i, value; | |
1399 | char zero, one; | |
1400 | ||
1401 | if (nbits == 0) | |
1402 | return; | |
1403 | i = 1 << (nbits - 1); | |
1404 | bp = ep->bits; | |
1405 | if (highlight) { | |
1406 | value = highlight; | |
1407 | zero = ' '; | |
1408 | one = '^'; | |
1409 | } else { | |
1410 | value = ep->value; | |
1411 | zero = '0'; | |
1412 | one = '1'; | |
1413 | } | |
1414 | do { | |
1415 | if (highlight != 0 || (ep->mask & i)) { | |
1416 | putc((value & i) ? one : zero, f); | |
1417 | i >>= 1; | |
1418 | } else { | |
1419 | assert(bp != NULL && (bp->mask & i)); | |
1420 | do { | |
1421 | putc(bp->name, f); | |
1422 | i >>= 1; | |
1423 | } while (bp->mask & i); | |
1424 | bp = bp->next; | |
1425 | } | |
1426 | } while (i != 0); | |
1427 | } | |
1428 | ||
1429 | ||
1430 | void showargs(FILE *f, struct arg *ap, int fieldwidth) { | |
1431 | int width; | |
1432 | int lastc; | |
1433 | int isint; | |
1434 | ||
1435 | if (ap == NULL) | |
1436 | width = 0; | |
1437 | else { | |
1438 | width = 1; | |
1439 | lastc = '('; | |
1440 | do { | |
1441 | isint = (ap->type == T_INTEGER); | |
1442 | fprintf(f, "%c%s%c", lastc, isint ? "%" : "", ap->name); | |
1443 | width += 2 + isint; | |
1444 | ap = ap->next; | |
1445 | lastc = ','; | |
1446 | } while (ap != NULL); | |
1447 | putc(')', f); | |
1448 | } | |
1449 | fprintf(f, "%-*s", fieldwidth - width, ""); | |
1450 | } | |
1451 | ||
1452 | ||
1453 | void showstring(FILE *f, struct string *sp) { | |
1454 | for ( ; sp != NULL; sp = sp->next) | |
1455 | showstringelement(f, sp); | |
1456 | } | |
1457 | ||
1458 | ||
1459 | void showstringelement(FILE *f, struct string *sp) { | |
1460 | struct bitsplice *bsp; | |
1461 | ||
1462 | switch (sp->type) { | |
1463 | case S_TEXT: | |
1464 | fputs(sp->value.text, f); | |
1465 | break; | |
1466 | case S_BITSTRING: | |
1467 | fprintf(f, "$%c", sp->value.bits->name); | |
1468 | break; | |
1469 | case S_BITSPLICE: | |
1470 | fprintf(f, "$["); | |
1471 | bsp = sp->value.bitsplice; | |
1472 | showbits(f, &bsp->entry, bsp->nbits, 0); | |
1473 | fprintf(f, "]"); | |
1474 | break; | |
1475 | case S_PARAMETER: | |
1476 | fprintf(f, "$%c", sp->value.parameter->name); | |
1477 | break; | |
1478 | case S_FUNCTIONCALL: | |
1479 | showfunctioncall(f, sp->value.functioncall); | |
1480 | break; | |
1481 | case S_ARRAY: | |
1482 | showarray(f, sp->value.array); | |
1483 | break; | |
1484 | default: | |
1485 | fprintf(stderr, "showstring case %d\n", sp->type); | |
1486 | abort(); | |
1487 | } | |
1488 | } | |
1489 | ||
1490 | ||
1491 | void showfunctioncall(FILE *f, struct functioncall *fcp) { | |
1492 | struct stringlist *sp; | |
1493 | char *last; | |
1494 | ||
1495 | fprintf(f, "$%s(", fcp->function->name); | |
1496 | last = ""; | |
1497 | for (sp = fcp->args; sp != NULL; sp = sp->next) { | |
1498 | fputs(last, f); | |
1499 | last = ","; | |
1500 | showstring(f, sp->string); | |
1501 | } | |
1502 | putc(')', f); | |
1503 | } | |
1504 | ||
1505 | ||
1506 | void showarray(FILE *f, struct array *ap) { | |
1507 | struct stringlist *sp; | |
1508 | char *last; | |
1509 | ||
1510 | putc('{'/*}*/, f); | |
1511 | last = ""; | |
1512 | for (sp = ap->elements; sp != NULL; sp = sp->next) { | |
1513 | fputs(last, f); | |
1514 | last = "|"; | |
1515 | showstring(f, sp->string); | |
1516 | } | |
1517 | fputs(/*{*/"}[", f); | |
1518 | showstring(f, ap->index); | |
1519 | putc(']', f); | |
1520 | } | |
1521 | ||
1522 | ||
1523 | const char commonpreamble[] = "\ | |
1524 | typedef %s bits;\n\ | |
1525 | \n\ | |
1526 | "; | |
1527 | ||
1528 | const char concatpreamble[] = "\ | |
1529 | static char *dis_buf;\n\ | |
1530 | static int dis_bufindex, dis_buflen;\n\ | |
1531 | \n\ | |
1532 | void *dis_alloc(size_t size)\n\ | |
1533 | {\n\ | |
1534 | void *p;\n\ | |
1535 | int newindex = dis_bufindex + size;\n\ | |
1536 | if (newindex > dis_buflen) {\n\ | |
1537 | dis_buflen = newindex * 4;\n\ | |
1538 | dis_buf = malloc(dis_buflen);\n\ | |
1539 | /* We can't use realloc because there might be pointers extant into\n\ | |
1540 | the old buffer. So we waste the memory of the old buffer. We\n\ | |
1541 | should soon reach an adequate buffer size and stop leaking. */\n\ | |
1542 | if (dis_buf == 0) {\n\ | |
1543 | perror(\"malloc\");\n\ | |
1544 | exit(1);\n\ | |
1545 | }\n\ | |
1546 | dis_bufindex = 0;\n\ | |
1547 | }\n\ | |
1548 | p = dis_buf + dis_bufindex;\n\ | |
1549 | dis_bufindex = newindex;\n\ | |
1550 | return p;\n\ | |
1551 | }\n\ | |
1552 | \n\ | |
1553 | void dis_done()\n\ | |
1554 | {\n\ | |
1555 | dis_bufindex = 0;\n\ | |
1556 | }\n\ | |
1557 | \n\ | |
1558 | "; | |
1559 | ||
1560 | const char concatdeclarations[] = "\ | |
1561 | #include <string.h>\n\ | |
1562 | #include <stdlib.h>\n\ | |
1563 | #include <errno.h>\n\ | |
1564 | \n\ | |
1565 | extern void *dis_realloc(void *p, size_t size); /* User-provided. */\n\ | |
1566 | void *dis_alloc(size_t size);\n\ | |
1567 | void dis_done(void);\n\ | |
1568 | "; | |
1569 | ||
1570 | const char nonconcatpreamble[] = "\ | |
1571 | void dis_done() {}\n\ | |
1572 | "; | |
1573 | ||
1574 | ||
1575 | int outputfunctions() { | |
1576 | struct function *fp; | |
1577 | ||
1578 | outputidentity(stdout); | |
1579 | if (headerfilename != NULL) { | |
1580 | if ((headerfile = fopen(headerfilename, "w")) == NULL) { | |
1581 | fprintf(stderr, "%s: create %s: %s\n", progname, headerfilename, | |
1582 | strerror(errno)); | |
1583 | return 1; | |
1584 | } | |
1585 | outputidentity(headerfile); | |
1586 | fprintf(headerfile, commonpreamble, bitstype); | |
1587 | printf("\n#include \"%s\"\n", headerfilename); | |
1588 | } else | |
1589 | printf(commonpreamble, bitstype); | |
1590 | findarrays(); | |
1591 | if (outputdeclarations() != 0) | |
1592 | return 1; | |
1593 | outputconcats(); | |
1594 | for (fp = functions; fp != NULL; fp = fp->next) { | |
1595 | if (fp->isarray) | |
1596 | functionarray(fp); | |
1597 | } | |
1598 | for (fp = functions; fp != NULL; fp = fp->next) { | |
1599 | if (fp->first != NULL && !fp->isarray) { | |
1600 | if (outputfunction(fp) != 0) | |
1601 | return 1; | |
1602 | } | |
1603 | } | |
1604 | return 0; | |
1605 | } | |
1606 | ||
1607 | ||
1608 | void outputidentity(FILE *f) { | |
1609 | char **p; | |
1610 | ||
1611 | fprintf(f, "/*\n * This file was generated by:\n *"); | |
1612 | for (p = global_argv; *p != NULL; p++) | |
1613 | fprintf(f, " %s", *p); | |
1614 | fprintf(f, "\n */\n\n"); | |
1615 | } | |
1616 | ||
1617 | ||
1618 | int outputdeclarations() { | |
1619 | FILE *f = headerfile ? headerfile : stdout; | |
1620 | struct function *fp; | |
1621 | ||
1622 | for (fp = functions; fp != NULL; fp = fp->next) { | |
1623 | if (fp->type != T_UNKNOWN) { | |
1624 | if (fp->isarray) { | |
1625 | fprintf(f, "extern "); | |
1626 | if (fp->fixedlength > 0) | |
1627 | fprintf(f, "char %s[][%d]", fp->name, fp->fixedlength); | |
1628 | else { | |
1629 | compiletype(f, &fp->type); | |
1630 | fprintf(f, "%s[]", fp->name); | |
1631 | } | |
1632 | } else | |
1633 | functionheader(f, fp); | |
1634 | fprintf(f, ";\n"); | |
1635 | } | |
1636 | } | |
1637 | return 0; | |
1638 | } | |
1639 | ||
1640 | ||
1641 | void outputconcats() { | |
1642 | int i; | |
1643 | ||
1644 | if (componentbits & ~3) { | |
1645 | fputs(concatdeclarations, headerfile ? headerfile : stdout); | |
1646 | fputs(concatpreamble, stdout); | |
1647 | } else | |
1648 | fputs(nonconcatpreamble, stdout); | |
1649 | for (i = 2; i < MAXBITS; i++) { | |
1650 | if (componentbits & (1 << i)) | |
1651 | outputconcat(i); | |
1652 | } | |
1653 | } | |
1654 | ||
1655 | ||
1656 | void outputconcat(int n) { | |
1657 | int i; | |
1658 | char *last; | |
1659 | ||
1660 | assert(n > 1); | |
1661 | if (headerfile) { | |
1662 | outputconcatheader(headerfile, n); | |
1663 | fprintf(headerfile, ";\n"); | |
1664 | } | |
1665 | outputconcatheader(stdout, n); | |
1666 | printf("\n{\n void *p;\n int len = "); | |
1667 | last = ""; | |
1668 | for (i = 0; i < n; i++) { | |
1669 | printf("%sstrlen(p%d)", last, i); | |
1670 | last = " + "; | |
1671 | } | |
1672 | printf(";\n p = dis_alloc(len + 1);\n return "); | |
1673 | for (i = 1; i < n; i++) | |
1674 | printf("strcat("); | |
1675 | printf("strcpy(p, p0)"); | |
1676 | for (i = 1; i < n; i++) | |
1677 | printf(", p%d)", i); | |
1678 | printf(";\n}\n\n"); | |
1679 | } | |
1680 | ||
1681 | ||
1682 | void outputconcatheader(FILE *f, int n) { | |
1683 | int i; | |
1684 | char *last = ""; | |
1685 | ||
1686 | fprintf(f, "char *dis_concat%d(", n); | |
1687 | for (i = 0; i < n; i++) { | |
1688 | fprintf(f, "%schar *p%d", last, i); | |
1689 | last = ", "; | |
1690 | } | |
1691 | fprintf(f, ")"); | |
1692 | } | |
1693 | ||
1694 | ||
1695 | void findarrays() { | |
1696 | struct function *fp; | |
1697 | struct entry *ep; | |
1698 | struct string *estr, *indexstr; | |
1699 | struct bits *bp; | |
1700 | ||
1701 | for (fp = functions; fp != NULL; fp = fp->next) { | |
1702 | if (fp->nbits > 0 && fp->nargs > 0) | |
1703 | continue; | |
1704 | if (fp->nargs > 1) | |
1705 | continue; | |
1706 | ep = fp->first; | |
1707 | if (ep == NULL || ep->next != NULL) | |
1708 | continue; | |
1709 | estr = ep->string; | |
1710 | if (estr == NULL || estr->next != NULL || estr->type != S_ARRAY) | |
1711 | continue; | |
1712 | indexstr = estr->value.array->index; | |
1713 | if (indexstr->next != NULL) | |
1714 | continue; | |
1715 | if (fp->nbits > 0) { | |
1716 | bp = ep->bits; | |
1717 | if (bp == NULL || bp->next != NULL || bp->shift != 0) | |
1718 | continue; | |
1719 | if (bp->mask != allbitsset(fp->nbits)) | |
1720 | continue; | |
1721 | if (indexstr->type != S_BITSTRING || indexstr->value.bits != bp) | |
1722 | continue; | |
1723 | } else { | |
1724 | if (indexstr->type != S_PARAMETER | |
1725 | || indexstr->value.parameter != fp->args) | |
1726 | continue; | |
1727 | } | |
1728 | if (!simplearray(estr->value.array)) | |
1729 | continue; | |
1730 | fp->isarray = 1; | |
1731 | fp->fixedlength = | |
1732 | (fp->type == T_INTEGER) ? 0 : checkfixedlength(estr->value.array); | |
1733 | } | |
1734 | } | |
1735 | ||
1736 | ||
1737 | int checkfixedlength(struct array *ap) { | |
1738 | int len, maxlen, wasted, n; | |
1739 | struct stringlist *lp; | |
1740 | ||
1741 | maxlen = 0; | |
1742 | for (lp = ap->elements; lp != NULL; lp = lp->next) { | |
1743 | if (lp->string == NULL) | |
1744 | continue; | |
1745 | assert(lp->string->type == S_TEXT); | |
1746 | len = strlen(lp->string->value.text); | |
1747 | if (len > maxlen) | |
1748 | maxlen = len; | |
1749 | } | |
1750 | for (wasted = n = 0, lp = ap->elements; lp != NULL; n++, lp = lp->next) { | |
1751 | if (lp->string == NULL) | |
1752 | continue; | |
1753 | wasted += maxlen - strlen(lp->string->value.text); | |
1754 | } | |
1755 | if (wasted < n * sizeof(char *)) /* Should be target's sizeof. */ | |
1756 | return maxlen + 1; | |
1757 | return 0; | |
1758 | } | |
1759 | ||
1760 | ||
1761 | int outputfunction(struct function *fp) { | |
1762 | printf("\n"); | |
1763 | functionheader(stdout, fp); | |
1764 | printf("\n{\n"/*}*/); | |
1765 | switch (functionswitch(fp, 0, 0)) { | |
1766 | case -1: | |
1767 | return 1; | |
1768 | case 0: | |
1769 | if (warnings) { | |
1770 | fprintf(stderr, "%s: warning: not all cases of %s covered\n", | |
1771 | progname, fp->name); | |
1772 | } | |
1773 | } | |
1774 | printf(/*{*/"}\n"); | |
1775 | return 0; | |
1776 | } | |
1777 | ||
1778 | ||
1779 | void functionarray(struct function *fp) { | |
1780 | struct array *ap; | |
1781 | ||
1782 | ap = fp->first->string->value.array; | |
1783 | printf("\n"); | |
1784 | compilesimplearray(&fp->type, fp->name, 0, ap); | |
1785 | } | |
1786 | ||
1787 | ||
1788 | void functionheader(FILE *f, struct function *fp) { | |
1789 | char *last; | |
1790 | struct arg *ap; | |
1791 | ||
1792 | compiletype(f, &fp->type); | |
1793 | fprintf(f, "%s(", fp->name); | |
1794 | last = ""; | |
1795 | if (fp->nbits > 0) { | |
1796 | fprintf(f, "bits code"); | |
1797 | last = ", "; | |
1798 | } | |
1799 | for (ap = fp->args; ap != NULL; ap = ap->next) { | |
1800 | fprintf(f, last); | |
1801 | compiletype(f, &ap->type); | |
1802 | putc(ap->name, f); | |
1803 | last = ", "; | |
1804 | } | |
1805 | if (*last == '\0') | |
1806 | fprintf(f, "void"); | |
1807 | putc(')', f); | |
1808 | } | |
1809 | ||
1810 | ||
1811 | int simplearray(struct array *ap) { | |
1812 | struct stringlist *lp; | |
1813 | ||
1814 | for (lp = ap->elements; lp != NULL; lp = lp->next) { | |
1815 | if (lp->string != NULL | |
1816 | && (lp->string->next != NULL || lp->string->type != S_TEXT)) | |
1817 | break; | |
1818 | } | |
1819 | return (lp == NULL); | |
1820 | } | |
1821 | ||
1822 | ||
1823 | void compiletype(FILE *f, enum type *tp) { | |
1824 | switch (*tp) { | |
1825 | case T_UNKNOWN: | |
1826 | *tp = T_STRING; | |
1827 | /* Fall in... */ | |
1828 | case T_STRING: | |
1829 | fprintf(f, "char *"); | |
1830 | break; | |
1831 | case T_INTEGER: | |
1832 | fprintf(f, "bits "); | |
1833 | break; | |
1834 | default: | |
1835 | fprintf(stderr, "compiletype type %d\n", *tp); | |
1836 | abort(); | |
1837 | } | |
1838 | } | |
1839 | ||
1840 | ||
1841 | /* Generate code for entries in function fp whose bitstring b satisfies | |
1842 | the constraint (b & mask) == value. Return 1 if generated switch | |
1843 | always does `return', 0 if not, -1 on error. | |
1844 | The algorithm is as follows. Scan the eligible entries to find the | |
1845 | largest set of bits not in the passed-in mask which always have a | |
1846 | constant value (are not variable). One `default' entry is allowed | |
1847 | all of whose bits are variable. For each value of the constant bits, | |
1848 | generate a `switch' case and invoke the function recursively with | |
1849 | that value included in the constraint parameters. The recursion | |
1850 | stops when no set of constant bits is found, perhaps because the | |
1851 | mask parameter has all bits set. | |
1852 | This algorithm could be improved. Currently it will fail if there | |
1853 | are input lines "xxyy", "00xx" and "yy00", each of which is default with | |
1854 | respect to the others. The correct behaviour would then be to select | |
1855 | a bit that is sometimes constant and deal with those cases first. | |
1856 | But this problem has not yet arisen in real life. */ | |
1857 | int functionswitch(struct function *fp, bits mask, bits value) { | |
1858 | struct entry *ep, *defaultcase; | |
1859 | bits allbits, constbits, missingcases; | |
1860 | int nhits, ncases, nconstbits, alwaysreturns; | |
1861 | ||
1862 | indentation++; | |
1863 | allbits = allbitsset(fp->nbits); | |
1864 | constbits = allbits & ~mask; | |
1865 | if (debug) { | |
1866 | findent(stderr); | |
1867 | fprintf(stderr, | |
1868 | "functionswitch(%s): (x & 0x%lx) == 0x%lx; const == 0x%lx\n", | |
1869 | fp->name, mask, value, constbits); | |
1870 | } | |
1871 | defaultcase = NULL; | |
1872 | ncases = nhits = 0; | |
1873 | alwaysreturns = 1; | |
1874 | for (ep = fp->first; ep != NULL; ep = ep->next) { | |
1875 | /* If this is not one of the entries under consideration, skip. */ | |
1876 | if (ep->done | |
1877 | || (ep->mask & mask) != mask || (ep->value & mask) != value) | |
1878 | continue; | |
1879 | if (debug) { | |
1880 | findent(stderr); | |
1881 | showentry(stderr, fp, ep, 0); | |
1882 | } | |
1883 | /* If this entry has no constant bits in the still-variable portion, | |
1884 | it's the default. */ | |
1885 | if ((constbits & ep->mask) == 0) { | |
1886 | if (defaultcase != NULL) { | |
1887 | fprintf(stderr, | |
1888 | "%s: function %s: unable to distinguish between:\n", | |
1889 | progname, fp->name); | |
1890 | showentry(stderr, fp, defaultcase, 0); | |
1891 | showentry(stderr, fp, ep, 0); | |
1892 | return -1; | |
1893 | } | |
1894 | defaultcase = ep; | |
1895 | if (debug) { | |
1896 | findent(stderr); | |
1897 | fprintf(stderr, "^^ default case\n"); | |
1898 | } | |
1899 | } else { | |
1900 | if (debug && (constbits & ~ep->mask)) { | |
1901 | findent(stderr); | |
1902 | fprintf(stderr, "const now 0x%lx\n", constbits & ep->mask); | |
1903 | } | |
1904 | constbits &= ep->mask; | |
1905 | nhits++; | |
1906 | } | |
1907 | } | |
1908 | if (nhits > 0) { | |
1909 | indent(); | |
1910 | if (constbits == allbits) | |
1911 | printf("switch (code) {\n"/*}*/); | |
1912 | else | |
1913 | printf("switch (code & 0x%lx) {\n"/*}*/, constbits); | |
1914 | for (ep = fp->first; ep != NULL; ep = ep->next) { | |
1915 | /* If this is not one of the entries under consideration, skip. */ | |
1916 | if ((ep->mask & mask) != mask || (ep->value & mask) != value) | |
1917 | continue; | |
1918 | if (ep->done || ep == defaultcase) | |
1919 | continue; | |
1920 | ncases++; | |
1921 | indent(); | |
1922 | printf("case 0x%lx:\n", ep->value & constbits); | |
1923 | switch (functionswitch(fp, mask | constbits, | |
1924 | value | (ep->value & constbits))) { | |
1925 | case -1: | |
1926 | return -1; | |
1927 | case 0: | |
1928 | alwaysreturns = 0; | |
1929 | indentation++; indent(); indentation--; | |
1930 | printf("break;\n"); | |
1931 | } | |
1932 | } | |
1933 | indent(); | |
1934 | printf(/*{*/"}\n"); | |
1935 | } | |
1936 | nconstbits = bitcount(constbits); | |
1937 | missingcases = ((nconstbits == MAXBITS) ? 0 : 1 << nconstbits) - ncases; | |
1938 | if (alwaysreturns) { | |
1939 | switch (missingcases) { | |
1940 | case 0: | |
1941 | if (defaultcase != NULL) { | |
1942 | fprintf(stderr, "%s: warning: redundant entry:\n", progname); | |
1943 | showentry(stderr, fp, defaultcase, 0); | |
1944 | defaultcase = NULL; | |
1945 | } | |
1946 | break; | |
1947 | case 1: | |
1948 | if (defaultcase != NULL && nconstbits != 0) { | |
1949 | fprintf(stderr, | |
1950 | "%s: warning: variable bit(s) could be constant:\n", | |
1951 | progname); | |
1952 | showentry(stderr, fp, defaultcase, constbits); | |
1953 | break; | |
1954 | } | |
1955 | /* Fall in... */ | |
1956 | default: | |
1957 | alwaysreturns = 0; | |
1958 | } | |
1959 | } | |
1960 | if (defaultcase != NULL) { | |
1961 | /* If defaultcase has some constant bits of its own, recursion will | |
1962 | check that they have the required value. */ | |
1963 | if ((defaultcase->mask & ~mask) == 0) { | |
1964 | alwaysreturns = 1; | |
1965 | if (compilestring(-1, defaultcase->string, fp->type) != 0) | |
1966 | return -1; | |
1967 | defaultcase->done = 1; | |
1968 | } else { | |
1969 | indentation--; | |
1970 | alwaysreturns = functionswitch(fp, mask, value); | |
1971 | indentation++; | |
1972 | } | |
1973 | } | |
1974 | indentation--; | |
1975 | return alwaysreturns; | |
1976 | } | |
1977 | ||
1978 | ||
1979 | int compilestring(int assignto, struct string *sp, enum type type) { | |
1980 | int tempno; | |
1981 | ||
1982 | tempno = walkstring(sp, COUNTARRAYS, assignto); | |
1983 | if (tempno > assignto) { | |
1984 | indent(); | |
1985 | printf("{\n"/*}*/); | |
1986 | indentation++; | |
1987 | (void) walkstring(sp, DECLAREARRAYS, assignto); | |
1988 | if (walkstring(sp, COMPILEARRAYS, assignto) < 0) | |
1989 | return 1; | |
1990 | } | |
1991 | if (compilecheckedstring(assignto, sp, type) != 0) | |
1992 | return 1; | |
1993 | if (tempno > assignto) { | |
1994 | indentation--; | |
1995 | indent(); | |
1996 | printf(/*{*/"}\n"); | |
1997 | } | |
1998 | return 0; | |
1999 | } | |
2000 | ||
2001 | ||
2002 | int compilecheckedstring(int assignto, struct string *sp, enum type type) { | |
2003 | compileassign(assignto); | |
2004 | if (compileconcat(sp, type) != 0) | |
2005 | return 1; | |
2006 | printf(";\n"); | |
2007 | return 0; | |
2008 | } | |
2009 | ||
2010 | ||
2011 | void compileassign(int assignto) { | |
2012 | indent(); | |
2013 | if (assignto < 0) | |
2014 | printf("return "); | |
2015 | else { | |
2016 | compiletemp(assignto); | |
2017 | printf(" = "); | |
2018 | } | |
2019 | } | |
2020 | ||
2021 | ||
2022 | void compiletemp(int tempno) { | |
2023 | printf("t__%d", tempno); | |
2024 | } | |
2025 | ||
2026 | ||
2027 | void compiletext(char *s) { | |
2028 | putchar('"'); | |
2029 | if (s != NULL) { | |
2030 | for ( ; *s != '\0'; s++) { | |
2031 | switch (*s) { | |
2032 | case '"': | |
2033 | case '\\': | |
2034 | putchar('\\'); | |
2035 | } | |
2036 | putchar(*s); | |
2037 | } | |
2038 | } | |
2039 | putchar('"'); | |
2040 | } | |
2041 | ||
2042 | ||
2043 | int compileconcat(struct string *sp, enum type type) { | |
2044 | int elements; | |
2045 | struct string *sp1; | |
2046 | char *last; | |
2047 | ||
2048 | if (sp == NULL) | |
2049 | return compilenull(type); | |
2050 | if (sp->next == NULL) | |
2051 | return compilesimple(sp, type); | |
2052 | if (type != T_INTEGER) { | |
2053 | for (elements = 0, sp1 = sp; sp1 != NULL; elements++, sp1 = sp1->next) ; | |
2054 | printf("dis_concat%d(", elements); | |
2055 | } | |
2056 | last = ""; | |
2057 | for (sp1 = sp; sp1 != NULL; sp1 = sp1->next) { | |
2058 | printf(last); | |
2059 | if (type != T_INTEGER) | |
2060 | last = ", "; | |
2061 | if (sp1->type == S_ARRAY) | |
2062 | compilearrayref(sp1->value.array); | |
2063 | else | |
2064 | if (compilesimple(sp1, type) != 0) | |
2065 | return 1; | |
2066 | } | |
2067 | if (type != T_INTEGER) | |
2068 | printf(")"); | |
2069 | return 0; | |
2070 | } | |
2071 | ||
2072 | ||
2073 | int compilenull(enum type type) { | |
2074 | if (type == T_INTEGER) { | |
2075 | fprintf(stderr, "%s: empty integer expression\n", progname); | |
2076 | return 1; | |
2077 | } | |
2078 | printf("\"\""); | |
2079 | return 0; | |
2080 | } | |
2081 | ||
2082 | ||
2083 | int compilesimple(struct string *sp, enum type type) { | |
2084 | if (sp == NULL) | |
2085 | return compilenull(type); | |
2086 | switch (sp->type) { | |
2087 | case S_TEXT: | |
2088 | if (type == T_INTEGER) | |
2089 | printf("%s", sp->value.text); | |
2090 | else | |
2091 | compiletext(sp->value.text); | |
2092 | break; | |
2093 | case S_BITSTRING: | |
2094 | compilebitstring(sp->value.bits); | |
2095 | break; | |
2096 | case S_BITSPLICE: | |
2097 | compilebitsplice(sp->value.bitsplice); | |
2098 | break; | |
2099 | case S_PARAMETER: | |
2100 | putchar(sp->value.parameter->name); | |
2101 | break; | |
2102 | case S_FUNCTIONCALL: | |
2103 | return compilefunctioncall(sp); | |
2104 | case S_ARRAY: | |
2105 | if (compilearrayref(sp->value.array) != 0) | |
2106 | return 1; | |
2107 | break; | |
2108 | default: | |
2109 | fprintf(stderr, "compilesimple case %d", sp->type); | |
2110 | abort(); | |
2111 | } | |
2112 | return 0; | |
2113 | } | |
2114 | ||
2115 | ||
2116 | int compilearrayref(struct array *ap) { | |
2117 | compiletemp(ap->tempno); | |
2118 | if (simplearray(ap)) { | |
2119 | printf("["); | |
2120 | if (compileconcat(ap->index, T_INTEGER) != 0) | |
2121 | return 1; | |
2122 | printf("]"); | |
2123 | } | |
2124 | return 0; | |
2125 | } | |
2126 | ||
2127 | ||
2128 | int compilefunctioncall(struct string *sp) { | |
2129 | struct function *fp; | |
2130 | struct stringlist *actualp; | |
2131 | struct arg *formalp; | |
2132 | char *last; | |
2133 | int nbits; | |
2134 | enum type formaltype; | |
2135 | ||
2136 | assert(sp->type == S_FUNCTIONCALL); | |
2137 | fp = sp->value.functioncall->function; | |
2138 | printf("%s%c", fp->name, fp->isarray ? '[' : '('); | |
2139 | last = ""; | |
2140 | nbits = fp->nbits; | |
2141 | formalp = fp->args; | |
2142 | actualp = sp->value.functioncall->args; | |
2143 | while (actualp != NULL) { | |
2144 | if (nbits > 0) { | |
2145 | nbits = 0; | |
2146 | formaltype = T_INTEGER; | |
2147 | } else { | |
2148 | if (formalp == NULL) { | |
2149 | fprintf(stderr, "%s: too many arguments to %s:\n", progname, | |
2150 | fp->name); | |
2151 | showstring(stderr, sp); | |
2152 | putc('\n', stderr); | |
2153 | return 1; | |
2154 | } | |
2155 | formaltype = formalp->type; | |
2156 | formalp = formalp->next; | |
2157 | } | |
2158 | if (actualp->type != T_UNKNOWN && actualp->type != formaltype) { | |
2159 | fprintf(stderr, "%s: argument to %s has the wrong type:\n", | |
2160 | progname, fp->name); | |
2161 | showstring(stderr, actualp->string); | |
2162 | putc('\n', stderr); | |
2163 | return 1; | |
2164 | } | |
2165 | printf(last); | |
2166 | last = ", "; | |
2167 | if (compileconcat(actualp->string, formaltype) != 0) | |
2168 | return 1; | |
2169 | actualp = actualp->next; | |
2170 | } | |
2171 | putchar(fp->isarray ? ']' : ')'); | |
2172 | return 0; | |
2173 | } | |
2174 | ||
2175 | ||
2176 | int walkstring(struct string *sp, enum walkstringop op, int tempno) { | |
2177 | struct stringlist *lp; | |
2178 | struct array *ap; | |
2179 | ||
2180 | for ( ; sp != NULL; sp = sp->next) { | |
2181 | switch (sp->type) { | |
2182 | case S_ARRAY: | |
2183 | ap = sp->value.array; | |
2184 | for (lp = ap->elements; lp != NULL; lp = lp->next) | |
2185 | tempno = walkstring(lp->string, op, tempno); | |
2186 | tempno = walkstring(ap->index, op, tempno); | |
2187 | ap->tempno = ++tempno; | |
2188 | switch (op) { | |
2189 | case DECLAREARRAYS: | |
2190 | if (simplearray(ap)) { | |
2191 | indent(); | |
2192 | printf("static "); | |
2193 | compilesimplearray(&ap->type, NULL, tempno, ap); | |
2194 | } else | |
2195 | declarearray(ap); | |
2196 | break; | |
2197 | case COMPILEARRAYS: | |
2198 | if (!simplearray(ap)) | |
2199 | if (compilearray(ap) != 0) | |
2200 | return -1; | |
2201 | break; | |
2202 | default: | |
2203 | break; | |
2204 | } | |
2205 | break; | |
2206 | case S_FUNCTIONCALL: | |
2207 | for (lp = sp->value.functioncall->args; lp != NULL; lp = lp->next) | |
2208 | tempno = walkstring(lp->string, op, tempno); | |
2209 | break; | |
2210 | default: | |
2211 | break; | |
2212 | } | |
2213 | } | |
2214 | return tempno; | |
2215 | } | |
2216 | ||
2217 | ||
2218 | int compilearray(struct array *ap) { | |
2219 | struct stringlist *ep; | |
2220 | int i; | |
2221 | ||
2222 | indent(); | |
2223 | printf("switch ("); | |
2224 | if (compileconcat(ap->index, T_INTEGER) != 0) | |
2225 | return 1; | |
2226 | printf(") {\n"/*}*/); | |
2227 | for (i = 0, ep = ap->elements; ep != NULL; i++, ep = ep->next) { | |
2228 | indent(); | |
2229 | printf("case %d:\n", i); | |
2230 | indentation++; | |
2231 | if (compilecheckedstring(ap->tempno, ep->string, ap->type) != 0) | |
2232 | return 1; | |
2233 | indent(); | |
2234 | printf("break;\n"); | |
2235 | indentation--; | |
2236 | } | |
2237 | indent(); | |
2238 | printf(/*{*/"}\n"); | |
2239 | return 0; | |
2240 | } | |
2241 | ||
2242 | ||
2243 | void compilesimplearray(enum type *tp, char *name, int num, struct array *ap) { | |
2244 | struct stringlist *lp; | |
2245 | int fixedlength; | |
2246 | ||
2247 | fixedlength = (*tp == T_INTEGER) ? 0 : checkfixedlength(ap); | |
2248 | if (fixedlength > 0) | |
2249 | printf("char "); | |
2250 | else | |
2251 | compiletype(stdout, tp); | |
2252 | if (name != NULL) | |
2253 | printf(name); | |
2254 | else | |
2255 | compiletemp(num); | |
2256 | printf("[]"); | |
2257 | if (fixedlength > 0) | |
2258 | printf("[%d]", fixedlength); | |
2259 | printf(" = {\n"/*}*/); | |
2260 | indentation++; | |
2261 | for (lp = ap->elements; lp != NULL; lp = lp->next) { | |
2262 | indent(); | |
2263 | compilesimple(lp->string, lp->type); | |
2264 | printf(",\n"); | |
2265 | } | |
2266 | indentation--; | |
2267 | indent(); | |
2268 | printf(/*{*/"};\n"); | |
2269 | } | |
2270 | ||
2271 | ||
2272 | void declarearray(struct array *ap) { | |
2273 | indent(); | |
2274 | compiletype(stdout, &ap->type); | |
2275 | compiletemp(ap->tempno); | |
2276 | printf(";\n"); | |
2277 | } | |
2278 | ||
2279 | ||
2280 | void compilebitstring(struct bits *bp) { | |
2281 | printf("("); | |
2282 | if (bp->shift != 0) | |
2283 | printf("("); | |
2284 | printf("code & 0x%lx", bp->mask); | |
2285 | if (bp->shift != 0) | |
2286 | printf(") >> %d", bp->shift); | |
2287 | printf(")"); | |
2288 | } | |
2289 | ||
2290 | ||
2291 | void compilebitsplice(struct bitsplice *splicep) { | |
2292 | struct bitsplicebits *bsp; | |
2293 | char *last = ""; | |
2294 | ||
2295 | printf("("); | |
2296 | for (bsp = splicep->splice; bsp != NULL; bsp = bsp->next) { | |
2297 | printf(last); | |
2298 | last = " | "; | |
2299 | if (bsp->type == S_PARAMETER) | |
2300 | putchar(bsp->value.arg->name); | |
2301 | else { | |
2302 | assert(bsp->type == S_BITSTRING); | |
2303 | if (bsp->value.mask == 0) | |
2304 | printf("code"); | |
2305 | else | |
2306 | printf("(code & 0x%lx)", bsp->value.mask); | |
2307 | } | |
2308 | if (bsp->shift > 0) | |
2309 | printf(" << %d", bsp->shift); | |
2310 | else if (bsp->shift < 0) | |
2311 | printf(" >> %d", -bsp->shift); | |
2312 | } | |
2313 | if (splicep->entry.value != 0) | |
2314 | printf("%s0x%lx", last, splicep->entry.value); | |
2315 | printf(")"); | |
2316 | } | |
2317 | ||
2318 | ||
2319 | int bitcount(bits x) { | |
2320 | int nbits; | |
2321 | ||
2322 | for (nbits = 0; x != 0; x >>= 1) { | |
2323 | if (x & 1) | |
2324 | nbits++; | |
2325 | } | |
2326 | return nbits; | |
2327 | } | |
2328 | ||
2329 | ||
2330 | bits allbitsset(int nbits) { | |
2331 | return (nbits == MAXBITS) ? ~0 : (1 << nbits) - 1; | |
2332 | } | |
2333 | ||
2334 | ||
2335 | void findent(FILE *f) { | |
2336 | int i; | |
2337 | ||
2338 | for (i = 1; i < indentation; i += 2) | |
2339 | putc('\t', f); | |
2340 | if (i == indentation) | |
2341 | fputs(" ", f); | |
2342 | } | |
2343 | ||
2344 | ||
2345 | void indent() { | |
2346 | findent(stdout); | |
2347 | } | |
2348 | ||
2349 | ||
2350 | void *xrealloc(char *oldp, size_t size) { | |
2351 | void *p; | |
2352 | ||
2353 | if (oldp == NULL) | |
2354 | p = malloc(size); | |
2355 | else | |
2356 | p = realloc(oldp, size); | |
2357 | if (p == NULL) { | |
2358 | fprintf(stderr, "%s: allocate of %d bytes failed: %s\n", progname, | |
2359 | (int) size, strerror(errno)); | |
2360 | exit(1); | |
2361 | } | |
2362 | return p; | |
2363 | } | |
2364 | ||
2365 | ||
2366 | void *xmalloc(size_t size) { | |
2367 | return xrealloc(NULL, size); | |
2368 | } | |
2369 | ||
2370 | ||
2371 | void *xstrdup(char *s) { | |
2372 | char *p; | |
2373 | ||
2374 | p = xmalloc(strlen(s) + 1); | |
2375 | strcpy(p, s); | |
2376 | return p; | |
2377 | } | |
2378 | ||
2379 | ||
2380 | int prematureeof() { | |
2381 | fprintf(stderr, "%s: %s(%d): premature end of file\n", progname, filename, | |
2382 | lineno); | |
2383 | return 1; | |
2384 | } |