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