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