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