* asranlib/asranlib.c, link/lkar.h, link/lkar.c:
[fw/sdcc] / as / link / lklex.c
1 /* lklex.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 #include <stdio.h>
20 #include <string.h>
21 #include "aslink.h"
22
23 /*)Module       lklex.c
24  *
25  *      The module lklex.c contains the general lexical analysis
26  *      functions used to scan the text lines from the .rel files.
27  *
28  *      lklex.c contains the fllowing functions:
29  *              char    endline()
30  *              char    get()
31  *              VOID    getfid()
32  *              VOID    getid()
33  *              VOID    getSid()
34  *              int     lk_getline()
35  *              int     getmap()
36  *              char    getnb()
37  *              int     more()
38  *              VOID    skip()
39  *              VOID    unget()
40  *
41  *      lklex.c contains no local 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
52  *
53  *      The function getid() scans the current input 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.
63  *
64  *      local variables:
65  *              char *  p               pointer to external string buffer
66  *              int     c               current character value
67  *
68  *      global variables:
69  *              char    ctype[]         a character array which defines the
70  *                                      type of character being processed.
71  *                                      This index is the character
72  *                                      being processed.
73  *
74  *      called functions:
75  *              char    get()           lklex.c
76  *              char    getnb()         lklex.c
77  *              VOID    unget()         lklex.c
78  *
79  *      side effects:
80  *              use of getnb(), get(), and unget() updates the
81  *              global pointer ip the position in the current
82  *              input text line.
83  */
84
85 VOID
86 getid(id, c)
87 register int c;
88 char *id;
89 {
90         register char *p;
91
92         if (c < 0) {
93                 c = getnb();
94         }
95         p = id;
96         do {
97                 if (p < &id[NCPS])
98                         *p++ = c;
99         } while (ctype[c=get()] & (LETTER|DIGIT));
100         unget(c);
101         while (p < &id[NCPS])
102                 *p++ = 0;
103 }
104
105 /*)Function     VOID    getSid (char *id)
106  *
107  *              char *  id              a pointer to a string of
108  *                                      maximum length NCPS
109  *
110  *  getSid is derived from getid. It is called from newsym()
111  *  in lksym.c, when an S-record has to be scanned. getSid accepts
112  *  much more characters than getid, which is necessary for SDCC.
113  *
114  *      The function getSid() scans the current input text line
115  *      from the current position copying the next string
116  *      into the external string buffer (id).  The string ends when a space
117  *  character (space, tab, \0) is found. The maximum number of
118  *      characters copied is NCPS.  If the input string is larger than
119  *      NCPS characters then the string is truncated, if the input string
120  *      is shorter than NCPS characters then the string is NULL filled.
121  *      Intervening white space (SPACES and TABS) are skipped.
122  *
123  *      local variables:
124  *              char *  p               pointer to external string buffer
125  *              int     c               current character value
126  *
127  *      global variables:
128  *              char    ctype[]         a character array which defines the
129  *                                      type of character being processed.
130  *                                      This index is the character
131  *                                      being processed.
132  *
133  *      called functions:
134  *              char    get()           lklex.c
135  *              char    getnb()         lklex.c
136  *              VOID    unget()         lklex.c
137  *
138  *      side effects:
139  *              use of getnb(), get(), and unget() updates the
140  *              global pointer ip the position in the current
141  *              input text line.
142  */
143
144 VOID
145 getSid (char *id)
146 {
147         register int c;
148         register char *p;
149
150         c = getnb();
151         p = id;
152         do {
153                 if (p < &id[NCPS])
154                         *p++ = c;
155                 c = get();
156         } while (c != '\0' && c != ' ' && c != '\t');
157         unget(c);
158         while (p < &id[NCPS])
159                 *p++ = 0;
160 }
161
162 /*)Function     VOID    getfid(fid,c)
163  *
164  *              char *  str             a pointer to a string of
165  *                                      maximum length PATH_MAX
166  *              int     c               this is first character to
167  *                                      copy to the string buffer
168  *
169  *      The function getfid() scans the current input text line from
170  *      the current position copying the next string into the external
171  *      string buffer (str).  The string ends when end of line is found.
172  *      Trailing spaces are removed. The maximum number of characters
173  *      copied is PATH_MAX. If the input string is larger than PATH_MAX
174  *      characters then the string is truncated. The string is NULL
175  *      terminated.
176  *
177  *      local variables:
178  *              char *  p               pointer to external string buffer
179  *              int     c               current character value
180  *
181  *      global variables:
182  *              char    ctype[]         a character array which defines the
183  *                                      type of character being processed.
184  *                                      This index is the character
185  *                                      being processed.
186  *
187  *      called functions:
188  *              char    get()           lklex.c
189  *
190  *      side effects:
191  *              use of get() updates the global pointer ip
192  *              the position in the current input text line.
193  */
194
195 VOID
196 getfid(char *str, register int c)
197 {
198         register char *p;
199
200         p = str;
201         do
202         {
203                 if (p < &str[PATH_MAX-1])
204                         *p++ = c;
205                 c = get();
206                 if (c == ';')
207                         while (c)
208                                 c = get();
209         } while (c);
210         /* trim trailing spaces */
211         --p;
212         while (p >= str && ctype[(int)*p] == SPACE)
213                 --p;
214         /* terminate the string */
215         *(++p) = '\0';
216 }
217
218 /*)Function     char    getnb()
219  *
220  *      The function getnb() scans the current input text
221  *      line returning the first character not a SPACE or TAB.
222  *
223  *      local variables:
224  *              int     c               current character from input
225  *
226  *      global variables:
227  *              none
228  *
229  *      called functions:
230  *              char    get()           lklex.c
231  *
232  *      side effects:
233  *              use of get() updates the global pointer ip, the position
234  *              in the current input text line
235  */
236
237 char
238 getnb()
239 {
240         register int c;
241
242         while ((c=get())==' ' || c=='\t')
243                 ;
244         return (c);
245 }
246
247 /*)Function     VOID    skip()
248  *
249  *      The function skip() scans the input text skipping all
250  *      letters and digits.
251  *
252  *      local variables:
253  *              none
254  *
255  *      global variables:
256  *              char    ctype[]         array of character types, one per
257  *                                      ASCII character
258  *
259  *      functions called:
260  *              char    get()           lklex.c
261  *              char    getnb()         lklex.c
262  *              VOID    unget()         lklex.c
263  *
264  *      side effects:
265  *              Input letters and digits are skipped.
266  */
267
268 VOID
269 skip(register int c)
270 {
271         if (c < 0)
272                 c = getnb();
273         while (ctype[c=get()] & (LETTER|DIGIT)) { ; }
274         unget(c);
275 }
276
277 /*)Function     char    get()
278  *
279  *      The function get() returns the next character in the
280  *      input text line, at the end of the line a
281  *      NULL character is returned.
282  *
283  *      local variables:
284  *              int     c               current character from
285  *                                      input text line
286  *
287  *      global variables:
288  *              char *  ip              pointer into the current
289  *                                      input text line
290  *
291  *      called functions:
292  *              none
293  *
294  *      side effects:
295  *              updates ip to the next character position in the
296  *              input text line.  If ip is at the end of the
297  *              line, ip is not updated.
298  */
299
300 char
301 get()
302 {
303         register int c;
304
305         if ((c = *ip) != 0)
306                 ++ip;
307         return (c);
308 }
309
310 /*)Function     VOID    unget(c)
311  *
312  *              int     c               value of last character
313  *                                      read from input text line
314  *
315  *      If (c) is not a NULL character then the global pointer ip
316  *      is updated to point to the preceeding character in the
317  *      input text line.
318  *
319  *      NOTE:   This function does not push the character (c)
320  *              back into the input text line, only
321  *              the pointer ip is changed.
322  *
323  *      local variables:
324  *              int     c               last character read
325  *                                      from input text line
326  *
327  *      global variables:
328  *              char *  ip              position into the current
329  *                                      input text line
330  *
331  *      called functions:
332  *              none
333  *
334  *      side effects:
335  *              ip decremented by 1 character position
336  */
337
338 VOID
339 unget(int c)
340 {
341         if (c != 0)
342                 --ip;
343 }
344
345 /*)Function     int     getmap(d)
346  *
347  *              int     d               value to compare with the
348  *                                      input text line character
349  *
350  *      The function getmap() converts the 'C' style characters \b, \f,
351  *      \n, \r, and \t to their equivalent ascii values and also
352  *      converts 'C' style octal constants '\123' to their equivalent
353  *      numeric values.  If the first character is equivalent to (d) then
354  *      a (-1) is returned, if the end of the line is detected then
355  *      a 'q' error terminates the parse for this line, or if the first
356  *      character is not a \ then the character value is returned.
357  *
358  *      local variables:
359  *              int     c               value of character
360  *                                      from input text line
361  *              int     n               looping counter
362  *              int     v               current value of numeric conversion
363  *
364  *      global variables:
365  *              none
366  *
367  *      called functions:
368  *              char    get()           lklex.c
369  *              VOID    unget()         lklex.c
370  *
371  *      side effects:
372  *              use of get() updates the global pointer ip the position
373  *              in the current input text line
374  */
375
376 int
377 getmap(int d)
378 {
379         register int c, n, v;
380
381         if ((c = get()) == '\0')
382                 return (-1);
383         if (c == d)
384                 return (-1);
385         if (c == '\\') {
386                 c = get();
387                 switch (c) {
388
389                 case 'b':
390                         c = '\b';
391                         break;
392
393                 case 'f':
394                         c = '\f';
395                         break;
396
397                 case 'n':
398                         c = '\n';
399                         break;
400
401                 case 'r':
402                         c = '\r';
403                         break;
404
405                 case 't':
406                         c = '\t';
407                         break;
408
409                 case '0':
410                 case '1':
411                 case '2':
412                 case '3':
413                 case '4':
414                 case '5':
415                 case '6':
416                 case '7':
417                         n = 0;
418                         v = 0;
419                         while (++n<=3 && c>='0' && c<='7') {
420                                 v = (v<<3) + c - '0';
421                                 c = get();
422                         }
423                         unget(c);
424                         c = v;
425                         break;
426                 }
427         }
428         return (c);
429 }
430
431 /*)Function     int     lk_getline()
432  *
433  *      The function lk_getline() reads a line of input text from a
434  *      .rel source text file, a .lnk command file or from stdin.
435  *      Lines of text are processed from a single .lnk file or
436  *      multiple .rel files until all files have been read.
437  *      The input text line is copied into the global string ib[]
438  *      and converted to a NULL terminated string.  The function
439  *      lk_getline() returns a (1) after succesfully reading a line
440  *      or a (0) if all files have been read.
441  *      This function also opens each input .lst file and output
442  *      .rst file as each .rel file is processed.
443  *
444  *      local variables:
445  *              int     i               string length
446  *              int     ftype           file type
447  *              char *  fid             file name
448  *
449  *      global variables:
450  *              lfile   *cfp            The pointer *cfp points to the
451  *                                      current lfile structure
452  *              lfile   *filep          The pointer *filep points to the
453  *                                      beginning of a linked list of
454  *                                      lfile structures.
455  *              int     gline           get a line from the LST file
456  *                                      to translate for the RST file
457  *              char    ib[NINPUT]      REL file text line
458  *              int     pass            linker pass number
459  *              int     pflag           print linker command file flag
460  *              FILE    *rfp            The file handle to the current
461  *                                      output RST file
462  *              FILE    *sfp            The file handle sfp points to the
463  *                                      currently open file
464  *              FILE *  stdin           c_library
465  *              FILE *  stdout          c_library
466  *              FILE    *tfp            The file handle to the current
467  *                                      LST file being scanned
468  *              int     uflag           update listing flag
469  *
470  *      called functions:
471  *              FILE *  afile()         lkmain.c
472  *              int     fclose()        c_library
473  *              char *  fgets()         c_library
474  *              int     fprintf()       c_library
475  *              VOID    lkulist()       lklist.c
476  *              VOID    lkexit()        lkmain.c
477  *              int     strlen()        c_library
478  *
479  *      side effects:
480  *              The input stream is scanned.  The .rel files will be
481  *              opened and closed sequentially scanning each in turn.
482  */
483
484 int
485 lk_getline()
486 {
487         register int ftype;
488         register char *fid;
489
490 loop:   if (pflag && cfp && cfp->f_type == F_STD)
491                 fprintf(stdout, "ASlink >> ");
492
493         if (sfp == NULL || fgets(ib, sizeof ib, sfp) == NULL) {
494                 if (sfp) {
495                         fclose(sfp);
496                         sfp = NULL;
497                         lkulist(0);
498                 }
499                 if (cfp == NULL) {
500                         cfp = filep;
501                 } else {
502                         cfp = cfp->f_flp;
503                 }
504                 if (cfp) {
505                         ftype = cfp->f_type;
506                         fid = cfp->f_idp;
507                         if (ftype == F_STD) {
508                                 sfp = stdin;
509                         } else
510                         if (ftype == F_LNK) {
511                                 sfp = afile(fid, "lnk", 0);
512                         } else
513                         if (ftype == F_REL) {
514                                 sfp = afile(fid, LKOBJEXT, 0);
515                                 /* if a .adb file exists then copy it over */
516                                 if (dflag && sfp && dfp && pass == 0) {
517                                         FILE *xfp = afile(fid,"adb",0); //JCF: Nov 30, 2002
518                                         if (xfp) {
519                                                 copyfile(dfp,xfp);
520                                                 fclose(xfp);
521                                         }
522                                 }
523                                 if (uflag && pass != 0) {
524                                         SaveLinkedFilePath(fid); //Save the linked path for aomf51
525                                         if ((tfp = afile(fid, "lst", 0)) != NULL) {
526                                                 if ((rfp = afile(fid, "rst", 1)) == NULL) {
527                                                         fclose(tfp);
528                                                         tfp = NULL;
529                                                 }
530                                         }
531                                 }
532                                 gline = 1;
533                         } else {
534                                 fprintf(stderr, "Invalid file type\n");
535                                 lkexit(1);
536                         }
537                         if (sfp == NULL) {
538                                 lkexit(1);
539                         }
540                         goto loop;
541                 } else {
542                         filep = NULL;
543                         return(0);
544                 }
545         }
546         chop_crlf(ib);
547         return (1);
548 }
549
550 /*)Function     int     more()
551  *
552  *      The function more() scans the input text line
553  *      skipping white space (SPACES and TABS) and returns a (0)
554  *      if the end of the line or a comment delimeter (;) is found,
555  *      or a (1) if their are additional characters in the line.
556  *
557  *      local variables:
558  *              int     c               next character from
559  *                                      the input text line
560  *
561  *      global variables:
562  *              none
563  *
564  *      called functions:
565  *              char    getnb()         lklex.c
566  *              VOID    unget()         lklex.c
567  *
568  *      side effects:
569  *              use of getnb() and unget() updates the global pointer ip
570  *              the position in the current input text line
571  */
572
573 int
574 more()
575 {
576         register int c;
577
578         c = getnb();
579         unget(c);
580         return( (c == '\0' || c == ';') ? 0 : 1 );
581 }
582
583 /*)Function     char    endline()
584  *
585  *      The function endline() scans the input text line
586  *      skipping white space (SPACES and TABS) and returns the next
587  *      character or a (0) if the end of the line is found or a
588  *      comment delimiter (;) is found.
589  *
590  *      local variables:
591  *              int     c               next character from
592  *                                      the input text line
593  *
594  *      global variables:
595  *              none
596  *
597  *      called functions:
598  *              char    getnb()         lklex.c
599  *
600  *      side effects:
601  *              Use of getnb() updates the global pointer ip the
602  *              position in the current input text line.
603  */
604
605 char
606 endline()
607 {
608         register int c;
609
610         c = getnb();
611         return( (c == '\0' || c == ';') ? 0 : c );
612 }
613
614 /*)Function     VOID    chop_crlf(str)
615  *
616  *              char    *str            string to chop
617  *
618  *      The function chop_crlf() removes trailing LF or CR/LF from
619  *      str, if present.
620  *
621  *      local variables:
622  *              int     i               string length
623  *
624  *      global variables:
625  *              none
626  *
627  *      functions called:
628  *              none
629  *
630  *      side effects:
631  *              none
632  */
633
634 VOID
635 chop_crlf(char *str)
636 {
637         register int i;
638
639         i = strlen(str);
640         if (i >= 1 && str[i-1] == '\n') str[i-1] = 0;
641         if (i >= 2 && str[i-2] == '\r') str[i-2] = 0;
642 }