1 /***** spin: main.c *****/
3 /* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */
4 /* All Rights Reserved. This software is for educational purposes only. */
5 /* No guarantee whatsoever is expressed or implied by the distribution of */
6 /* this code. Permission is given to distribute this code provided that */
7 /* this introductory message is not removed and no monies are exchanged. */
8 /* Software written by Gerard J. Holzmann. For tool documentation see: */
9 /* http://spinroot.com/ */
10 /* Send all bug-reports and/or questions to: bugs@spinroot.com */
16 /* #include <malloc.h> */
20 extern int unlink(const char *);
26 extern int DstepStart
, lineno
, tl_terse
;
27 extern FILE *yyin
, *yyout
, *tl_out
;
28 extern Symbol
*context
;
29 extern char *claimproc
;
30 extern void repro_src(void);
31 extern void qhide(int);
33 Symbol
*Fname
, *oFname
;
35 int Etimeouts
; /* nr timeouts in program */
36 int Ntimeouts
; /* nr timeouts in never claim */
37 int analyze
, columns
, dumptab
, has_remote
, has_remvar
;
38 int interactive
, jumpsteps
, m_loss
, nr_errs
, cutoff
;
39 int s_trail
, ntrail
, verbose
, xspin
, notabs
, rvopt
;
40 int no_print
, no_wrapup
, Caccess
, limited_vis
, like_java
;
41 int separate
; /* separate compilation */
42 int export_ast
; /* pangen5.c */
44 int merger
= 1, deadvar
= 1, ccache
= 1;
46 static int preprocessonly
, SeedUsed
;
47 static int seedy
; /* be verbose about chosen seed */
48 static int inlineonly
; /* show inlined code */
49 static int dataflow
= 1;
52 meaning of flags on verbose
:
53 1 -g global variable values
54 2 -l local variable values
55 4 -p all process actions
62 static char Operator
[] = "operator: ";
63 static char Keyword
[] = "keyword: ";
64 static char Function
[] = "function-name: ";
65 static char **add_ltl
= (char **)0;
66 static char **ltl_file
= (char **)0;
67 static char **nvr_file
= (char **)0;
68 static char *PreArg
[64];
69 static int PreCnt
= 0;
74 /* OS2: "spin -Picc -E/Pd+ -E/Q+" */
75 /* Visual C++: "spin -PCL -E/E */
77 #define CPP "gcc -E -x c" /* most systems have gcc anyway */
81 #define CPP "/usr/ccs/lib/cpp"
83 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
86 #define CPP "/lib/cpp" /* classic Unix systems */
92 static char *PreProc
= CPP
;
93 extern int depth
; /* at least some steps were made */
98 if (preprocessonly
== 0
100 (void) unlink((const char *)out1
);
102 if (seedy
&& !analyze
&& !export_ast
103 && !s_trail
&& !preprocessonly
&& depth
> 0)
104 printf("seed used: %d\n", SeedUsed
);
106 if (xspin
&& (analyze
|| s_trail
))
108 printf("spin: %d error(s) - aborting\n",
111 printf("Exit-Status 0\n");
117 preprocess(char *a
, char *b
, int a_tmp
)
118 { char precmd
[1024], cmd
[2048]; int i
;
120 extern int try_zpp(char *, char *);
121 if (PreCnt
== 0 && try_zpp(a
, b
)) goto out
;
123 strcpy(precmd
, PreProc
);
124 for (i
= 1; i
<= PreCnt
; i
++)
125 { strcat(precmd
, " ");
126 strcat(precmd
, PreArg
[i
]);
128 if (strlen(precmd
) > sizeof(precmd
))
129 { fprintf(stdout
, "spin: too many -D args, aborting\n");
132 sprintf(cmd
, "%s %s > %s", precmd
, a
, b
);
133 if (system((const char *)cmd
))
134 { (void) unlink((const char *) b
);
135 if (a_tmp
) (void) unlink((const char *) a
);
136 fprintf(stdout
, "spin: preprocessing failed\n"); /* 4.1.2 was stderr */
137 alldone(1); /* no return, error exit */
142 if (a_tmp
) (void) unlink((const char *) a
);
146 cpyfile(char *src
, char *tgt
)
150 inp
= fopen(src
, "r");
151 out
= fopen(tgt
, "w");
153 { printf("spin: cannot cp %s to %s\n", src
, tgt
);
156 while (fgets(buf
, 1024, inp
))
157 fprintf(out
, "%s", buf
);
165 printf("use: spin [-option] ... [-option] file\n");
166 printf("\tNote: file must always be the last argument\n");
167 printf("\t-A apply slicing algorithm\n");
168 printf("\t-a generate a verifier in pan.c\n");
169 printf("\t-B no final state details in simulations\n");
170 printf("\t-b don't execute printfs in simulation\n");
171 printf("\t-C print channel access info (combine with -g etc.)\n");
172 printf("\t-c columnated -s -r simulation output\n");
173 printf("\t-d produce symbol-table information\n");
174 printf("\t-Dyyy pass -Dyyy to the preprocessor\n");
175 printf("\t-Eyyy pass yyy to the preprocessor\n");
176 printf("\t-f \"..formula..\" translate LTL ");
177 printf("into never claim\n");
178 printf("\t-F file like -f, but with the LTL ");
179 printf("formula stored in a 1-line file\n");
180 printf("\t-g print all global variables\n");
181 printf("\t-h at end of run, print value of seed for random nr generator used\n");
182 printf("\t-i interactive (random simulation)\n");
183 printf("\t-I show result of inlining and preprocessing\n");
184 printf("\t-J reverse eval order of nested unlesses\n");
185 printf("\t-jN skip the first N steps ");
186 printf("in simulation trail\n");
187 printf("\t-l print all local variables\n");
188 printf("\t-M print msc-flow in Postscript\n");
189 printf("\t-m lose msgs sent to full queues\n");
190 printf("\t-N file use never claim stored in file\n");
191 printf("\t-nN seed for random nr generator\n");
192 printf("\t-o1 turn off dataflow-optimizations in verifier\n");
193 printf("\t-o2 don't hide write-only variables in verifier\n");
194 printf("\t-o3 turn off statement merging in verifier\n");
195 printf("\t-Pxxx use xxx for preprocessing\n");
196 printf("\t-p print all statements\n");
197 printf("\t-qN suppress io for queue N in printouts\n");
198 printf("\t-r print receive events\n");
199 printf("\t-S1 and -S2 separate pan source for claim and model\n");
200 printf("\t-s print send events\n");
201 printf("\t-T do not indent printf output\n");
202 printf("\t-t[N] follow [Nth] simulation trail\n");
203 printf("\t-Uyyy pass -Uyyy to the preprocessor\n");
204 printf("\t-uN stop a simulation run after N steps\n");
205 printf("\t-v verbose, more warnings\n");
206 printf("\t-w very verbose (when combined with -l or -g)\n");
207 printf("\t-[XYZ] reserved for use by xspin interface\n");
208 printf("\t-V print version number and exit\n");
213 optimizations(int nr
)
217 dataflow
= 1 - dataflow
; /* dataflow */
219 printf("spin: dataflow optimizations turned %s\n",
220 dataflow
?"on":"off");
223 /* dead variable elimination */
224 deadvar
= 1 - deadvar
;
226 printf("spin: dead variable elimination turned %s\n",
230 /* statement merging */
233 printf("spin: statement merging turned %s\n",
238 /* rv optimization */
241 printf("spin: rendezvous optimization turned %s\n",
248 printf("spin: case caching turned %s\n",
252 printf("spin: bad or missing parameter on -o\n");
260 Rename(const char *old
, char *new)
264 if ((fo
= fopen(old
, "r")) == NULL
)
265 { printf("spin: cannot open %s\n", old
);
268 if ((fn
= fopen(new, "w")) == NULL
)
269 { printf("spin: cannot create %s\n", new);
273 while (fgets(buf
, 1024, fo
))
279 return 0; /* success */
284 main(int argc
, char *argv
[])
286 int T
= (int) time((time_t *)0);
288 extern void ana_src(int, int);
294 /* unused flags: e, w, x, y, z, A, G, I, L, O, Q, R, S, T, W */
295 while (argc
> 1 && argv
[1][0] == '-')
296 { switch (argv
[1][1]) {
298 /* generate code for separate compilation: S1 or S2 */
299 case 'S': separate
= atoi(&argv
[1][2]);
301 case 'a': analyze
= 1; break;
303 case 'A': export_ast
= 1; break;
304 case 'B': no_wrapup
= 1; break;
305 case 'b': no_print
= 1; break;
306 case 'C': Caccess
= 1; break;
307 case 'c': columns
= 1; break;
308 case 'D': PreArg
[++PreCnt
] = (char *) &argv
[1][0];
310 case 'd': dumptab
= 1; break;
311 case 'E': PreArg
[++PreCnt
] = (char *) &argv
[1][2];
313 case 'F': ltl_file
= (char **) (argv
+2);
314 argc
--; argv
++; break;
315 case 'f': add_ltl
= (char **) argv
;
316 argc
--; argv
++; break;
317 case 'g': verbose
+= 1; break;
318 case 'h': seedy
= 1; break;
319 case 'i': interactive
= 1; break;
320 case 'I': inlineonly
= 1; break;
321 case 'J': like_java
= 1; break;
322 case 'j': jumpsteps
= atoi(&argv
[1][2]); break;
323 case 'l': verbose
+= 2; break;
324 case 'M': columns
= 2; break;
325 case 'm': m_loss
= 1; break;
326 case 'N': nvr_file
= (char **) (argv
+2);
327 argc
--; argv
++; break;
328 case 'n': T
= atoi(&argv
[1][2]); tl_terse
= 1; break;
329 case 'o': optimizations(argv
[1][2]);
331 case 'P': PreProc
= (char *) &argv
[1][2]; break;
332 case 'p': verbose
+= 4; break;
333 case 'q': if (isdigit(argv
[1][2]))
334 qhide(atoi(&argv
[1][2]));
336 case 'r': verbose
+= 8; break;
337 case 's': verbose
+= 16; break;
338 case 'T': notabs
= 1; break;
339 case 't': s_trail
= 1;
340 if (isdigit(argv
[1][2]))
341 ntrail
= atoi(&argv
[1][2]);
343 case 'U': PreArg
[++PreCnt
] = (char *) &argv
[1][0];
344 break; /* undefine */
345 case 'u': cutoff
= atoi(&argv
[1][2]); break; /* new 3.4.14 */
346 case 'v': verbose
+= 32; break;
347 case 'V': printf("%s\n", SpinVersion
);
350 case 'w': verbose
+= 64; break;
351 case 'X': xspin
= notabs
= 1;
353 signal(SIGPIPE
, alldone
); /* not posix... */
356 case 'Y': limited_vis
= 1; break; /* used by xspin */
357 case 'Z': preprocessonly
= 1; break; /* used by xspin */
359 default : usage(); break;
363 if (usedopts
&& !analyze
)
364 printf("spin: warning -o[123] option ignored in simulations\n");
367 { char formula
[4096];
368 add_ltl
= ltl_file
-2; add_ltl
[1][1] = 'f';
369 if (!(tl_out
= fopen(*ltl_file
, "r")))
370 { printf("spin: cannot open %s\n", *ltl_file
);
373 fgets(formula
, 4096, tl_out
);
376 *ltl_file
= (char *) formula
;
379 { char cmd
[128], out2
[64];
381 /* must remain in current dir */
382 strcpy(out1
, "pan.pre");
384 if (add_ltl
|| nvr_file
)
385 strcpy(out2
, "pan.___");
388 { tl_out
= cpyfile(argv
[1], out2
);
389 nr_errs
= tl_main(2, add_ltl
); /* in tl_main.c */
391 preprocess(out2
, out1
, 1);
393 { FILE *fd
; char buf
[1024];
395 if ((fd
= fopen(*nvr_file
, "r")) == NULL
)
396 { printf("spin: cannot open %s\n",
400 tl_out
= cpyfile(argv
[1], out2
);
401 while (fgets(buf
, 1024, fd
))
402 fprintf(tl_out
, "%s", buf
);
405 preprocess(out2
, out1
, 1);
407 preprocess(argv
[1], out1
, 0);
412 if (!(yyin
= fopen(out1
, "r")))
413 { printf("spin: cannot open %s\n", out1
);
417 if (strncmp(argv
[1], "progress", (size_t) 8) == 0
418 || strncmp(argv
[1], "accept", (size_t) 6) == 0)
419 sprintf(cmd
, "_%s", argv
[1]);
421 strcpy(cmd
, argv
[1]);
422 oFname
= Fname
= lookup(cmd
);
423 if (oFname
->name
[0] == '\"')
424 { int i
= (int) strlen(oFname
->name
);
425 oFname
->name
[i
-1] = '\0';
426 oFname
= lookup(&oFname
->name
[1]);
429 { oFname
= Fname
= lookup("<stdin>");
432 exit(tl_main(2, add_ltl
));
433 printf("spin: missing argument to -f\n");
436 printf("%s\n", SpinVersion
);
437 printf("reading input from stdin:\n");
441 { extern void putprelude(void);
442 if (xspin
|| verbose
&(1|4|8|16|32))
443 { printf("spin: -c precludes all flags except -t\n");
448 if (columns
&& !(verbose
&8) && !(verbose
&16))
450 if (columns
== 2 && limited_vis
)
452 Srand((unsigned int) T
); /* defined in run.c */
454 s
= lookup("_"); s
->type
= PREDEF
; /* write-only global var */
455 s
= lookup("_p"); s
->type
= PREDEF
;
456 s
= lookup("_pid"); s
->type
= PREDEF
;
457 s
= lookup("_last"); s
->type
= PREDEF
;
458 s
= lookup("_nr_pr"); s
->type
= PREDEF
; /* new 3.3.10 */
471 { if (!s_trail
&& (dataflow
|| merger
))
472 ana_src(dataflow
, merger
);
480 yywrap(void) /* dummy routine */
486 non_fatal(char *s1
, char *s2
)
487 { extern int yychar
; extern char yytext
[];
489 printf("spin: line %3d %s, Error: ",
490 lineno
, Fname
?Fname
->name
:"nofilename");
495 if (yychar
!= -1 && yychar
!= 0)
500 if (strlen(yytext
)>1)
501 printf(" near '%s'", yytext
);
507 fatal(char *s1
, char *s2
)
518 return NULL
; /* robert shelton 10/20/06 */
520 if (!(tmp
= (char *) malloc(n
)))
521 fatal("not enough memory", (char *)0);
527 trapwonly(Lextok
*n
/* , char *unused */)
528 { extern int realread
;
529 short i
= (n
->sym
)?n
->sym
->type
:0;
540 n
->sym
->hidden
|= 128; /* var is read at least once */
544 setaccess(Symbol
*sp
, Symbol
*what
, int cnt
, int t
)
547 for (a
= sp
->access
; a
; a
= a
->lnk
)
548 if (a
->who
== context
554 a
= (Access
*) emalloc(sizeof(Access
));
564 nn(Lextok
*s
, int t
, Lextok
*ll
, Lextok
*rl
)
565 { Lextok
*n
= (Lextok
*) emalloc(sizeof(Lextok
));
566 static int warn_nn
= 0;
572 } else if (rl
&& rl
->fn
)
575 } else if (ll
&& ll
->fn
)
582 if (s
) n
->sym
= s
->sym
;
585 n
->indstep
= DstepStart
;
587 if (t
== TIMEOUT
) Etimeouts
++;
589 if (!context
) return n
;
591 if (t
== 'r' || t
== 's')
592 setaccess(n
->sym
, ZS
, 0, t
);
594 setaccess(n
->sym
, ZS
, 0, 'P');
596 if (context
->name
== claimproc
)
597 { int forbidden
= separate
;
600 printf("spin: Warning, never claim has side-effect\n");
603 non_fatal("never claim contains i/o stmnts",(char *)0);
606 /* never claim polls timeout */
607 if (Ntimeouts
&& Etimeouts
)
609 Ntimeouts
++; Etimeouts
--;
611 case LEN
: case EMPTY
: case FULL
:
612 case 'R': case NFULL
: case NEMPTY
:
613 /* status becomes non-exclusive */
614 if (n
->sym
&& !(n
->sym
->xu
&XX
))
617 printf("spin: warning, make sure that the S1 model\n");
618 printf(" also polls channel '%s' in its claim\n",
624 AST_track(n
, 0); /* register as a slice criterion */
631 { printf("spin: never, saw "); explain(t
); printf("\n");
632 fatal("incompatible with separate compilation",(char *)0);
634 } else if ((t
== ENABLED
|| t
== PC_VAL
) && !(warn_nn
&t
))
635 { printf("spin: Warning, using %s outside never claim\n",
636 (t
== ENABLED
)?"enabled()":"pc_value()");
638 } else if (t
== NONPROGRESS
)
639 { fatal("spin: Error, using np_ outside never claim\n", (char *)0);
645 rem_lab(Symbol
*a
, Lextok
*b
, Symbol
*c
) /* proctype name, pid, label name */
646 { Lextok
*tmp1
, *tmp2
, *tmp3
;
649 c
->type
= LABEL
; /* refered to in global context here */
650 fix_dest(c
, a
); /* in case target of rem_lab is jump */
651 tmp1
= nn(ZN
, '?', b
, ZN
); tmp1
->sym
= a
;
652 tmp1
= nn(ZN
, 'p', tmp1
, ZN
);
653 tmp1
->sym
= lookup("_p");
654 tmp2
= nn(ZN
, NAME
, ZN
, ZN
); tmp2
->sym
= a
;
655 tmp3
= nn(ZN
, 'q', tmp2
, ZN
); tmp3
->sym
= c
;
656 return nn(ZN
, EQ
, tmp1
, tmp3
);
658 .---------------EQ
-------.
660 'p' -sym
-> _p
'q' -sym
-> c (label name
)
662 '?' -sym
-> a (proctype
) NAME
-sym
-> a (proctype name
)
669 rem_var(Symbol
*a
, Lextok
*b
, Symbol
*c
, Lextok
*ndx
)
674 dataflow
= 0; /* turn off dead variable resets 4.2.5 */
675 tmp1
= nn(ZN
, '?', b
, ZN
); tmp1
->sym
= a
;
676 tmp1
= nn(ZN
, 'p', tmp1
, ndx
);
680 cannot refer to
struct elements
681 only to scalars
and arrays
683 'p' -sym
-> c (variable name
)
684 / \______ possible arrayindex on c
686 '?' -sym
-> a (proctype
)
696 default: if (n
> 0 && n
< 256)
697 fprintf(fd
, "'%c' = '", n
);
698 fprintf(fd
, "%d'", n
);
700 case '\b': fprintf(fd
, "\\b"); break;
701 case '\t': fprintf(fd
, "\\t"); break;
702 case '\f': fprintf(fd
, "\\f"); break;
703 case '\n': fprintf(fd
, "\\n"); break;
704 case '\r': fprintf(fd
, "\\r"); break;
705 case 'c': fprintf(fd
, "condition"); break;
706 case 's': fprintf(fd
, "send"); break;
707 case 'r': fprintf(fd
, "recv"); break;
708 case 'R': fprintf(fd
, "recv poll %s", Operator
); break;
709 case '@': fprintf(fd
, "@"); break;
710 case '?': fprintf(fd
, "(x->y:z)"); break;
711 case ACTIVE
: fprintf(fd
, "%sactive", Keyword
); break;
712 case AND
: fprintf(fd
, "%s&&", Operator
); break;
713 case ASGN
: fprintf(fd
, "%s=", Operator
); break;
714 case ASSERT
: fprintf(fd
, "%sassert", Function
); break;
715 case ATOMIC
: fprintf(fd
, "%satomic", Keyword
); break;
716 case BREAK
: fprintf(fd
, "%sbreak", Keyword
); break;
717 case C_CODE
: fprintf(fd
, "%sc_code", Keyword
); break;
718 case C_DECL
: fprintf(fd
, "%sc_decl", Keyword
); break;
719 case C_EXPR
: fprintf(fd
, "%sc_expr", Keyword
); break;
720 case C_STATE
: fprintf(fd
, "%sc_state",Keyword
); break;
721 case C_TRACK
: fprintf(fd
, "%sc_track",Keyword
); break;
722 case CLAIM
: fprintf(fd
, "%snever", Keyword
); break;
723 case CONST
: fprintf(fd
, "a constant"); break;
724 case DECR
: fprintf(fd
, "%s--", Operator
); break;
725 case D_STEP
: fprintf(fd
, "%sd_step", Keyword
); break;
726 case D_PROCTYPE
: fprintf(fd
, "%sd_proctype", Keyword
); break;
727 case DO
: fprintf(fd
, "%sdo", Keyword
); break;
728 case DOT
: fprintf(fd
, "."); break;
729 case ELSE
: fprintf(fd
, "%selse", Keyword
); break;
730 case EMPTY
: fprintf(fd
, "%sempty", Function
); break;
731 case ENABLED
: fprintf(fd
, "%senabled",Function
); break;
732 case EQ
: fprintf(fd
, "%s==", Operator
); break;
733 case EVAL
: fprintf(fd
, "%seval", Function
); break;
734 case FI
: fprintf(fd
, "%sfi", Keyword
); break;
735 case FULL
: fprintf(fd
, "%sfull", Function
); break;
736 case GE
: fprintf(fd
, "%s>=", Operator
); break;
737 case GOTO
: fprintf(fd
, "%sgoto", Keyword
); break;
738 case GT
: fprintf(fd
, "%s>", Operator
); break;
739 case HIDDEN
: fprintf(fd
, "%shidden", Keyword
); break;
740 case IF
: fprintf(fd
, "%sif", Keyword
); break;
741 case INCR
: fprintf(fd
, "%s++", Operator
); break;
742 case INAME
: fprintf(fd
, "inline name"); break;
743 case INLINE
: fprintf(fd
, "%sinline", Keyword
); break;
744 case INIT
: fprintf(fd
, "%sinit", Keyword
); break;
745 case ISLOCAL
: fprintf(fd
, "%slocal", Keyword
); break;
746 case LABEL
: fprintf(fd
, "a label-name"); break;
747 case LE
: fprintf(fd
, "%s<=", Operator
); break;
748 case LEN
: fprintf(fd
, "%slen", Function
); break;
749 case LSHIFT
: fprintf(fd
, "%s<<", Operator
); break;
750 case LT
: fprintf(fd
, "%s<", Operator
); break;
751 case MTYPE
: fprintf(fd
, "%smtype", Keyword
); break;
752 case NAME
: fprintf(fd
, "an identifier"); break;
753 case NE
: fprintf(fd
, "%s!=", Operator
); break;
754 case NEG
: fprintf(fd
, "%s! (not)",Operator
); break;
755 case NEMPTY
: fprintf(fd
, "%snempty", Function
); break;
756 case NFULL
: fprintf(fd
, "%snfull", Function
); break;
757 case NON_ATOMIC
: fprintf(fd
, "sub-sequence"); break;
758 case NONPROGRESS
: fprintf(fd
, "%snp_", Function
); break;
759 case OD
: fprintf(fd
, "%sod", Keyword
); break;
760 case OF
: fprintf(fd
, "%sof", Keyword
); break;
761 case OR
: fprintf(fd
, "%s||", Operator
); break;
762 case O_SND
: fprintf(fd
, "%s!!", Operator
); break;
763 case PC_VAL
: fprintf(fd
, "%spc_value",Function
); break;
764 case PNAME
: fprintf(fd
, "process name"); break;
765 case PRINT
: fprintf(fd
, "%sprintf", Function
); break;
766 case PRINTM
: fprintf(fd
, "%sprintm", Function
); break;
767 case PRIORITY
: fprintf(fd
, "%spriority", Keyword
); break;
768 case PROCTYPE
: fprintf(fd
, "%sproctype",Keyword
); break;
769 case PROVIDED
: fprintf(fd
, "%sprovided",Keyword
); break;
770 case RCV
: fprintf(fd
, "%s?", Operator
); break;
771 case R_RCV
: fprintf(fd
, "%s??", Operator
); break;
772 case RSHIFT
: fprintf(fd
, "%s>>", Operator
); break;
773 case RUN
: fprintf(fd
, "%srun", Operator
); break;
774 case SEP
: fprintf(fd
, "token: ::"); break;
775 case SEMI
: fprintf(fd
, ";"); break;
776 case SHOW
: fprintf(fd
, "%sshow", Keyword
); break;
777 case SND
: fprintf(fd
, "%s!", Operator
); break;
778 case STRING
: fprintf(fd
, "a string"); break;
779 case TRACE
: fprintf(fd
, "%strace", Keyword
); break;
780 case TIMEOUT
: fprintf(fd
, "%stimeout",Keyword
); break;
781 case TYPE
: fprintf(fd
, "data typename"); break;
782 case TYPEDEF
: fprintf(fd
, "%stypedef",Keyword
); break;
783 case XU
: fprintf(fd
, "%sx[rs]", Keyword
); break;
784 case UMIN
: fprintf(fd
, "%s- (unary minus)", Operator
); break;
785 case UNAME
: fprintf(fd
, "a typename"); break;
786 case UNLESS
: fprintf(fd
, "%sunless", Keyword
); break;