ecf37f908755ccc19cb4b64e047b6a04bfe53e3d
[fw/sdcc] / as / asxxsrc / aslex.c
1 /* aslex.c */
2
3 /*
4  * (C) Copyright 1989-1995
5  * All Rights Reserved
6  *
7  * Alan R. Baldwin
8  * 721 Berkeley St.
9  * Kent, Ohio  44240
10  *
11  * 28-Oct-97 JLH bug in getst(): sign extend on ~(SPACE|ILL)
12  *           causes infinite loop
13  */
14
15 /*
16  * Extensions: P. Felber, M. Hope
17  */
18
19 #include <stdio.h>
20 #include <setjmp.h>
21 #include <string.h>
22 #include "asm.h"
23
24 /*)Module       aslex.c
25  *
26  *      The module aslex.c includes the general lexical
27  *      analysis routines for the assembler.
28  *
29  *      aslex.c contains the following functions:
30  *              char    endline()
31  *              char    get()
32  *              VOID    getid(id,c)
33  *              int     as_getline()
34  *              int     getmap()
35  *              char    getnb()
36  *              VOID    getst()
37  *              int     more()
38  *              VOID    unget(c)
39  *
40  *      aslex.c contains no local/static variables
41  */
42
43 /*)Function     VOID    getid(id,c)
44  *
45  *              char *  id              a pointer to a string of
46  *                                      maximum length NCPS
47  *              int     c               mode flag
48  *                                      >=0     this is first character to
49  *                                              copy to the string buffer
50  *                                      <0      skip white space, first
51  *                                              character must be a LETTER
52  *
53  *      The function getid() scans the current assembler-source text line
54  *      from the current position copying the next LETTER | DIGIT string
55  *      into the external string buffer (id).  The string ends when a non
56  *      LETTER or DIGIT character is found. The maximum number of
57  *      characters copied is NCPS.  If the input string is larger than
58  *      NCPS characters then the string is truncated, if the input string
59  *      is shorter than NCPS characters then the string is NULL filled.
60  *      If the mode argument (c) is >=0 then (c) is the first character
61  *      copied to the string buffer, if (c) is <0 then intervening white
62  *      space (SPACES and TABS) are skipped and the first character found
63  *      must be a LETTER else a 'q' error terminates the parse of this
64  *      assembler-source text line.
65  *
66  *      local variables:
67  *              char *  p               pointer to external string buffer
68  *              int     c               current character value
69  *
70  *      global variables:
71  *              char    ctype[]         a character array which defines the
72  *                                      type of character being processed.
73  *                                      This index is the character
74  *                                      being processed.
75  *
76  *      called functions:
77  *              char    get()           aslex.c
78  *              char    getnb()         aslex.c
79  *              VOID    unget()         aslex.c
80  *
81  *      side effects:
82  *              use of getnb(), get(), and unget() updates the
83  *              global pointer ip, the position in the current
84  *              assembler-source text line.
85  */
86
87 VOID
88 getid(id, c)
89 register int c;
90 char *id;
91 {
92         register char *p;
93
94         if (c < 0) {
95                 c = getnb();
96                 if ((ctype[c] & LETTER) == 0)
97                         qerr();
98         }
99         p = id;
100         do {
101                 if (p < &id[NCPS])
102                         *p++ = c;
103         } while (ctype[c=get()] & (LETTER|DIGIT));
104         unget(c);
105         while (p < &id[NCPS])
106                 *p++ = 0;
107 }
108
109 /*)Function     VOID    getst(id,c)
110  *
111  *              char *  id              a pointer to a string of
112  *                                      maximum length NCPS
113  *              int     c               mode flag
114  *                                      >=0     this is first character to
115  *                                              copy to the string buffer
116  *                                      <0      skip white space, first
117  *                                              character must be a LETTER
118  *
119  *      The function getnbid() scans the current assembler-source text line
120  *      from the current position copying the next character string into
121  *      the external string buffer (id).  The string ends when a SPACE or
122  *      ILL character is found. The maximum number of
123  *      characters copied is NCPS.  If the input string is larger than
124  *      NCPS characters then the string is truncated, if the input string
125  *      is shorter than NCPS characters then the string is NULL filled.
126  *      If the mode argument (c) is >=0 then (c) is the first character
127  *      copied to the string buffer, if (c) is <0 then intervening white
128  *      space (SPACES and TABS) are skipped and the first character found
129  *      must be a LETTER else a 'q' error terminates the parse of this
130  *      assembler-source text line.
131  *
132  *      local variables:
133  *              char *  p               pointer to external string buffer
134  *              int     c               current character value
135  *
136  *      global variables:
137  *              char    ctype[]         a character array which defines the
138  *                                      type of character being processed.
139  *                                      This index is the character
140  *                                      being processed.
141  *
142  *      called functions:
143  *              char    get()           aslex.c
144  *              char    getnb()         aslex.c
145  *              VOID    unget()         aslex.c
146  *
147  *      side effects:
148  *              use of getnb(), get(), and unget() updates the
149  *              global pointer ip, the position in the current
150  *              assembler-source text line.
151  */
152
153 VOID
154 getst(id, c)
155 register int c;
156 char *id;
157 {
158         register char *p;
159
160         if (c < 0) {
161                 c = getnb();
162                 if ((ctype[c] & LETTER) == 0)
163                         qerr();
164         }
165         p = id;
166         do {
167                 if (p < &id[NCPS])
168                         *p++ = c;
169         } while (ctype[c=get()] & (0xFF - (SPACE|ILL)));
170         unget(c);
171         while (p < &id[NCPS])
172                 *p++ = 0;
173 }
174
175 /*)Function     char    getnb()
176  *
177  *      The function getnb() scans the current assembler-source
178  *      text line returning the first character not a SPACE or TAB.
179  *
180  *      local variables:
181  *              int     c               current character from
182  *                                      assembler-source text line
183  *
184  *      global variables:
185  *              none
186  *
187  *      called functions:
188  *              char    get()           aslex.c
189  *
190  *      side effects:
191  *              use of get() updates the global pointer ip, the position
192  *              in the current assembler-source text line
193  */
194
195 char
196 getnb()
197 {
198         register int c;
199
200         while ((c=get()) == ' ' || c == '\t')
201                 ;
202         return (c);
203 }
204
205 /*)Function     char    get()
206  *
207  *      The function get() returns the next character in the
208  *      assembler-source text line, at the end of the line a
209  *      NULL character is returned.
210  *
211  *      local variables:
212  *              int     c               current character from
213  *                                      assembler-source text line
214  *
215  *      global variables:
216  *              char *  ip              pointer into the current
217  *                                      assembler-source text line
218  *
219  *      called functions:
220  *              none
221  *
222  *      side effects:
223  *              updates ip to the next character position in the
224  *              assembler-source text line.  If ip is at the end of the
225  *              line, ip is not updated.
226  */
227
228 char
229 get()
230 {
231         register int c;
232
233         if ((c = *ip) != 0)
234                 ++ip;
235         return (c);
236 }
237
238 /*)Function     VOID    unget(c)
239  *
240  *              int     c               value of last character read from
241  *                                      assembler-source text line
242  *
243  *      If (c) is not a NULL character then the global pointer ip
244  *      is updated to point to the preceeding character in the
245  *      assembler-source text line.
246  *
247  *      NOTE:   This function does not push the character (c)
248  *              back into the assembler-source text line, only
249  *              the pointer ip is changed.
250  *
251  *      local variables:
252  *              int     c               last character read from
253  *                                      assembler-source text line
254  *
255  *      global variables:
256  *              char *  ip              position into the current
257  *                                      assembler-source text line
258  *
259  *      called functions:
260  *              none
261  *
262  *      side effects:
263  *              ip decremented by 1 character position
264  */
265
266 VOID
267 unget(c)
268 {
269         if (c)
270                 if (ip != ib)
271                         --ip;
272 }
273
274 /*)Function     int     getmap(d)
275  *
276  *              int     d               value to compare with the
277  *                                      assembler-source text line character
278  *
279  *      The function getmap() converts the 'C' style characters \b, \f,
280  *      \n, \r, and \t to their equivalent ascii values and also
281  *      converts 'C' style octal constants '\123' to their equivalent
282  *      numeric values.  If the first character is equivalent to (d) then
283  *      a (-1) is returned, if the end of the line is detected then
284  *      a 'q' error terminates the parse for this line, or if the first
285  *      character is not a \ then the character value is returned.
286  *
287  *      local variables:
288  *              int     c               value of character from the
289  *                                      assembler-source text line
290  *              int     n               looping counter
291  *              int     v               current value of numeric conversion
292  *
293  *      global variables:
294  *              none
295  *
296  *      called functions:
297  *              char    get()           aslex.c
298  *
299  *      side effects:
300  *              use of get() updates the global pointer ip the position
301  *              in the current assembler-source text line
302  */
303
304 int
305 getmap(d)
306 {
307         register int c, n, v;
308
309         if ((c=get()) == '\0')
310                 qerr();
311         if (c == d)
312                 return (-1);
313         if (c == '\\') {
314                 c = get();
315                 switch (c) {
316
317                 case 'b':
318                         c = '\b';
319                         break;
320
321                 case 'f':
322                         c = '\f';
323                         break;
324
325                 case 'n':
326                         c = '\n';
327                         break;
328
329                 case 'r':
330                         c = '\r';
331                         break;
332
333                 case 't':
334                         c = '\t';
335                         break;
336
337                 case '0':
338                 case '1':
339                 case '2':
340                 case '3':
341                 case '4':
342                 case '5':
343                 case '6':
344                 case '7':
345                         n = 0;
346                         v = 0;
347                         while (++n<=3 && c>='0' && c<='7') {
348                                 v = (v<<3) + c - '0';
349                                 c = get();
350                         }
351                         unget(c);
352                         c = v;
353                         break;
354                 }
355         }
356         return (c);
357 }
358
359 /*)Function     char *  readlin()
360  *
361  *              char *  str             poinetr to beginning of the buffer
362  *              size_t  n               size of the buffer
363  *              FILE *  infp            input file pointer
364  *
365  *      The function readlin() reads a line from a file to the buffer s.
366  *      The buffer length is n. If the line is truncterd to n -1 caharecters
367  *      if it is longer the n - 1 characters.
368  *      Trailing LF or CR/LF are removed from str, if present.
369  *
370  *      local variables:
371  *              int c                   character read from the file
372  *              char *s                 buffer pointer
373  *              satic char eof_f        EOF flag
374  *
375  *      global variables:
376  *              none
377  *
378  *      called functions:
379  *              int     getc            c-library
380  */
381
382 char *
383 readlin(char *str, size_t n, FILE *infp)
384 {
385   int c;
386   char *s;
387   static char eof_f = 0;
388
389   if (eof_f)
390     {
391       eof_f = 0;
392       return NULL;
393     }
394
395   if (n > 0)
396     {
397     s = str;
398     if (n > 1)
399       {
400         while (--n && (c = getc(infp)) != '\n' && c != EOF)
401           *s++ = c;
402       }
403     else
404       c = ' ';  /* initialize it to something for the caharacter eating step */
405
406     /* chop CR */
407     if (s > str && *(s - 1) == '\r')
408       --s;
409
410     /* terminate the line */
411     *s = '\0';
412
413     /* eat characters until the end of line */
414     while (c != '\n' && c != EOF)
415       c = getc(infp);
416
417     /* if the EOF is not at the beginning of the line, return the line;
418        return NULL at the next call of redlin */
419     if (c == EOF)
420       {
421         if (s == str)
422           return NULL;
423         eof_f = 1;
424       }
425     }
426
427   return str;
428 }
429
430 /*)Function     int     as_getline()
431  *
432  *      The function as_getline() reads a line of assembler-source text
433  *      from an assembly source text file or an include file.
434  *      Lines of text are processed from assembler-source files until
435  *      all files have been read.  If an include file is opened then
436  *      lines of text are read from the include file (or nested
437  *      include file) until the end of the include file is found.
438  *      The input text line is copied into the global string ib[]
439  *      and converted to a NULL terminated string.  The function
440  *      as_getline() returns a (1) after succesfully reading a line
441  *      or a (0) if all files have been read.
442  *
443  *      local variables:
444  *              int     i               string length
445  *
446  *      global variables:
447  *              char    ib[]            string buffer containing
448  *                                      assembler-source text line
449  *              char    ifp[]           array of file handles for
450  *                                      include files
451  *              int     incfil          index for ifp[] specifies
452  *                                      active include file
453  *              int     incline[]       array of include file
454  *                                      line numbers
455  *              char    sfp[]           array of file handles for
456  *                                      assembler source files
457  *              int     cfile           index for sfp[] specifies
458  *                                      active source file
459  *              int     srcline[]       array of source file
460  *                                      line numbers
461  *              int     inpfil          maximum input file index
462  *
463  *      called functions:
464  *              int     fclose()        c-library
465  *              char *  fgets()         c-library
466  *              int     strlen()        c-library
467  *
468  *      side effects:
469  *              include file will be closed at detection of end of file.
470  *              the next sequential source file may be selected.
471  *              the global file indexes incfil or cfile may be changed.
472  *              The respective source line or include line counter
473  *              will be updated.
474  */
475
476 int
477 as_getline()
478 {
479 loop:   if (incfil >= 0) {
480                 if (readlin(ib, sizeof ib, ifp[incfil]) == NULL) {
481                         fclose(ifp[incfil]);
482                         ifp[incfil--] = NULL;
483                         lop = NLPP;
484                         goto loop;
485                 } else {
486                         ++incline[incfil];
487                 }
488         } else {
489                 if (readlin(ib, sizeof ib, sfp[cfile]) == NULL) {
490                         if (++cfile <= inpfil) {
491                                 srcline[cfile] = 0;
492                                 goto loop;
493                         }
494                         return (0);
495                 } else {
496                         ++srcline[cfile];
497                 }
498         }
499         return (1);
500 }
501
502 /*)Function     int     more()
503  *
504  *      The function more() scans the assembler-source text line
505  *      skipping white space (SPACES and TABS) and returns a (0)
506  *      if the end of the line or a comment delimeter (;) is found,
507  *      or a (1) if their are additional characters in the line.
508  *
509  *      local variables:
510  *              int     c               next character from the
511  *                                      assembler-source text line
512  *
513  *      global variables:
514  *              none
515  *
516  *      called functions:
517  *              char    getnb()         aslex.c
518  *              VOID    unget()         aslex.c
519  *
520  *      side effects:
521  *              use of getnb() and unget() updates the global pointer ip
522  *              the position in the current assembler-source text line
523  */
524
525 int
526 more()
527 {
528         register int c;
529
530         c = getnb();
531         unget(c);
532         return( (c == '\0' || c == ';') ? 0 : 1 );
533 }
534
535 /*)Function     char    endline()
536  *
537  *      The function endline() scans the assembler-source text line
538  *      skipping white space (SPACES and TABS) and returns the next
539  *      character or a (0) if the end of the line is found or a
540  *      comment delimiter (;) is found.
541  *
542  *      local variables:
543  *              int     c               next character from the
544  *                                      assembler-source text line
545  *
546  *      global variables:
547  *              none
548  *
549  *      called functions:
550  *              char    getnb()         aslex.c
551  *
552  *      side effects:
553  *              use of getnb() updates the global pointer ip the
554  *              position in the current assembler-source text line
555  */
556
557 char
558 endline()
559 {
560         register int c;
561
562         c = getnb();
563         return( (c == '\0' || c == ';') ? 0 : c );
564 }