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