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