"Fossies" - the Fresh Open Source Software Archive

Member "bas-2.6/program.c" (2 Jul 2019, 19239 Bytes) of package /linux/privat/bas-2.6.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "program.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.5_vs_2.6.

    1 /* Program storage. */
    2 /* #includes */ /*{{{C}}}*//*{{{*/
    3 #undef  _POSIX_SOURCE
    4 #define _POSIX_SOURCE   1
    5 #undef  _POSIX_C_SOURCE
    6 #define _POSIX_C_SOURCE 2
    7 
    8 #include "config.h"
    9 
   10 #include <assert.h>
   11 #include <errno.h>
   12 #ifdef HAVE_GETTEXT
   13 #include <libintl.h>
   14 #define _(String) gettext(String)
   15 #else
   16 #define _(String) String
   17 #endif
   18 #include <stdio.h>
   19 #include <stdlib.h>
   20 #include <string.h>
   21 
   22 #include "auto.h"
   23 #include "error.h"
   24 #include "fs.h"
   25 #include "program.h"
   26 /*}}}*/
   27 
   28 struct Program *Program_new(struct Program *this) /*{{{*/
   29 {
   30   this->trace=0;
   31   this->size=0;
   32   this->numbered=1;
   33   this->capacity=0;
   34   this->runnable=0;
   35   this->unsaved=0;
   36   this->code=(struct Token**)0;
   37   this->scope=(struct Scope*)0;
   38   String_new(&this->name);
   39   return this;
   40 }
   41 /*}}}*/
   42 void Program_destroy(struct Program *this) /*{{{*/
   43 {
   44   while (this->size) Token_destroy(this->code[--this->size]);
   45   if (this->capacity) free(this->code);
   46   this->code=(struct Token**)0;
   47   this->scope=(struct Scope*)0;
   48   String_destroy(&this->name);
   49 }
   50 /*}}}*/
   51 void Program_norun(struct Program *this) /*{{{*/
   52 {
   53   this->runnable=0;
   54   this->scope=(struct Scope*)0;
   55 }
   56 /*}}}*/
   57 void Program_store(struct Program *this, struct Token *line, long int where) /*{{{*/
   58 {
   59   int i;
   60 
   61   assert(line->type==T_INTEGER || line->type==T_UNNUMBERED);
   62   this->runnable=0;
   63   this->unsaved=1;
   64   if (line->type==T_UNNUMBERED) this->numbered=0;
   65   if (where)
   66   {
   67     int last=-1;
   68 
   69     for (i=0; i<this->size; ++i)
   70     {
   71       assert(this->code[i]->type==T_INTEGER || this->code[i]->type==T_UNNUMBERED);
   72       if (where>last && where<this->code[i]->u.integer)
   73       {
   74         if ((this->size+1)>=this->capacity)
   75         {
   76           this->code=realloc(this->code,sizeof(struct Token*)*(this->capacity?(this->capacity*=2):(this->capacity=256)));
   77         }
   78         memmove(&this->code[i+1],&this->code[i],(this->size-i)*sizeof(struct Token*));
   79         this->code[i]=line;
   80         ++this->size;
   81         return;
   82       }
   83       else if (where==this->code[i]->u.integer)
   84       {
   85         Token_destroy(this->code[i]);
   86         this->code[i]=line;
   87         return;
   88       }
   89       last=this->code[i]->u.integer;
   90     }
   91   }
   92   else i=this->size;
   93   if ((this->size+1)>=this->capacity)
   94   {
   95     this->code=realloc(this->code,sizeof(struct Token*)*(this->capacity?(this->capacity*=2):(this->capacity=256)));
   96   }
   97   this->code[i]=line;
   98   ++this->size;
   99 }
  100 /*}}}*/
  101 void Program_delete(struct Program *this, const struct Pc *from, const struct Pc *to) /*{{{*/
  102 {
  103   int i, first, last;
  104 
  105   this->runnable=0;
  106   this->unsaved=1;
  107   first=from ? from->line : 0;
  108   last=to ? to->line : this->size-1;
  109   for (i=first; i<=last; ++i) Token_destroy(this->code[i]);
  110   if ((last+1)!=this->size) memmove(&this->code[first],&this->code[last+1],(this->size-last+1)*sizeof(struct Token*));
  111   this->size-=(last-first+1);
  112 }
  113 /*}}}*/
  114 void Program_addScope(struct Program *this, struct Scope *scope) /*{{{*/
  115 {
  116   struct Scope *s;
  117 
  118   s=this->scope;
  119   this->scope=scope;
  120   scope->next=s;
  121 }
  122 /*}}}*/
  123 struct Pc *Program_goLine(struct Program *this, long int line, struct Pc *pc) /*{{{*/
  124 {
  125   int i;
  126 
  127   for (i=0; i<this->size; ++i)
  128   {
  129     if (this->code[i]->type==T_INTEGER && line==this->code[i]->u.integer)
  130     {
  131       pc->line=i;
  132       pc->token=this->code[i]+1;
  133       return pc;
  134     }
  135   }
  136   return (struct Pc*)0;
  137 }
  138 /*}}}*/
  139 struct Pc *Program_fromLine(struct Program *this, long int line, struct Pc *pc) /*{{{*/
  140 {
  141   int i;
  142 
  143   for (i=0; i<this->size; ++i)
  144   {
  145     if (this->code[i]->type==T_INTEGER && this->code[i]->u.integer>=line)
  146     {
  147       pc->line=i;
  148       pc->token=this->code[i]+1;
  149       return pc;
  150     }
  151   }
  152   return (struct Pc*)0;
  153 }
  154 /*}}}*/
  155 struct Pc *Program_toLine(struct Program *this, long int line, struct Pc *pc) /*{{{*/
  156 {
  157   int i;
  158 
  159   for (i=this->size-1; i>=0; --i)
  160   {
  161     if (this->code[i]->type==T_INTEGER && this->code[i]->u.integer<=line)
  162     {
  163       pc->line=i;
  164       pc->token=this->code[i]+1;
  165       return pc;
  166     }
  167   }
  168   return (struct Pc*)0;
  169 }
  170 /*}}}*/
  171 int Program_scopeCheck(struct Program *this, struct Pc *pc, struct Pc *fn) /*{{{*/
  172 {
  173   struct Scope *scope;
  174 
  175   if (fn==(struct Pc*)0) /* jump from global block must go to global pc */
  176   {
  177     for (scope=this->scope; scope; scope=scope->next)
  178     {
  179       if (pc->line<scope->begin.line) continue;
  180       if (pc->line==scope->begin.line && pc->token<=scope->begin.token) continue;
  181       if (pc->line>scope->end.line) continue;
  182       if (pc->line==scope->end.line && pc->token>scope->end.token) continue;
  183       return -1;
  184     }
  185   }
  186   else /* jump from local block must go to local block */
  187   {
  188     scope=&(fn->token+1)->u.identifier->sym->u.sub.u.def.scope;
  189     if (pc->line<scope->begin.line) return -1;
  190     if (pc->line==scope->begin.line && pc->token<=scope->begin.token) return -1;
  191     if (pc->line>scope->end.line) return -1;
  192     if (pc->line==scope->end.line && pc->token>scope->end.token) return -1;
  193   }
  194   return 0;
  195 }
  196 /*}}}*/
  197 struct Pc *Program_dataLine(struct Program *this, long int line, struct Pc *pc) /*{{{*/
  198 {
  199   if ((pc=Program_goLine(this,line,pc))==(struct Pc*)0) return (struct Pc*)0;
  200   while (pc->token->type!=T_DATA)
  201   {
  202     if (pc->token->type==T_EOL) return (struct Pc*)0;
  203     else ++pc->token;
  204   }
  205   return pc;
  206 }
  207 /*}}}*/
  208 struct Pc *Program_imageLine(struct Program *this, long int line, struct Pc *pc) /*{{{*/
  209 {
  210   if ((pc=Program_goLine(this,line,pc))==(struct Pc*)0) return (struct Pc*)0;
  211   while (pc->token->type!=T_IMAGE)
  212   {
  213     if (pc->token->type==T_EOL) return (struct Pc*)0;
  214     else ++pc->token;
  215   }
  216   ++pc->token;
  217   if (pc->token->type!=T_STRING) return (struct Pc*)0;
  218   return pc;
  219 }
  220 /*}}}*/
  221 long int Program_lineNumber(const struct Program *this, const struct Pc *pc) /*{{{*/
  222 {
  223   if (pc->line==-1) return 0;
  224   if (this->numbered) return (this->code[pc->line]->u.integer);
  225   else return (pc->line+1);
  226 }
  227 /*}}}*/
  228 struct Pc *Program_beginning(struct Program *this, struct Pc *pc) /*{{{*/
  229 {
  230   if (this->size==0) return (struct Pc*)0;
  231   else
  232   {
  233     pc->line=0;
  234     pc->token=this->code[0]+1;
  235     return pc;
  236   }
  237 }
  238 /*}}}*/
  239 struct Pc *Program_end(struct Program *this, struct Pc *pc) /*{{{*/
  240 {
  241   if (this->size==0) return (struct Pc*)0;
  242   else
  243   {
  244     pc->line=this->size-1;
  245     pc->token=this->code[this->size-1];
  246     while (pc->token->type!=T_EOL) ++pc->token;
  247     return pc;
  248   }
  249 }
  250 /*}}}*/
  251 struct Pc *Program_nextLine(struct Program *this, struct Pc *pc) /*{{{*/
  252 {
  253   if (pc->line+1==this->size) return (struct Pc*)0;
  254   else
  255   {
  256     pc->token=this->code[++pc->line]+1;
  257     return pc;
  258   }
  259 }
  260 /*}}}*/
  261 int Program_skipEOL(struct Program *this, struct Pc *pc, int dev, int tr) /*{{{*/
  262 {
  263   if (pc->token->type==T_EOL)
  264   {
  265     if (pc->line==-1 || pc->line+1==this->size) return 0;
  266     {
  267       pc->token=this->code[++pc->line]+1;
  268       Program_trace(this,pc,dev,tr);
  269       return 1;
  270     }
  271   }
  272   else return 1;
  273 }
  274 /*}}}*/
  275 void Program_trace(struct Program *this, struct Pc *pc, int dev, int tr) /*{{{*/
  276 {
  277   if (tr && this->trace && pc->line!=-1)
  278   {
  279     char buf[40];
  280 
  281     sprintf(buf,"<%ld>\n",this->code[pc->line]->u.integer);
  282     FS_putChars(dev,buf);
  283   }
  284 }
  285 /*}}}*/
  286 void Program_PCtoError(struct Program *this, struct Pc *pc, struct Value *v) /*{{{*/
  287 {
  288   struct String s;
  289 
  290   String_new(&s);
  291   if (pc->line>=0)
  292   {
  293     if (pc->line<(this->size-1) || pc->token->type!=T_EOL)
  294     {
  295       String_appendPrintf(&s,_(" in line %ld at:\n"),Program_lineNumber(this,pc));
  296       Token_toString(this->code[pc->line],(struct Token*)0,&s,(int*)0,-1);
  297       Token_toString(this->code[pc->line],pc->token,&s,(int*)0,-1);
  298       String_appendPrintf(&s,"^\n");
  299     }
  300     else
  301     {
  302       String_appendPrintf(&s,_(" at: end of program\n"));
  303     }
  304   }
  305   else
  306   {
  307     String_appendPrintf(&s,_(" at: "));
  308     if (pc->token->type!=T_EOL) Token_toString(pc->token,(struct Token*)0,&s,(int*)0,-1);
  309     else String_appendPrintf(&s,_("end of line\n"));
  310   }
  311   Value_errorSuffix(v,s.character);
  312   String_destroy(&s);
  313 }
  314 /*}}}*/
  315 struct Value *Program_merge(struct Program *this, int dev, struct Value *value) /*{{{*/
  316 {
  317   struct String s;
  318   int l,err=0;
  319 
  320   l=0;
  321   while (String_new(&s),(err=FS_appendToString(dev,&s,1))!=-1 && s.length)
  322   {
  323     struct Token *line;
  324 
  325     ++l;
  326     if (l!=1 || s.character[0]!='#') 
  327     {
  328       line=Token_newCode(s.character);
  329       if (line->type==T_INTEGER && line->u.integer>0) Program_store(this,line,this->numbered?line->u.integer:0);
  330       else if (line->type==T_UNNUMBERED) Program_store(this,line,0);
  331       else
  332       {
  333         Token_destroy(line);
  334         return Value_new_ERROR(value,INVALIDLINE,l);
  335       }
  336     }
  337     String_destroy(&s);
  338   }
  339   String_destroy(&s);
  340   if (err) return Value_new_ERROR(value,IOERROR,FS_errmsg);
  341   return (struct Value*)0;
  342 }
  343 /*}}}*/
  344 int Program_lineNumberWidth(struct Program *this) /*{{{*/
  345 {
  346   int i,w=0;
  347 
  348   for (i=0; i<this->size; ++i) if (this->code[i]->type==T_INTEGER)
  349   {
  350     int nw,ln;
  351     for (ln=this->code[i]->u.integer,nw=1; ln/=10; ++nw);
  352     if (nw>w) w=nw;
  353   }
  354   return w;
  355 }
  356 /*}}}*/
  357 struct Value *Program_list(struct Program *this, int dev, int watchIntr, struct Pc *from, struct Pc *to, struct Value *value) /*{{{*/
  358 {
  359   int i,w;
  360   int indent=0;
  361   struct String s;
  362 
  363   w=Program_lineNumberWidth(this);
  364   for (i=0; i<this->size; ++i)
  365   {
  366     String_new(&s);
  367     Token_toString(this->code[i],(struct Token*)0,&s,&indent,w);
  368     if ((from==(struct Pc *)0 || from->line<=i) && (to==(struct Pc*)0 || to->line>=i))
  369     {
  370       if (FS_putString(dev,&s)==-1) return Value_new_ERROR(value,IOERROR,FS_errmsg);
  371       if (watchIntr && FS_intr) return Value_new_ERROR(value,BREAK);
  372     }
  373     String_destroy(&s);
  374   }
  375   return (struct Value*)0;
  376 }
  377 /*}}}*/
  378 struct Value *Program_analyse(struct Program *this, struct Pc *pc, struct Value *value) /*{{{*/
  379 {
  380   int i;
  381 
  382   for (i=0; i<this->size; ++i)
  383   {
  384     pc->token=this->code[i];
  385     pc->line=i;
  386     if (pc->token->type==T_INTEGER || pc->token->type==T_UNNUMBERED) ++pc->token;
  387     for (;;)
  388     {
  389       if (pc->token->type==T_GOTO || pc->token->type==T_RESUME || pc->token->type==T_RETURN || pc->token->type==T_END || pc->token->type==T_STOP)
  390       {
  391         ++pc->token;
  392         while (pc->token->type==T_INTEGER)
  393         {
  394           ++pc->token;
  395           if (pc->token->type==T_COMMA) ++pc->token;
  396           else break;
  397         }
  398         if (pc->token->type==T_COLON)
  399         {
  400           ++pc->token;
  401           switch (pc->token->type)
  402           {
  403             case T_EOL:
  404             case T_DEFPROC:
  405             case T_SUB:
  406             case T_DEFFN:
  407             case T_FUNCTION:
  408             case T_COLON:
  409             case T_REM:
  410             case T_QUOTE: break; /* those are fine to be unreachable */
  411             default: return Value_new_ERROR(value,UNREACHABLE);
  412           }
  413         }
  414       }
  415       if (pc->token->type==T_EOL) break;
  416       else ++pc->token;
  417     }
  418   }
  419   return (struct Value*)0;
  420 }
  421 /*}}}*/
  422 void Program_renum(struct Program *this, int first, int inc) /*{{{*/
  423 {
  424   int i;
  425   struct Token *token;
  426 
  427   for (i=0; i<this->size; ++i)
  428   {
  429     for (token=this->code[i]; token->type!=T_EOL; )
  430     {
  431       if (token->type==T_GOTO
  432           || token->type==T_GOSUB
  433           || token->type==T_RESTORE
  434           || token->type==T_RESUME
  435           || token->type==T_USING)
  436       {
  437         ++token;
  438         while (token->type==T_INTEGER)
  439         {
  440           struct Pc dst;
  441 
  442           if (Program_goLine(this,token->u.integer,&dst)) token->u.integer=first+dst.line*inc;
  443           ++token;
  444           if (token->type==T_COMMA) ++token;
  445           else break;
  446         }
  447       }
  448       else ++token;
  449     }
  450   }
  451   for (i=0; i<this->size; ++i)
  452   {
  453     assert(this->code[i]->type==T_INTEGER || this->code[i]->type==T_UNNUMBERED);
  454     this->code[i]->type=T_INTEGER;
  455     this->code[i]->u.integer=first+i*inc;
  456   }
  457   this->numbered=1;
  458   this->runnable=0;
  459   this->unsaved=1;
  460 }
  461 /*}}}*/
  462 void Program_unnum(struct Program *this) /*{{{*/
  463 {
  464   char *ref;
  465   int i;
  466   struct Token *token;
  467 
  468   ref=malloc(this->size);
  469   memset(ref,0,this->size);
  470   for (i=0; i<this->size; ++i)
  471   {
  472     for (token=this->code[i]; token->type!=T_EOL; )
  473     {
  474       if (token->type==T_GOTO
  475           || token->type==T_GOSUB
  476           || token->type==T_RESTORE
  477           || token->type==T_RESUME
  478           || token->type==T_USING)
  479       {
  480         ++token;
  481         while (token->type==T_INTEGER)
  482         {
  483           struct Pc dst;
  484 
  485           if (Program_goLine(this,token->u.integer,&dst)) ref[dst.line]=1;
  486           ++token;
  487           if (token->type==T_COMMA) ++token;
  488           else break;
  489         }
  490       }
  491       else ++token;
  492     }
  493   }
  494   for (i=0; i<this->size; ++i)
  495   {
  496     assert(this->code[i]->type==T_INTEGER || this->code[i]->type==T_UNNUMBERED);
  497     if (!ref[i])
  498     {
  499       this->code[i]->type=T_UNNUMBERED;
  500       this->numbered=0;
  501     }
  502   }
  503   free(ref);
  504   this->runnable=0;
  505   this->unsaved=1;
  506 }
  507 /*}}}*/
  508 int Program_setname(struct Program *this, const char *filename) /*{{{*/
  509 {
  510   if (this->name.length) String_delete(&this->name,0,this->name.length);
  511   if (filename) return String_appendChars(&this->name,filename);
  512   else return 0;
  513 }
  514 /*}}}*/
  515 
  516 /*
  517 
  518 The list of line numbers is circular, which avoids the need to have one
  519 extra pointer for the head (for ordered output).  Instead only a pointer
  520 to the tail is needed.  The tail's next element is the head of the list.
  521 
  522 tail --> last element <-- ... <-- first element <--,
  523               \                                   /
  524                \_________________________________/
  525 
  526 */
  527 
  528 struct Xref
  529 {
  530   const void *key;
  531   struct LineNumber
  532   {
  533     struct Pc line;
  534     struct LineNumber *next;
  535   } *lines;
  536   struct Xref *l,*r;
  537 };
  538 
  539 static void Xref_add(struct Xref **root, int (*cmp)(const void*,const void*), const void *key, struct Pc *line) /*{{{*/
  540 {
  541   int res;
  542   struct LineNumber **tail;
  543   struct LineNumber *new;
  544 
  545   while (*root && (res=cmp(key,(*root)->key))) root=(res<0)?&(*root)->l:&(*root)->r;
  546   if (*root==(struct Xref*)0)
  547   {
  548     *root=malloc(sizeof(struct Xref));
  549     (*root)->key=key;
  550     (*root)->l=(*root)->r=(struct Xref*)0;
  551     /* create new circular list */
  552     (*root)->lines=new=malloc(sizeof(struct LineNumber));
  553     new->line=*line;
  554     new->next=new;
  555   }
  556   else
  557   {
  558     /* add to existing circular list */
  559     tail=&(*root)->lines;
  560     if ((*tail)->line.line!=line->line)
  561     {
  562       new=malloc(sizeof(struct LineNumber));
  563       new->line=*line;
  564       new->next=(*tail)->next;
  565       (*tail)->next=new;
  566       *tail=new;
  567     }
  568   }
  569 }
  570 /*}}}*/
  571 static void Xref_destroy(struct Xref *root) /*{{{*/
  572 {
  573   if (root)
  574   {
  575     struct LineNumber *cur,*next,*tail;
  576 
  577     Xref_destroy(root->l);
  578     Xref_destroy(root->r);
  579     cur=tail=root->lines;
  580     do
  581     {
  582       next=cur->next;
  583       free(cur);
  584       cur=next;
  585     } while (cur!=tail);
  586     free(root);
  587   }
  588 }
  589 /*}}}*/
  590 static void Xref_print(struct Xref *root, void (*print)(const void *key, struct Program *p, int chn), struct Program *p, int chn) /*{{{*/
  591 {
  592   if (root)
  593   {
  594     const struct LineNumber *cur,*tail;
  595 
  596     Xref_print(root->l,print,p,chn);
  597     print(root->key,p,chn);
  598     cur=tail=root->lines;
  599     do
  600     {
  601       char buf[128];
  602 
  603       cur=cur->next;
  604       if (FS_charpos(chn)>72) FS_putChars(chn,"\n        ");
  605       sprintf(buf," %ld",Program_lineNumber(p,&cur->line));
  606       FS_putChars(chn,buf);
  607     } while (cur!=tail);
  608     FS_putChar(chn,'\n');
  609     Xref_print(root->r,print,p,chn);
  610   }
  611 }
  612 /*}}}*/
  613 static int cmpLine(const void *a, const void *b) /*{{{*/
  614 {
  615   register const struct Pc *pcA=(const struct Pc*)a,*pcB=(const struct Pc*)b;
  616 
  617   return pcA->line-pcB->line;
  618 }
  619 /*}}}*/
  620 static void printLine(const void *k, struct Program *p, int chn) /*{{{*/
  621 {
  622   char buf[80];
  623 
  624   sprintf(buf,"%8ld",Program_lineNumber(p,(const struct Pc*)k));
  625   FS_putChars(chn,buf);
  626 }
  627 /*}}}*/
  628 static int cmpName(const void *a, const void *b) /*{{{*/
  629 {
  630   register const char *funcA=(const char*)a,*funcB=(const char*)b;
  631 
  632   return strcmp(funcA,funcB);
  633 }
  634 /*}}}*/
  635 static void printName(const void *k, struct Program *p, int chn) /*{{{*/
  636 {
  637   size_t len=strlen((const char*)k);
  638 
  639   FS_putChars(chn,(const char*)k);
  640   if (len<8) FS_putChars(chn,"        "+len);
  641 }
  642 /*}}}*/
  643 
  644 void Program_xref(struct Program *this, int chn) /*{{{*/
  645 {
  646   struct Pc pc;
  647   struct Xref *func,*var,*gosub,*goto_;
  648   int nl=0;
  649 
  650   assert(this->runnable);
  651   func=(struct Xref*)0;
  652   var=(struct Xref*)0;
  653   gosub=(struct Xref*)0;
  654   goto_=(struct Xref*)0;
  655 
  656   for (pc.line=0; pc.line<this->size; ++pc.line)
  657   {
  658     struct On *on;
  659 
  660     for (on=(struct On*)0,pc.token=this->code[pc.line]; pc.token->type!=T_EOL; ++pc.token)
  661     {
  662       switch (pc.token->type)
  663       {
  664         case T_ON: /*{{{*/
  665         {
  666           on=&pc.token->u.on;
  667           break;
  668         }
  669         /*}}}*/
  670         case T_GOTO: /*{{{*/
  671         {
  672           if (on)
  673           {
  674             int key;
  675 
  676             for (key=0; key<on->pcLength; ++key) Xref_add(&goto_,cmpLine,&on->pc[key],&pc);
  677             on=(struct On*)0;
  678           }
  679           else Xref_add(&goto_,cmpLine,&pc.token->u.gotopc,&pc);
  680           break;
  681         }
  682         /*}}}*/
  683         case T_GOSUB: /*{{{*/
  684         {
  685           if (on)
  686           {
  687             int key;
  688 
  689             for (key=0; key<on->pcLength; ++key) Xref_add(&gosub,cmpLine,&on->pc[key],&pc);
  690             on=(struct On*)0;
  691           }
  692           else Xref_add(&gosub,cmpLine,&pc.token->u.gosubpc,&pc);
  693           break;
  694         }
  695         /*}}}*/
  696         case T_DEFFN:
  697         case T_DEFPROC:
  698         case T_FUNCTION:
  699         case T_SUB: /*{{{*/
  700         {
  701           ++pc.token;
  702           Xref_add(&func,cmpName,&pc.token->u.identifier->name,&pc);
  703           break;
  704         }
  705         /*}}}*/
  706         default: break;
  707       }
  708     }
  709   }
  710 
  711   for (pc.line=0; pc.line<this->size; ++pc.line)
  712   {
  713     for (pc.token=this->code[pc.line]; pc.token->type!=T_EOL; ++pc.token)
  714     {
  715       switch (pc.token->type)
  716       {
  717         case T_DEFFN:
  718         case T_DEFPROC:
  719         case T_FUNCTION:
  720         case T_SUB: /* skip identifier already added above */ /*{{{*/
  721         {
  722           ++pc.token;
  723           break;
  724         }
  725         /*}}}*/
  726         case T_IDENTIFIER: /*{{{*/
  727         {
  728           /* formal parameters have no assigned symbol */
  729           if (pc.token->u.identifier->sym) switch (pc.token->u.identifier->sym->type)
  730           {
  731             case GLOBALVAR:
  732             {
  733               Xref_add(&var,cmpName,&pc.token->u.identifier->name,&pc);
  734               break;
  735             }
  736             case USERFUNCTION:
  737             {
  738               Xref_add(&func,cmpName,&pc.token->u.identifier->name,&pc);
  739               break;
  740             }
  741             default: break;
  742           }
  743           break;
  744         }
  745         /*}}}*/
  746         default: break;
  747       }
  748     }
  749   }
  750 
  751   if (func)
  752   {
  753     FS_putChars(chn,_("Function Referenced in line\n"));
  754     Xref_print(func,printName,this,chn);
  755     Xref_destroy(func);
  756     nl=1;
  757   }
  758 
  759   if (var)
  760   {
  761     if (nl) FS_putChar(chn,'\n');
  762     FS_putChars(chn,_("Variable Referenced in line\n"));
  763     Xref_print(var,printName,this,chn);
  764     Xref_destroy(func);
  765     nl=1;
  766   }
  767 
  768   if (gosub)
  769   {
  770     if (nl) FS_putChar(chn,'\n');
  771     FS_putChars(chn,_("Gosub    Referenced in line\n"));
  772     Xref_print(gosub,printLine,this,chn);
  773     Xref_destroy(gosub);
  774     nl=1;
  775   }
  776 
  777   if (goto_)
  778   {
  779     if (nl) FS_putChar(chn,'\n');
  780     FS_putChars(chn,_("Goto     Referenced in line\n"));
  781     Xref_print(goto_,printLine,this,chn);
  782     Xref_destroy(goto_);
  783     nl=1;
  784   }
  785 }
  786 /*}}}*/