death to trailing whitespace
[openafs.git] / src / rxgen / rpc_scan.c
1 /* @(#)rpc_scan.c       1.1 87/11/04 3.9 RPCSRC */
2 /*
3  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
4  * unrestricted use provided that this legend is included on all tape
5  * media and as a part of the software program in whole or part.  Users
6  * may copy or modify Sun RPC without charge, but are not authorized
7  * to license or distribute it to anyone else except as part of a product or
8  * program developed by the user.
9  *
10  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
11  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
12  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
13  *
14  * Sun RPC is provided with no support and without any obligation on the
15  * part of Sun Microsystems, Inc. to assist in its use, correction,
16  * modification or enhancement.
17  *
18  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
19  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
20  * OR ANY PART THEREOF.
21  *
22  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
23  * or profits or other special, indirect and consequential damages, even if
24  * Sun has been advised of the possibility of such damages.
25  *
26  * Sun Microsystems, Inc.
27  * 2550 Garcia Avenue
28  * Mountain View, California  94043
29  */
30
31 /*
32  * rpc_scan.c, Scanner for the RPC protocol compiler
33  * Copyright (C) 1987, Sun Microsystems, Inc.
34  */
35
36 /* Portions Copyright (c) 2003 Apple Computer, Inc. */
37 #include <afsconfig.h>
38 #include <afs/param.h>
39
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <ctype.h>
44 #include <string.h>
45
46 #include "rpc_scan.h"
47 #include "rpc_parse.h"
48 #include "rpc_util.h"
49
50 #define startcomment(where) (where[0] == '/' && where[1] == '*')
51 #define endcomment(where) (where[-1] == '*' && where[0] == '/')
52 #define verbatimstart(p) (*(p) == '@' && *((p) + 1) == '{')
53 #define verbatimend(p)  (*(p) == '@' && *((p) + 1) == '}')
54
55 int pushed = 0;                 /* is a token pushed */
56 token lasttok;                  /* last token, if pushed */
57 int scan_print = 1;
58
59 /* static prototypes */
60 static void findstrconst(char **str, char **val);
61 static void findconst(char **str, char **val);
62 static int cppline(char *line);
63 static int directive(char *line);
64 static void docppline(char *line, int *lineno, char **fname);
65 #ifdef undef
66 static void deverbatim(void);
67 #endif
68
69
70 /*
71  * scan expecting 1 given token
72  */
73 void
74 scan(tok_kind expect, token * tokp)
75 {
76     get_token(tokp);
77     if (tokp->kind != expect) {
78         expected1(expect);
79     }
80 }
81
82 /*
83  * scan expecting 2 given tokens
84  */
85 void
86 scan2(tok_kind expect1, tok_kind expect2, token * tokp)
87 {
88     get_token(tokp);
89     if (tokp->kind != expect1 && tokp->kind != expect2) {
90         expected2(expect1, expect2);
91     }
92 }
93
94 /*
95  * scan expecting 3 given token
96  */
97 void
98 scan3(tok_kind expect1, tok_kind expect2, tok_kind expect3, token * tokp)
99 {
100     get_token(tokp);
101     if (tokp->kind != expect1 && tokp->kind != expect2
102         && tokp->kind != expect3) {
103         expected3(expect1, expect2, expect3);
104     }
105 }
106
107
108 /*
109  * scan expecting 4 given token
110  */
111 void
112 scan4(tok_kind expect1, tok_kind expect2, tok_kind expect3, tok_kind expect4,
113       token * tokp)
114 {
115     get_token(tokp);
116     if (tokp->kind != expect1 && tokp->kind != expect2
117         && tokp->kind != expect3 && tokp->kind != expect4) {
118         expected4(expect1, expect2, expect3, expect4);
119     }
120 }
121
122 /*
123  * scan expecting a constant, possibly symbolic
124  */
125 void
126 scan_num(token * tokp)
127 {
128     get_token(tokp);
129     switch (tokp->kind) {
130     case TOK_IDENT:
131         break;
132     default:
133         error("constant or identifier expected");
134     }
135 }
136
137
138 /*
139  * Peek at the next token
140  */
141 void
142 peek(token * tokp)
143 {
144     get_token(tokp);
145     unget_token(tokp);
146 }
147
148
149 /*
150  * Peek at the next token and scan it if it matches what you expect
151  */
152 int
153 peekscan(tok_kind expect, token * tokp)
154 {
155     peek(tokp);
156     if (tokp->kind == expect) {
157         get_token(tokp);
158         return (1);
159     }
160     return (0);
161 }
162
163
164
165 /*
166  * Get the next token, printing out any directive that are encountered.
167  */
168 void
169 get_token(token * tokp)
170 {
171     int commenting;
172     int verbatim = 0;
173
174     if (pushed) {
175         pushed = 0;
176         *tokp = lasttok;
177         return;
178     }
179     commenting = 0;
180     for (;;) {
181         if (*where == 0) {
182             for (;;) {
183                 if (!fgets(curline, MAXLINESIZE, fin)) {
184                     tokp->kind = TOK_EOF;
185                     *where = 0;
186                     return;
187                 }
188                 linenum++;
189                 if (verbatim) {
190                     fputs(curline, fout);
191                     break;
192                 }
193                 if (commenting) {
194                     break;
195                 } else if (cppline(curline)) {
196 #if defined(AFS_DARWIN_ENV)
197                     if (strncmp(curline, "#pragma", 7) == 0)
198                         continue;
199 #endif /* defined(AFS_DARWIN_ENV) */
200                     docppline(curline, &linenum, &infilename);
201                 } else if (directive(curline)) {
202                     printdirective(curline);
203                 } else {
204                     break;
205                 }
206             }
207             where = curline;
208         } else if (isspace(*where)) {
209             while (isspace(*where)) {
210                 where++;        /* eat */
211             }
212         } else if (verbatim) {
213             where++;
214             if (verbatimend(where)) {
215                 where++;
216                 verbatim--;
217             }
218         } else if (verbatimstart(where)) {
219             where += 2;
220             verbatim++;
221         } else if (commenting) {
222             where++;
223             if (endcomment(where)) {
224                 where++;
225                 commenting--;
226             }
227         } else if (startcomment(where)) {
228             where += 2;
229             commenting++;
230         } else {
231             break;
232         }
233     }
234
235     /*
236      * 'where' is not whitespace, comment or directive Must be a token!
237      */
238     switch (*where) {
239     case ':':
240         tokp->kind = TOK_COLON;
241         where++;
242         break;
243     case ';':
244         tokp->kind = TOK_SEMICOLON;
245         where++;
246         break;
247     case ',':
248         tokp->kind = TOK_COMMA;
249         where++;
250         break;
251     case '=':
252         tokp->kind = TOK_EQUAL;
253         where++;
254         break;
255     case '*':
256         tokp->kind = TOK_STAR;
257         where++;
258         break;
259     case '[':
260         tokp->kind = TOK_LBRACKET;
261         where++;
262         break;
263     case ']':
264         tokp->kind = TOK_RBRACKET;
265         where++;
266         break;
267     case '{':
268         tokp->kind = TOK_LBRACE;
269         where++;
270         break;
271     case '}':
272         tokp->kind = TOK_RBRACE;
273         where++;
274         break;
275     case '(':
276         tokp->kind = TOK_LPAREN;
277         where++;
278         break;
279     case ')':
280         tokp->kind = TOK_RPAREN;
281         where++;
282         break;
283     case '<':
284         tokp->kind = TOK_LANGLE;
285         where++;
286         break;
287     case '>':
288         tokp->kind = TOK_RANGLE;
289         where++;
290         break;
291
292     case '"':
293         tokp->kind = TOK_STRCONST;
294         findstrconst(&where, &tokp->str);
295         break;
296
297     case '-':
298     case '0':
299     case '1':
300     case '2':
301     case '3':
302     case '4':
303     case '5':
304     case '6':
305     case '7':
306     case '8':
307     case '9':
308         tokp->kind = TOK_IDENT;
309         findconst(&where, &tokp->str);
310         break;
311
312
313     default:
314         if (!(isalpha(*where) || *where == '_')) {
315             char buf[100];
316             char *p;
317
318             s_print(buf, "illegal character in file: ");
319             p = buf + strlen(buf);
320             if (isprint(*where)) {
321                 s_print(p, "%c", *where);
322             } else {
323                 s_print(p, "%d", *where);
324             }
325             error(buf);
326         }
327         findkind(&where, tokp);
328         break;
329     }
330 }
331
332
333 void
334 unget_token(token * tokp)
335 {
336     lasttok = *tokp;
337     pushed = 1;
338 }
339
340
341 static void
342 findstrconst(char **str, char **val)
343 {
344     char *p;
345     int size;
346
347     p = *str;
348     do {
349         p++;
350     } while (*p && *p != '"');
351     if (*p == 0) {
352         error("unterminated string constant");
353     }
354     p++;
355     size = (int)(p - *str);
356     *val = alloc(size + 1);
357     (void)strncpy(*val, *str, size);
358     (*val)[size] = 0;
359     *str = p;
360 }
361
362 static void
363 findconst(char **str, char **val)
364 {
365     char *p;
366     int size;
367
368     p = *str;
369     if (*p == '0' && *(p + 1) == 'x') {
370         p++;
371         do {
372             p++;
373         } while (isxdigit(*p));
374     } else {
375         do {
376             p++;
377         } while (isdigit(*p));
378     }
379     size = (int)(p - *str);
380     *val = alloc(size + 1);
381     (void)strncpy(*val, *str, size);
382     (*val)[size] = 0;
383     *str = p;
384 }
385
386
387
388 static token symbols[] = {
389     {TOK_CONST, "const"},
390     {TOK_UNION, "union"},
391     {TOK_SWITCH, "switch"},
392     {TOK_CASE, "case"},
393     {TOK_DEFAULT, "default"},
394     {TOK_STRUCT, "struct"},
395     {TOK_TYPEDEF, "typedef"},
396     {TOK_ENUM, "enum"},
397     {TOK_OPAQUE, "opaque"},
398     {TOK_BOOL, "bool"},
399     {TOK_VOID, "void"},
400     {TOK_CHAR, "char"},
401     {TOK_INT, "int"},
402     {TOK_UNSIGNED, "unsigned"},
403     {TOK_SHORT, "short"},
404     {TOK_INT32, "afs_int32"},
405     {TOK_FLOAT, "float"},
406     {TOK_DOUBLE, "double"},
407     {TOK_STRING, "string"},
408     {TOK_PROGRAM, "program"},
409     {TOK_VERSION, "version"},
410     {TOK_PACKAGE, "package"},
411     {TOK_PREFIX, "prefix"},
412     {TOK_STATINDEX, "statindex"},
413     {TOK_SPECIAL, "special"},
414     {TOK_STARTINGOPCODE, "startingopcode"},
415     {TOK_CUSTOMIZED, "customized"},
416     {TOK_PROC, "proc"},
417     {TOK_SPLITPREFIX, "splitprefix"},
418     {TOK_SPLIT, "split"},
419     {TOK_MULTI, "multi"},
420     {TOK_IN, "IN"},
421     {TOK_OUT, "OUT"},
422     {TOK_INOUT, "INOUT"},
423     {TOK_AFSUUID, "afsUUID"},
424     {TOK_EOF, "??????"},
425 };
426
427
428 void
429 findkind(char **mark, token * tokp)
430 {
431
432     int len;
433     token *s;
434     char *str;
435
436     str = *mark;
437     for (s = symbols; s->kind != TOK_EOF; s++) {
438         len = (int)strlen(s->str);
439         if (strncmp(str, s->str, len) == 0) {
440             if (!isalnum(str[len]) && str[len] != '_') {
441                 tokp->kind = s->kind;
442                 tokp->str = s->str;
443                 *mark = str + len;
444                 return;
445             }
446         }
447     }
448     tokp->kind = TOK_IDENT;
449     for (len = 0; isalnum(str[len]) || str[len] == '_'; len++);
450     tokp->str = alloc(len + 1);
451     (void)strncpy(tokp->str, str, len);
452     tokp->str[len] = 0;
453     *mark = str + len;
454 }
455
456 static int
457 cppline(char *line)
458 {
459     return (line == curline && *line == '#');
460 }
461
462 static int
463 directive(char *line)
464 {
465     return (line == curline && *line == '%');
466 }
467
468 void
469 printdirective(char *line)
470 {
471     f_print(fout, "%s", line + 1);
472 }
473
474 static void
475 docppline(char *line, int *lineno, char **fname)
476 {
477     char *file;
478     int num;
479     char *p;
480
481     line++;
482     while (isspace(*line)) {
483         line++;
484     }
485     num = atoi(line);
486     while (isdigit(*line)) {
487         line++;
488     }
489     while (isspace(*line)) {
490         line++;
491     }
492 #ifdef  AFS_HPUX_ENV
493     if (*line == '\0') {
494         *fname = NULL;
495         *lineno = num - 1;
496         return;
497     }
498 #endif
499     if (*line != '"') {
500 #ifdef  AFS_AIX41_ENV
501         if (!strncmp(line, "line", 4)) {
502             while (*line)
503                 *line++;
504             *fname = NULL;
505             *lineno = num - 1;
506             return;
507         }
508 #endif
509         error("preprocessor error");
510     }
511     line++;
512     p = file = alloc(strlen(line) + 1);
513     while (*line && *line != '"') {
514         *p++ = *line++;
515     }
516     if (*line == 0) {
517         error("preprocessor error");
518     }
519     *p = 0;
520     if (*file == 0) {
521         *fname = NULL;
522     } else {
523         *fname = file;
524     }
525     *lineno = num - 1;
526 }
527
528
529 #ifdef undef
530 /* doesn't appear to be used */
531 static void
532 deverbatim(void)
533 {
534     for (where += 2; !verbatimend(where); where++) {
535         if (*where == 0) {
536             if (!fgets(curline, MAXLINESIZE, fin)) {
537                 error("unterminated code: %} is missing");
538             }
539             linenum++;
540             where = curline - 1;
541             if (verbatimend(curline)) {
542                 where++;
543                 break;
544             }
545             fputs(curline, fout);
546         }
547     }
548     where += 2;
549 }
550 #endif