Hackfix and re-enable strtoull and wcstoull, see bug #3798.
[sdcc.git] / sdcc / debugger / mcs51 / symtab.c
blobd6eb3c44e0ee861f0d5091f03d2b1aec883867e2
1 /*-------------------------------------------------------------------------
2 symtab.c - Header file for symbol table for sdcdb ( debugger )
3 Written By - Sandeep Dutta . sandeep.dutta@usa.net (1999)
5 This program is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by the
7 Free Software Foundation; either version 2, or (at your option) any
8 later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 In other words, you are welcome to use, share and improve this program.
20 You are forbidden to forbid anyone else to use, share and improve
21 what you give them. Help stamp out software-hoarding!
22 -------------------------------------------------------------------------*/
24 #include "sdcdb.h"
25 #include "symtab.h"
26 #include "newalloc.h"
28 structdef *structWithName (char *);
29 DEFSETFUNC(symWithRName);
31 #define LEVEL_UNIT 65536
33 /*-----------------------------------------------------------------*/
34 /* gc_strcat - allocate and return concatenated strings */
35 /*-----------------------------------------------------------------*/
36 char *gc_strcat(const char *s1, const char *s2, const char *s3)
38 char *p = Safe_malloc(strlen(s1) + strlen(s2) + strlen(s3) + 1);
39 strcat(strcat(strcpy(p, s1), s2), s3);
40 return p;
43 /*------------------------------------------------------------------*/
44 /* getSize - returns size of a type chain in bits */
45 /*------------------------------------------------------------------*/
46 unsigned int getSize ( st_link *p )
48 /* if nothing return 0 */
49 if ( ! p )
50 return 0;
52 if ( IS_SPEC(p) ) /* if this is the specifier then */
54 switch (SPEC_NOUN(p)) /* depending on the specifier type */
56 case V_INT:
57 return (IS_LONG(p) ? LONGSIZE : ( IS_SHORT(p) ? SHORTSIZE: INTSIZE));
58 case V_FLOAT:
59 return FLOATSIZE;
60 case V_CHAR:
61 return CHARSIZE;
62 case V_VOID:
63 return 0;
64 case V_STRUCT:
65 return SPEC_STRUCT(p)->size;
66 case V_LABEL:
67 return 0 ;
68 case V_SBIT:
69 return BITSIZE;
70 case V_BIT:
71 return ((SPEC_BLEN(p) / 8) + (SPEC_BLEN(p) % 8 ? 1 : 0));
72 default:
73 return 0;
77 /* this is a specifier */
78 switch (DCL_TYPE(p))
80 case FUNCTION:
81 return 2;
82 case ARRAY:
83 return DCL_ELEM(p) * getSize (p->next);
84 case IPOINTER:
85 case PPOINTER:
86 case POINTER:
87 return ( PTRSIZE );
88 case FPOINTER:
89 case CPOINTER:
90 return ( FPTRSIZE );
91 case GPOINTER:
92 return ( GPTRSIZE );
94 default:
95 return 0;
99 /*-----------------------------------------------------------------*/
100 /* parseFunc - creates a function record entry */
101 /*-----------------------------------------------------------------*/
102 void parseFunc (char *line)
104 function *func;
105 char *rs = line;
106 int i;
108 while (*rs && *rs != '(')
109 rs++;
110 *--rs = '\0';
112 func = Safe_calloc(1, sizeof(function));
113 func->sym = NULL;
114 applyToSetFTrue(symbols, symWithRName, line, &func->sym);
115 *rs++ = '0';
116 if (! func->sym)
117 func->sym = parseSymbol(line, &rs, 1);
118 func->sym->isfunc = 1;
119 func->modName = currModName;
120 while(*rs && *rs != ',')
121 rs++;
122 rs++;
123 sscanf(rs, "%d,%d,%hd", &i,
124 &(SPEC_INTN(func->sym->etype)),
125 &(SPEC_BANK(func->sym->etype)));
126 SPEC_INTRTN(func->sym->etype) = i;
127 addSet(&functions, func);
130 /*-----------------------------------------------------------------*/
131 /* parseTypeInfo - parse the type info of a symbol expects the type*/
132 /* info to be of the form */
133 /* ({<size>}<type info chain) */
134 /*-----------------------------------------------------------------*/
135 static char *parseTypeInfo (symbol *sym, char *s)
137 char *bp;
139 s += 2; /* go past the ({ */
140 /* get the size */
141 sym->size = (short)strtol (s, &bp, 10);
142 /* bp now points to '}' ... go past it */
143 s = ++bp;
144 while (*s != ')') /* till we reach the end */
146 st_link *type;
147 type = Safe_calloc(1, sizeof(st_link));
148 if (*s == ',')
149 s++;
151 /* is a declarator */
152 if (*s == 'D')
154 s++;
155 switch (*s)
157 case 'F':
158 DCL_TYPE(type) = FUNCTION;
159 s++;
160 break;
161 case 'G':
162 DCL_TYPE(type) = GPOINTER;
163 s++;
164 break;
165 case 'C':
166 DCL_TYPE(type) = CPOINTER;
167 s++;
168 break;
169 case 'X':
170 DCL_TYPE(type) = FPOINTER;
171 s++;
172 break;
173 case 'D':
174 DCL_TYPE(type) = POINTER;
175 s++;
176 break;
177 case 'I':
178 DCL_TYPE(type) = IPOINTER;
179 s++;
180 break;
181 case 'P':
182 DCL_TYPE(type) = PPOINTER;
183 s++;
184 break;
185 case 'A':
186 s++;
187 DCL_TYPE(type) = ARRAY ;
188 DCL_ELEM(type) = (short)strtol(s,&s,10);
189 break;
192 else
194 /* is a specifier */
195 type->class = SPECIFIER;
196 s++;
197 switch (*s)
199 case 'L':
200 SPEC_NOUN(type) = V_INT;
201 SPEC_LONG(type) = 1;
202 s++;
203 break;
204 case 'I':
205 SPEC_NOUN(type) = V_INT;
206 s++;
207 break;
208 case 'S':
209 case 'C':
210 SPEC_NOUN(type) = V_CHAR ;
211 s++;
212 break;
213 case 'V':
214 SPEC_NOUN(type) = V_VOID;
215 s++;
216 break;
217 case 'F':
218 SPEC_NOUN(type) = V_FLOAT;
219 s++;
220 break;
221 case 'T':
222 s++;
223 SPEC_NOUN(type) = V_STRUCT;
225 char *ss = strtok(strdup(s), ",):");
227 SPEC_STRUCT(type) = structWithName(ss);
228 free(ss);
230 break;
231 case 'X':
232 s++;
233 SPEC_NOUN(type) = V_SBIT;
234 break;
235 case 'B':
236 SPEC_NOUN(type) = V_BIT;
237 s++;
238 SPEC_BSTR(type) = strtol(s, &s, 10);
239 s++;
240 SPEC_BLEN(type) = strtol(s, &s, 10);
241 break;
243 while (*s != ':')
244 s++;
245 s++;
246 if (*s++ == 'S')
247 SPEC_USIGN(type) = 0;
248 else
249 SPEC_USIGN(type) = 1;
252 /* add the type to the symbol's type chain */
253 if (sym->type)
254 sym->etype = sym->etype->next = type;
255 else
256 sym->type = sym->etype = type;
259 return ++s;
262 int calcLevel(int level1, int level2)
264 return (level1 * LEVEL_UNIT) + level2;
267 int parseLevel(char *s, char **rs, int base)
269 char *bp = s;
271 long level = strtol (s, &bp, 10);
272 if( *bp == '_')
274 s = ++bp;
275 level = calcLevel(level, strtol (s, &bp, 10));
278 *rs = bp;
280 return (int) level;
283 char *allocRName(char *start, int length)
285 int idx = length > 2 ? length - 2 : 0;
287 while(idx && start[idx] != '$')
289 if(start[idx] == '_')
291 start[idx++] = '$';
292 length = idx;
293 break;
295 --idx;
298 return alloccpy(start, length);
301 /*-----------------------------------------------------------------*/
302 /* symFromRec - parse a symbol record and extract and create a sym */
303 /* expects the input string to be of the form */
304 /* {G|F<filename>|L<filename>'.'<functionName>}'$' */
305 /* <name>'$'<level>'$'<block><type info> */
306 /*-----------------------------------------------------------------*/
307 symbol *parseSymbol (char *s, char **rs, int doadd)
309 symbol *nsym;
310 char save_ch;
311 char *bp = s;
313 /* go the mangled name */
314 for ( bp = s; *bp && *bp != '('; bp++ )
316 save_ch = *--bp;
317 *bp = '\0';
318 nsym = NULL;
319 if ( doadd == 2 )
321 /* add only if not present and if linkrecord before symbol record */
322 if ( applyToSetFTrue(symbols, symWithRName, s, &nsym))
324 if ( nsym->rname != nsym->name )
325 return NULL;
326 doadd = 0;
329 if ( ! nsym )
331 nsym = Safe_calloc(1, sizeof(symbol));
332 nsym->rname = allocRName(s, bp - s);
334 *bp = save_ch;
335 /* if this is a Global Symbol */
336 nsym->scopetype = *s;
337 s++;
338 if (nsym->scopetype != 'G')
340 /* get the function name it is local to */
341 bp = s;
342 while (*s != '$')
343 s++;
344 nsym->sname = alloccpy(bp, s - bp);
347 /* next get the name */
348 bp = ++s;
349 while ( *s != '$' )
350 s++;
351 nsym->name = alloccpy(bp, s - bp);
353 s++;
354 /* get the level number */
355 nsym->level = parseLevel (s, &bp, 10);
356 s = ++bp;
357 /* skip the '$' & get the block number */
358 nsym->block = (short)strtol (s, &bp, 10);
360 s = parseTypeInfo(nsym, bp);
362 /* get the address space after going past the comma */
363 s++;
364 nsym->addrspace = *s;
366 s+= 2;
367 nsym->isonstack = (short)strtol(s, &s, 10);
368 /* get the stack offset */
369 s++;
370 nsym->offset = strtol(s, &s, 10);
372 if ( nsym->addrspace == 'R' )
374 /* get registeroffset */
375 while (*s && *s != '[')
376 s++;
377 s++;
378 if ( *s == 'r' )
380 nsym->addr = strtol(s+1, &s, 10);
382 while (*s && *s != ']')
383 s++;
386 *rs = s;
387 if ( doadd )
388 addSet(&symbols, nsym);
390 Dprintf(D_symtab, ("symtab: par %s(0x%x) add=%d sym=%p\n",
391 nsym->name, nsym->addr, doadd, nsym));
393 Dprintf(D_symtab, ("symbol\n name: %s\n size: %d\n level: %hd\n block: %hd\n isonstack: %hd\n",
394 nsym->name, nsym->size, nsym->level, nsym->block, nsym->isonstack));
396 Dprintf(D_symtab, (" isfunc: %d\n offset: %d\n addr: %d\n eaddr: %d\n",
397 nsym->isfunc, nsym->offset, nsym->addr, nsym->eaddr));
399 Dprintf(D_symtab, (" addr_type: %c\n type: %p\n etype: %p\n",
400 nsym->addr_type, nsym->type, nsym->type));
402 Dprintf(D_symtab, (" scopetype: %c\n sname: %s\n rname: %s\n addrspace: %c\n",
403 nsym->scopetype, nsym->sname, nsym->rname, nsym->addrspace));
405 return nsym;
408 /*-----------------------------------------------------------------*/
409 /* parseStruct - parses a structure record expected in format */
410 /* {F<filename>}$<tag>[()()()...] */
411 /*-----------------------------------------------------------------*/
412 structdef *parseStruct (char *s)
414 structdef *nsdef ;
415 char *bp;
416 char *name;
417 symbol *fields = NULL;
419 while (*s != '$')
420 s++;
422 bp =++s;
423 while (*s != '[')
424 s++;
425 name = alloccpy(bp,s - bp);
426 nsdef = structWithName(name);
427 nsdef->fields = NULL;
428 nsdef->size = 0;
429 s++;
430 while (*s && *s != ']')
432 int offset ;
433 symbol *sym ;
434 while (!isdigit(*s))
435 s++;
436 offset = strtol(s,&s,10);
437 while (*s != ':')
438 s++;
439 s++;
440 sym = parseSymbol(s,&s,0);
441 sym->offset = offset ;
442 s += 3;
443 if (!fields)
444 fields = nsdef->fields = sym;
445 else
446 fields = fields->next = sym;
447 nsdef->size += sym->size;
450 return nsdef;
453 /*-----------------------------------------------------------------*/
454 /* parseModule - creates a module with a given name */
455 /*-----------------------------------------------------------------*/
456 module *parseModule (char *s, bool createName )
458 module *nmod ;
459 char buffer[512];
461 nmod = Safe_calloc(1, sizeof(module));
463 addSet (&modules, nmod);
465 /* create copy file name */
466 nmod->name = s;
468 if (createName)
470 sprintf(buffer, "%s.c", s);
471 nmod->c_name = Safe_malloc(strlen(buffer)+1);
472 strcpy(nmod->c_name, buffer);
474 sprintf(buffer, "%s.asm", s);
475 nmod->asm_name = Safe_malloc(strlen(buffer)+1);
476 strcpy(nmod->asm_name, buffer);
479 return nmod;
482 /*-----------------------------------------------------------------*/
483 /* moduleWithName - finds and returns a module with a given name */
484 /*-----------------------------------------------------------------*/
485 DEFSETFUNC(moduleWithName)
487 module *mod = item;
488 V_ARG(char *, s);
489 V_ARG(module **, rmod);
491 if (*rmod)
492 return 0;
494 if (strcmp(mod->name, s) == 0)
496 *rmod = mod;
497 return 1;
500 return 0;
503 /*-----------------------------------------------------------------*/
504 /* moduleWithCName - finds and returns a module with a given c_name*/
505 /*-----------------------------------------------------------------*/
506 DEFSETFUNC(moduleWithCName)
508 module *mod = item;
509 V_ARG(char *, s);
510 V_ARG(module **, rmod);
512 if (*rmod)
513 return 0;
515 if (strcmp(mod->c_name, s) == 0)
517 *rmod = mod;
518 return 1;
521 return 0;
524 /*-----------------------------------------------------------------*/
525 /* moduleWithAsmName - finds & returns a module with given asm_name*/
526 /*-----------------------------------------------------------------*/
527 DEFSETFUNC(moduleWithAsmName)
529 module *mod = item;
530 V_ARG(char *, s);
531 V_ARG(module **, rmod);
533 if (*rmod)
534 return 0;
536 if (strcmp(mod->asm_name, s) == 0)
538 *rmod = mod;
539 return 1;
542 return 0;
545 /*-----------------------------------------------------------------*/
546 /* structWithName - returns a structure with a given name */
547 /*-----------------------------------------------------------------*/
548 structdef *structWithName (char *s)
550 int i;
551 structdef *nsdef ;
553 /* go thru the struct table looking for a match */
554 for ( i = 0 ; i < nStructs ; i++ )
556 if (strcmp(currModName,structs[i]->sname) == 0 &&
557 strcmp(s,structs[i]->tag) == 0)
559 return structs[i];
563 nsdef = Safe_calloc(1,sizeof(structdef));
564 nsdef->tag = alloccpy(s,strlen(s));
565 nsdef->sname = currModName ;
567 nStructs++;
568 structs = (struct structdef **)resize((void **)structs,nStructs);
569 structs[nStructs-1] = nsdef;
570 return nsdef;
573 /*-----------------------------------------------------------------*/
574 /* symWithRName - look for symbol with mangled name = parm */
575 /*-----------------------------------------------------------------*/
576 DEFSETFUNC(symWithRName)
578 symbol *sym = item;
579 V_ARG(char *, s);
580 V_ARG(symbol **, rsym);
582 if (*rsym)
583 return 0;
585 if (strcmp(sym->rname, s) == 0)
587 *rsym = sym;
588 return 1;
591 return 0;
594 /*-----------------------------------------------------------------*/
595 /* funcWithRName - look for function with name */
596 /*-----------------------------------------------------------------*/
597 DEFSETFUNC(funcWithRName)
599 function *func = item;
600 V_ARG(char *,s);
601 V_ARG(function **,rfunc);
603 if (*rfunc)
604 return 0;
606 if (strcmp(func->sym->rname,s) == 0)
608 *rfunc = func;
609 return 1;
612 return 0;
615 /*-----------------------------------------------------------------*/
616 /* symLocal - local symbol respecting blocks & levels */
617 /*-----------------------------------------------------------------*/
618 DEFSETFUNC(symLocal)
620 symbol *sym = item;
621 V_ARG(char *, name);
622 V_ARG(char *, sname);
623 V_ARG(int, block);
624 V_ARG(int, level);
625 V_ARG(symbol **, rsym);
627 if (strcmp(name, sym->name) == 0 && /* name matches */
628 sym->scopetype != 'G' && /* local scope */
629 sym->sname &&
630 strcmp(sym->sname, sname) == 0 && /* scope == specified scope */
631 sym->block <= block && /* block & level kindo matches */
632 sym->level <= level)
634 /* if a symbol was previously found then
635 sure that ones block & level are less
636 then this one */
637 if (*rsym && (*rsym)->block >= block && (*rsym)->level >= level)
638 return 0;
640 *rsym = sym;
641 return 1;
644 return 0;
647 /*-----------------------------------------------------------------*/
648 /* symGlobal - return global symbol of name */
649 /*-----------------------------------------------------------------*/
650 DEFSETFUNC(symGlobal)
652 symbol *sym = item;
653 V_ARG(char *, name);
654 V_ARG(symbol **, rsym);
656 if (*rsym)
657 return 0;
659 /* simple :: global & name matches */
660 if (sym->scopetype == 'G' &&
661 strcmp(sym->name, name) == 0)
663 *rsym = sym;
664 return 1;
667 return 0;
670 /*-----------------------------------------------------------------*/
671 /* symLookup - determine symbol from name & context */
672 /*-----------------------------------------------------------------*/
673 symbol *symLookup (char *name, context *ctxt)
675 symbol *sym = NULL;
677 if ((ctxt) && (ctxt->func) &&
678 (ctxt->func->sym) && (ctxt->func->sym->name))
680 char *sname = gc_strcat(ctxt->func->mod->name, ".", ctxt->func->sym->name);
681 /* first try & find a local variable for the given name */
682 if ( applyToSet(symbols, symLocal,
683 name,
684 sname,
685 ctxt->block,
686 ctxt->level,
687 &sym))
689 Safe_free(sname);
690 return sym;
692 Safe_free(sname);
693 sym = NULL;
696 if ((ctxt) && (ctxt->func) &&
697 (ctxt->func->mod) && (ctxt->func->mod->name))
699 /* then try local to this module */
700 if (applyToSet(symbols, symLocal,
701 name,
702 ctxt->func->mod->name,
705 &sym))
707 return sym;
709 sym = NULL;
712 /* no:: try global */
713 if ( applyToSet(symbols, symGlobal, name, &sym))
714 return sym;
716 /* cannot find return null */
717 return NULL;
720 /*-----------------------------------------------------------------*/
721 /* lnkFuncEnd - link record for end of function */
722 /*-----------------------------------------------------------------*/
723 static void lnkFuncEnd (char *s)
725 char sname[128], *bp = sname;
726 function *func;
728 /* copy till we get to a ':' */
729 while ( *s != ':' )
730 *bp++ = *s++;
731 bp -= 1;
732 *bp = '\0';
734 func = NULL;
735 if (!applyToSet(functions,funcWithRName,sname,&func))
736 return ;
738 s++;
739 sscanf(s,"%x",&func->sym->eaddr);
741 Dprintf(D_symtab, ("symtab: ead %s(0x%x)\n",func->sym->name,func->sym->eaddr));
744 /*-----------------------------------------------------------------*/
745 /* lnkSymRec - record for a symbol */
746 /*-----------------------------------------------------------------*/
747 static void lnkSymRec (char *s)
749 char *bp, save_ch ;
750 symbol *sym;
752 /* search to a ':' */
753 for ( bp = s; *bp && *bp != ':'; bp++ );
754 save_ch = *--bp;
755 *bp = '\0';
757 sym = NULL;
758 applyToSetFTrue(symbols,symWithRName,s,&sym);
759 if (! sym)
761 sym = Safe_calloc(1,sizeof(symbol));
762 sym->rname = allocRName(s,bp - s);
763 sym->scopetype = *s;
764 sym->name = sym->rname;
765 addSet(&symbols,sym);
767 *bp = save_ch;
768 if ( *bp )
770 sscanf(bp+2,"%x",&sym->addr);
772 Dprintf(D_symtab, ("symtab: lnk %s(0x%x)\n",sym->name,sym->addr));
775 /*-----------------------------------------------------------------*/
776 /* lnkAsmSrc - process linker record for asm sources */
777 /*-----------------------------------------------------------------*/
778 static void lnkAsmSrc (char *s)
780 char mname[128], *bp = mname;
781 int line ;
782 unsigned addr;
783 module *mod = NULL;
785 /* input will be of format
786 filename$<line>:<address> */
787 while (*s != '$' && *s != '.')
788 *bp++ = *s++;
789 *bp = '\0';
790 /* skip to line stuff */
791 while (*s != '$')
792 s++;
794 if (!applyToSet(modules, moduleWithName, mname, &mod))
795 return ;
797 if (sscanf(s, "$%d:%x", &line, &addr) != 2)
798 return ;
800 line--;
801 if (line < mod->nasmLines)
803 mod->asmLines[line]->addr = addr;
804 Dprintf(D_symtab, ("symtab: asm %s(%d:0x%x) %s", mod->asm_name, line, addr, mod->asmLines[line]->src));
808 /*-----------------------------------------------------------------*/
809 /* lnkCSrc - process linker output for c source */
810 /*-----------------------------------------------------------------*/
811 static void lnkCSrc (char *s)
813 char mname[128], *bp = mname;
814 int block,level,line;
815 int level1 = 0;
816 int level2 = 0;
817 unsigned int addr;
818 module *mod ;
820 /* input will be of format
821 filename.ext$<line>$<level>$<block>:<address> */
822 /* get the module name */
823 while (*s != '$' )
824 *bp++ = *s++;
825 *bp = '\0';
826 /* skip the extension */
827 while (*s != '$')
828 s++;
830 if (sscanf(s,"$%d$%d$%d:%x", &line,&level2,&block,&addr) != 4)
831 if (sscanf(s,"$%d$%d_%d$%d:%x", &line,&level1,&level2,&block,&addr) != 5)
832 return ;
834 level = calcLevel(level1, level2);
836 mod = NULL;
837 if (!applyToSet(modules,moduleWithCName,mname,&mod))
839 mod = parseModule(mname, FALSE);
840 mod->c_name = alloccpy(mname,strlen(mname));
841 mod->cfullname=searchDirsFname(mod->c_name);
842 mod->cLines = loadFile(mod->c_name,&mod->ncLines);
845 line--;
846 /* one line can have more than one address : (for loops !)*/
847 if (line < mod->ncLines && line > 0 /*&&
848 ( !mod->cLines[line]->addr ||
849 mod->cLines[line]->level > level )*/ )
851 if ( mod->cLines[line]->addr != INT_MAX )
853 /* save double line information for exepoints */
854 exePoint *ep ;
855 ep = Safe_calloc(1,sizeof(exePoint));
856 ep->addr = mod->cLines[line]->addr ;
857 ep->line = line;
858 ep->block= mod->cLines[line]->block;
859 ep->level= mod->cLines[line]->level;
860 addSet(&mod->cfpoints,ep);
861 Dprintf(D_symtab, ("symtab: exe %s(%d:0x%x) %s", mod->c_name,
862 line+1, addr, mod->cLines[line]->src));
864 mod->cLines[line]->addr = addr;
865 mod->cLines[line]->block = block;
866 mod->cLines[line]->level = level;
867 Dprintf(D_symtab, ("symtab: ccc %s(%d:0x%x) %s", mod->c_name,
868 line+1, addr, mod->cLines[line]->src));
870 return;
873 /*-----------------------------------------------------------------*/
874 /* parseLnkRec - parses a linker generated record */
875 /*-----------------------------------------------------------------*/
876 void parseLnkRec (char *s)
878 /* link records can be several types
879 dpeneding on the type do */
881 switch (*s)
883 /* c source line address */
884 case 'C':
885 lnkCSrc(s+2);
886 break;
887 /* assembler source address */
888 case 'A':
889 lnkAsmSrc(s+2);
890 break;
892 case 'X':
893 lnkFuncEnd(s+1);
894 break;
896 default :
897 lnkSymRec(s);
898 break;