1. Fix some typos in README.
[nfs-utils.git] / tools / rpcgen / rpc_scan.c
1 /*
2  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
3  * unrestricted use provided that this legend is included on all tape
4  * media and as a part of the software program in whole or part.  Users
5  * may copy or modify Sun RPC without charge, but are not authorized
6  * to license or distribute it to anyone else except as part of a product or
7  * program developed by the user or with the express written consent of
8  * Sun Microsystems, Inc.
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 #ifndef lint
32 static char sccsid[] = "@(#)rpc_scan.c 1.11 89/02/22 (C) 1987 SMI";
33 #endif
34
35 /*
36  * rpc_scan.c, Scanner for the RPC protocol compiler 
37  * Copyright (C) 1987, Sun Microsystems, Inc. 
38  */
39 #include <stdio.h>
40 #include <ctype.h>
41 #include <string.h>
42 #include "rpc_scan.h"
43 #include "rpc_parse.h"
44 #include "rpc_util.h"
45
46 static void     unget_token(token *tokp);
47 static void     findstrconst(char **str, char **val);
48 static void     findchrconst(char **str, char **val);
49 static void     findconst(char **str, char **val);
50 static void     findkind(char **mark, token *tokp);
51 static int      cppline(char *line);
52 static int      directive(char *line);
53 static void     printdirective(char *line);
54 static void     docppline(char *line, int *lineno, char **fname);
55
56 #define startcomment(where) (where[0] == '/' && where[1] == '*')
57 #define endcomment(where) (where[-1] == '*' && where[0] == '/')
58
59 static int pushed = 0;  /* is a token pushed */
60 static token lasttok;   /* last token, if pushed */
61
62 /*
63  * scan expecting 1 given token 
64  */
65 void
66 scan(tok_kind expect, token *tokp)
67 {
68         get_token(tokp);
69         if (tokp->kind != expect) {
70                 expected1(expect);
71         }
72 }
73
74 /*
75  * scan expecting any of the 2 given tokens 
76  */
77 void
78 scan2(tok_kind expect1, tok_kind expect2, token *tokp)
79 {
80         get_token(tokp);
81         if (tokp->kind != expect1 && tokp->kind != expect2) {
82                 expected2(expect1, expect2);
83         }
84 }
85
86 /*
87  * scan expecting any of the 3 given token 
88  */
89 void
90 scan3(tok_kind expect1, tok_kind expect2, tok_kind expect3, token *tokp)
91 {
92         get_token(tokp);
93         if (tokp->kind != expect1 && tokp->kind != expect2
94             && tokp->kind != expect3) {
95                 expected3(expect1, expect2, expect3);
96         }
97 }
98
99 /*
100  * scan expecting a constant, possibly symbolic 
101  */
102 void
103 scan_num(token *tokp)
104 {
105         get_token(tokp);
106         switch (tokp->kind) {
107         case TOK_IDENT:
108                 break;
109         default:
110                 error("constant or identifier expected");
111         }
112 }
113
114 /*
115  * Peek at the next token 
116  */
117 void
118 peek(token *tokp)
119 {
120         get_token(tokp);
121         unget_token(tokp);
122 }
123
124 /*
125  * Peek at the next token and scan it if it matches what you expect 
126  */
127 int
128 peekscan(tok_kind expect, token *tokp)
129 {
130         peek(tokp);
131         if (tokp->kind == expect) {
132                 get_token(tokp);
133                 return (1);
134         }
135         return (0);
136 }
137
138 /*
139  * Get the next token, printing out any directive that are encountered. 
140  */
141 void
142 get_token(token *tokp)
143 {
144         int commenting;
145
146         if (pushed) {
147                 pushed = 0;
148                 *tokp = lasttok;
149                 return;
150         }
151         commenting = 0;
152         for (;;) {
153                 if (*where == 0) {
154                         for (;;) {
155                                 if (!fgets(curline, MAXLINESIZE, fin)) {
156                                         tokp->kind = TOK_EOF;
157                                         *where = 0;
158                                         return;
159                                 }
160                                 linenum++;
161                                 if (commenting) {
162                                         break;
163                                 } else if (cppline(curline)) {
164                                         docppline(curline, &linenum, 
165                                                   &infilename);
166                                 } else if (directive(curline)) {
167                                         printdirective(curline);
168                                 } else {
169                                         break;
170                                 }
171                         }
172                         where = curline;
173                 } else if (isspace(*where)) {
174                         while (isspace(*where)) {
175                                 where++;        /* eat */
176                         }
177                 } else if (commenting) {
178                         for (where++; *where; where++) {
179                                 if (endcomment(where)) {
180                                         where++;
181                                         commenting--;
182                                         break;
183                                 }
184                         }
185                 } else if (startcomment(where)) {
186                         where += 2;
187                         commenting++;
188                 } else {
189                         break;
190                 }
191         }
192
193         /*
194          * 'where' is not whitespace, comment or directive Must be a token! 
195          */
196         switch (*where) {
197         case ':':
198                 tokp->kind = TOK_COLON;
199                 where++;
200                 break;
201         case ';':
202                 tokp->kind = TOK_SEMICOLON;
203                 where++;
204                 break;
205         case ',':
206                 tokp->kind = TOK_COMMA;
207                 where++;
208                 break;
209         case '=':
210                 tokp->kind = TOK_EQUAL;
211                 where++;
212                 break;
213         case '*':
214                 tokp->kind = TOK_STAR;
215                 where++;
216                 break;
217         case '[':
218                 tokp->kind = TOK_LBRACKET;
219                 where++;
220                 break;
221         case ']':
222                 tokp->kind = TOK_RBRACKET;
223                 where++;
224                 break;
225         case '{':
226                 tokp->kind = TOK_LBRACE;
227                 where++;
228                 break;
229         case '}':
230                 tokp->kind = TOK_RBRACE;
231                 where++;
232                 break;
233         case '(':
234                 tokp->kind = TOK_LPAREN;
235                 where++;
236                 break;
237         case ')':
238                 tokp->kind = TOK_RPAREN;
239                 where++;
240                 break;
241         case '<':
242                 tokp->kind = TOK_LANGLE;
243                 where++;
244                 break;
245         case '>':
246                 tokp->kind = TOK_RANGLE;
247                 where++;
248                 break;
249
250         case '"':
251                 tokp->kind = TOK_STRCONST;
252                 findstrconst(&where, &tokp->str);
253                 break;
254         case '\'':
255                 tokp->kind = TOK_CHARCONST;
256                 findchrconst(&where, &tokp->str);
257                 break;
258
259         case '-':
260         case '0':
261         case '1':
262         case '2':
263         case '3':
264         case '4':
265         case '5':
266         case '6':
267         case '7':
268         case '8':
269         case '9':
270                 tokp->kind = TOK_IDENT;
271                 findconst(&where, &tokp->str);
272                 break;
273
274         default:
275                 if (!(isalpha(*where) || *where == '_')) {
276                         char buf[100];
277                         char *p;
278
279                         s_print(buf, "illegal character in file: ");
280                         p = buf + strlen(buf);
281                         if (isprint(*where)) {
282                                 s_print(p, "%c", *where);
283                         } else {
284                                 s_print(p, "%d", *where);
285                         }
286                         error(buf);
287                 }
288                 findkind(&where, tokp);
289                 break;
290         }
291 }
292
293 static void
294 unget_token(token *tokp)
295 {
296         lasttok = *tokp;
297         pushed = 1;
298 }
299
300 static void
301 findstrconst(char **str, char **val)
302 {
303         char *p;
304         int size;
305
306         p = *str;
307         do {
308                 *p++;
309         } while (*p && *p != '"');
310         if (*p == 0) {
311                 error("unterminated string constant");
312         }
313         p++;
314         size = p - *str;
315         *val = alloc(size + 1);
316         (void) strncpy(*val, *str, size);
317         (*val)[size] = 0;
318         *str = p;
319 }
320
321 static void
322 findchrconst(char **str, char **val)
323 {
324         char *p;
325         int size;
326
327         p = *str;
328         do {
329                 *p++;
330         } while (*p && *p != '\'');
331         if (*p == 0) {
332                 error("unterminated string constant");
333         }
334         p++;
335         size = p - *str;
336         if (size != 3) {
337                 error("empty char string");
338         }
339         *val = alloc(size + 1);
340         (void) strncpy(*val, *str, size);
341         (*val)[size] = 0;
342         *str = p;
343 }
344
345 static void
346 findconst(char **str, char **val)
347 {
348         char *p;
349         int size;
350
351         p = *str;
352         if (*p == '0' && *(p + 1) == 'x') {
353                 p++;
354                 do {
355                         p++;
356                 } while (isxdigit(*p));
357         } else {
358                 do {
359                         p++;
360                 } while (isdigit(*p));
361         }
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 token symbols[] = {
370                           {TOK_CONST, "const"},
371                           {TOK_UNION, "union"},
372                           {TOK_SWITCH, "switch"},
373                           {TOK_CASE, "case"},
374                           {TOK_DEFAULT, "default"},
375                           {TOK_STRUCT, "struct"},
376                           {TOK_TYPEDEF, "typedef"},
377                           {TOK_ENUM, "enum"},
378                           {TOK_OPAQUE, "opaque"},
379                           {TOK_BOOL, "bool"},
380                           {TOK_VOID, "void"},
381                           {TOK_CHAR, "char"},
382                           {TOK_INT, "int"},
383                           {TOK_UNSIGNED, "unsigned"},
384                           {TOK_SHORT, "short"},
385                           {TOK_INT32, "int32"},
386                           {TOK_FLOAT, "float"},
387                           {TOK_DOUBLE, "double"},
388                           {TOK_STRING, "string"},
389                           {TOK_PROGRAM, "program"},
390                           {TOK_VERSION, "version"},
391                           {TOK_EOF, "??????"},
392 };
393
394 static void
395 findkind(char **mark, token *tokp)
396 {
397         int len;
398         token *s;
399         char *str;
400
401         str = *mark;
402         for (s = symbols; s->kind != TOK_EOF; s++) {
403                 len = strlen(s->str);
404                 if (strncmp(str, s->str, len) == 0) {
405                         if (!isalnum(str[len]) && str[len] != '_') {
406                                 tokp->kind = s->kind;
407                                 tokp->str = s->str;
408                                 *mark = str + len;
409                                 return;
410                         }
411                 }
412         }
413         tokp->kind = TOK_IDENT;
414         for (len = 0; isalnum(str[len]) || str[len] == '_'; len++);
415         tokp->str = alloc(len + 1);
416         (void) strncpy(tokp->str, str, len);
417         tokp->str[len] = 0;
418         *mark = str + len;
419 }
420
421 static int
422 cppline(char *line)
423 {
424         return (line == curline && *line == '#');
425 }
426
427 static int
428 directive(char *line)
429 {
430         return (line == curline && *line == '%');
431 }
432
433 static void
434 printdirective(char *line)
435 {
436         f_print(fout, "%s", line + 1);
437 }
438
439 static void
440 docppline(char *line, int *lineno, char **fname)
441 {
442         char *file;
443         int num;
444         char *p;
445
446         line++;
447         while (isspace(*line)) {
448                 line++;
449         }
450         num = atoi(line);
451         while (isdigit(*line)) {
452                 line++;
453         }
454         while (isspace(*line)) {
455                 line++;
456         }
457         if (*line != '"') {
458                 error("preprocessor error");
459         }
460         line++;
461         p = file = alloc(strlen(line) + 1);
462         while (*line && *line != '"') {
463                 *p++ = *line++;
464         }
465         if (*line == 0) {
466                 error("preprocessor error");
467         }
468         *p = 0;
469         if (*file == 0) {
470                 *fname = NULL;
471         } else {
472                 *fname = file;
473         }
474         *lineno = num - 1;
475 }