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