C:/Users/Dennis/src/lang/Life_start/Life/life-1.02/source/token.c

Go to the documentation of this file.
00001 /* Copyright 1991 Digital Equipment Corporation.
00002 ** All Rights Reserved.
00003 *****************************************************************/
00004 /*      $Id: token.c,v 1.4 1995/07/27 19:22:17 duchier Exp $     */
00005 
00006 #ifndef lint
00007 static char vcid[] = "$Id: token.c,v 1.4 1995/07/27 19:22:17 duchier Exp $";
00008 #endif /* lint */
00009 #ifndef OS2_PORT
00010 #include <pwd.h>
00011 
00012 #else
00013 #include <stdlib.h>
00014 #endif
00015 #include "extern.h"
00016 #include "trees.h"
00017 #include "types.h"
00018 #include "token.h"
00019 #include "memory.h"
00020 #include "error.h"
00021 #include "parser.h" /* For heap_copy_psi_term */
00022 #include "modules.h"
00023 
00024 
00025 long var_occurred;
00026 ptr_node symbol_table;
00027 ptr_psi_term error_psi_term;
00028 long psi_term_line_number;
00029 long trace_input=FALSE;
00030 
00031 FILE *output_stream;
00032 char *prompt;
00033 
00034 long stdin_terminal;
00035 
00036 /* For parsing from a string */
00037 long stringparse;
00038 char *stringinput;
00039 
00040 /****************************************************************************/
00041 
00042 /* Abstract Data Type for the Input File State */
00043 
00044 /* FILE *last_eof_read; */
00045 
00046 /* Global input file state information */
00047 /* Note: all characters should be stored in longs.  This ensures
00048    that noncharacters (i.e., EOF) can also be stored. */
00049 FILE *input_stream;
00050 string input_file_name;
00051 long line_count;
00052 long start_of_line;
00053 long saved_char; /*  RM: Jul  7 1993  changed to 'int' */
00054 long old_saved_char;
00055 ptr_psi_term saved_psi_term;
00056 ptr_psi_term old_saved_psi_term;
00057 long eof_flag;
00058 
00059 /* Psi-term containing global input file state */
00060 ptr_psi_term input_state;
00061 
00062 /* Psi-term containing stdin file state */
00063 ptr_psi_term stdin_state;
00064 
00065 /***********************************************/
00066 /* Utilities */
00067 /* All psi-terms created here are on the HEAP. */
00068 /* Many utilities exist in two versions that allocate on the heap */
00069 /* or the stack. */
00070 /* All these routines are NON-backtrackable. */
00071 
00072 
00073 
00074 void TOKEN_ERROR(p)    /*  RM: Feb  1 1993  */
00075 
00076      ptr_psi_term p;
00077 {
00078   if(p->type==error_psi_term->type) {
00079     Syntaxerrorline("Module violation (%E).\n");
00080   }
00081 }
00082 
00083 
00084 
00085 /* Clear EOF if necessary for stdin */
00086 void stdin_cleareof()
00087 {
00088   if (eof_flag && stdin_terminal) {
00089     clearerr(stdin);
00090     start_of_line=TRUE;
00091     saved_psi_term=NULL;
00092     old_saved_psi_term=NULL;
00093     saved_char=0;
00094     old_saved_char=0;
00095     eof_flag=FALSE;
00096   }
00097 }
00098 
00099 
00100 /* Add an attribute whose value is an integer to a psi-term */
00101 /* that does not yet contains this attribute. */
00102 void heap_add_int_attr(t, attrname, value)
00103 ptr_psi_term t;
00104 char *attrname;
00105 long value;
00106 {
00107   ptr_psi_term t1;
00108 
00109   t1=heap_psi_term(4);
00110   t1->type=integer;
00111   t1->value=heap_alloc(sizeof(REAL));
00112   *(REAL *)t1->value = (REAL) value;
00113 
00114   heap_insert(featcmp,heap_copy_string(attrname),&(t->attr_list), t1);
00115 }
00116 
00117 void stack_add_int_attr(t, attrname, value)
00118 ptr_psi_term t;
00119 char *attrname;
00120 long value;
00121 {
00122   ptr_psi_term t1;
00123 
00124   t1=stack_psi_term(4);
00125   t1->type=integer;
00126   t1->value=heap_alloc(sizeof(REAL)); /* 12.5 */
00127   *(REAL *)t1->value = (REAL) value;
00128 
00129   stack_insert(featcmp,heap_copy_string(attrname),&(t->attr_list), t1);
00130 }
00131 
00132 
00133 /* Modify an attribute whose value is an integer to a psi-term */
00134 /* that already contains this attribute with another integer value. */
00135 void heap_mod_int_attr(t, attrname, value)
00136 ptr_psi_term t;
00137 char *attrname;
00138 long value;
00139 {
00140   ptr_node n;
00141   ptr_psi_term t1;
00142 
00143   n=find(featcmp,attrname,t->attr_list);
00144   t1=(ptr_psi_term)n->data;
00145   *(REAL *)t1->value = (REAL) value;
00146 }
00147 
00148 /*
00149 void stack_mod_int_attr(t, attrname, value)
00150 ptr_psi_term t;
00151 char *attrname;
00152 long value;
00153 {
00154   ptr_node n;
00155   ptr_psi_term t1;
00156 
00157   n=find(featcmp,attrname,t->attr_list);
00158   t1=(ptr_psi_term)n->data;
00159   *(REAL *)t1->value = (REAL) value;
00160 }
00161 */
00162 
00163 
00164 /* Add an attribute whose value is a string to a psi-term */
00165 /* that does not yet contains this attribute. */
00166 void heap_add_str_attr(t, attrname, str)
00167 ptr_psi_term t;
00168 char *attrname;
00169 char *str;
00170 {
00171   ptr_psi_term t1;
00172 
00173   t1=heap_psi_term(4);
00174   t1->type=quoted_string;
00175   t1->value=(GENERIC)heap_copy_string(str);
00176 
00177   heap_insert(featcmp,heap_copy_string(attrname),&(t->attr_list), t1);
00178 }
00179 
00180 void stack_add_str_attr(t, attrname, str)
00181 ptr_psi_term t;
00182 char *attrname;
00183 char *str;
00184 {
00185   ptr_psi_term t1;
00186 
00187   t1=stack_psi_term(4);
00188   t1->type=quoted_string;
00189   t1->value=(GENERIC)stack_copy_string(str);
00190 
00191   stack_insert(featcmp,heap_copy_string(attrname),&(t->attr_list), t1);
00192 }
00193 
00194 
00195 /* Modify an attribute whose value is a string to a psi-term */
00196 /* that already contains this attribute with another integer value. */
00197 void heap_mod_str_attr(t, attrname, str)
00198 ptr_psi_term t;
00199 char *attrname;
00200 char *str;
00201 {
00202   ptr_node n;
00203   ptr_psi_term t1;
00204 
00205   n=find(featcmp,attrname,t->attr_list);
00206   t1=(ptr_psi_term)n->data;
00207   t1->value=(GENERIC)heap_copy_string(str);
00208 }
00209 
00210 /*
00211 ATTENTION - This should be made backtrackable if used
00212 void stack_mod_str_attr(t, attrname, str)
00213 ptr_psi_term t;
00214 char *attrname;
00215 char *str;
00216 {
00217   ptr_node n;
00218   ptr_psi_term t1;
00219 
00220   n=find(featcmp,attrname,t->attr_list);
00221   t1=(ptr_psi_term)n->data;
00222   t1->value=(GENERIC)stack_copy_string(str);
00223 }
00224 */
00225 
00226 
00227 /* Attach a psi-term to another as an attribute. */
00228 void heap_add_psi_attr(t, attrname, g)
00229 ptr_psi_term t;
00230 char *attrname;
00231 ptr_psi_term g;
00232 {
00233   heap_insert(featcmp,heap_copy_string(attrname),&(t->attr_list), g);
00234 }
00235 
00236 void stack_add_psi_attr(t, attrname, g)
00237 ptr_psi_term t;
00238 char *attrname;
00239 ptr_psi_term g;
00240 {
00241   stack_insert(featcmp,heap_copy_string(attrname),&(t->attr_list), g);
00242 }
00243 
00244 void bk_stack_add_psi_attr(t, attrname, g)
00245 ptr_psi_term t;
00246 char *attrname;
00247 ptr_psi_term g;
00248 {
00249   bk_stack_insert(featcmp,heap_copy_string(attrname),&(t->attr_list), g);
00250 }
00251 
00252 
00253 /* Get the GENERIC value of a psi-term's attribute */
00254 GENERIC get_attr(t, attrname)
00255 ptr_psi_term t;
00256 char *attrname;
00257 {
00258   ptr_node n=find(featcmp,attrname,t->attr_list);
00259   return (GENERIC) n->data;
00260 }
00261 
00262 /* Get the psi-term's STREAM attribute */
00263 FILE *get_stream(t)
00264 ptr_psi_term t;
00265 {
00266   return (FILE *) ((ptr_psi_term)get_attr(t,STREAM))->value;
00267 }
00268 
00269 /***********************************************/
00270 /* Main routines for saving & restoring state */
00271 
00272 
00273 /* Save global state into an existing file state psi-term t */
00274 void save_state(t)
00275 ptr_psi_term t;
00276 {
00277   ptr_node n;
00278   ptr_psi_term t1;
00279 
00280   n=find(featcmp,STREAM,t->attr_list);
00281   t1=(ptr_psi_term)n->data;
00282   t1->value=(GENERIC)input_stream;
00283 
00284   /*  RM: Jan 27 1993
00285   heap_mod_str_attr(t,CURRENT_MODULE,current_module->module_name);
00286   */
00287   
00288   heap_mod_str_attr(t,INPUT_FILE_NAME,input_file_name);
00289   heap_mod_int_attr(t,LINE_COUNT,line_count);
00290   heap_mod_int_attr(t,SAVED_CHAR,saved_char);
00291   heap_mod_int_attr(t,OLD_SAVED_CHAR,old_saved_char);
00292 
00293   t1=saved_psi_term?saved_psi_term:null_psi_term;
00294   heap_add_psi_attr(t,SAVED_PSI_TERM,t1);
00295 
00296   t1=old_saved_psi_term?old_saved_psi_term:null_psi_term;
00297   heap_add_psi_attr(t,OLD_SAVED_PSI_TERM,t1);
00298 
00299   t1=heap_psi_term(4);
00300   t1->type=(eof_flag?true:false);
00301   heap_add_psi_attr(t,EOF_FLAG,t1);
00302 
00303   t1=heap_psi_term(4);
00304   t1->type=(start_of_line?true:false);
00305   heap_add_psi_attr(t,START_OF_LINE,t1);
00306 }
00307 
00308 
00309 
00310 /* Restore global state from an existing file state psi-term t */
00311 void restore_state(t)
00312 ptr_psi_term t;
00313 {
00314   long i;
00315   char *str;
00316 
00317   
00318   input_stream = (FILE *) ((ptr_psi_term)get_attr(t,STREAM))->value;
00319   str = (char*) ((ptr_psi_term)get_attr(t,INPUT_FILE_NAME))->value;
00320   strcpy(input_file_name,str);
00321   /* for (i=0;i++;i<=strlen(str)) input_file_name[i]=str[i]; */
00322   line_count = *(REAL *) ((ptr_psi_term)get_attr(t,LINE_COUNT))->value;
00323   saved_char = *(REAL *) ((ptr_psi_term)get_attr(t,SAVED_CHAR))->value;
00324   old_saved_char= *(REAL *)((ptr_psi_term)get_attr(t,OLD_SAVED_CHAR))->value;
00325 
00326   saved_psi_term=(ptr_psi_term)get_attr(t,SAVED_PSI_TERM);
00327   if (saved_psi_term==null_psi_term) saved_psi_term=NULL;
00328 
00329   old_saved_psi_term=(ptr_psi_term)get_attr(t,OLD_SAVED_PSI_TERM);
00330   if (old_saved_psi_term==null_psi_term) old_saved_psi_term=NULL;
00331 
00332   eof_flag = ((ptr_psi_term)get_attr(t,EOF_FLAG))->type==true;
00333   start_of_line = ((ptr_psi_term)get_attr(t,START_OF_LINE))->type==true;
00334 
00335   
00336   /*  RM: Jan 27 1993
00337       set_current_module(
00338       find_module(((ptr_psi_term)get_attr(input_state,
00339       CURRENT_MODULE))->value));
00340       */
00341 }
00342 
00343 
00344 /* Create a new file state psi-term that reflects the current global state */
00345 void new_state(t)
00346 ptr_psi_term *t;
00347 {
00348   ptr_psi_term t1;
00349 
00350   *t=heap_psi_term(4);
00351   (*t)->type=inputfilesym;
00352 
00353   t1=heap_psi_term(4);
00354   t1->type=stream;
00355   t1->value=(GENERIC)input_stream;
00356   heap_add_psi_attr(*t,STREAM,t1);
00357 
00358   /*  RM: Jan 27 1993  */
00359   heap_add_str_attr(*t,CURRENT_MODULE,current_module->module_name);
00360   
00361   /*
00362     printf("Creating new state for file '%s', module '%s'\n",
00363     input_file_name,
00364     current_module->module_name);
00365     */
00366   
00367   heap_add_str_attr(*t,INPUT_FILE_NAME,input_file_name);
00368   heap_add_int_attr(*t,LINE_COUNT,line_count);
00369   heap_add_int_attr(*t,SAVED_CHAR,saved_char);
00370   heap_add_int_attr(*t,OLD_SAVED_CHAR,old_saved_char);
00371 
00372   t1=saved_psi_term?saved_psi_term:null_psi_term;
00373   heap_add_psi_attr(*t,SAVED_PSI_TERM,t1);
00374 
00375   t1=old_saved_psi_term?old_saved_psi_term:null_psi_term;
00376   heap_add_psi_attr(*t,OLD_SAVED_PSI_TERM,t1);
00377 
00378   t1=heap_psi_term(4);
00379   t1->type=(eof_flag?true:false);
00380   heap_add_psi_attr(*t,EOF_FLAG,t1);
00381 
00382   t1=heap_psi_term(4);
00383   t1->type=(start_of_line?true:false);
00384   heap_add_psi_attr(*t,START_OF_LINE,t1);
00385 }
00386 
00387 
00388 
00389 /****************************************************************************/
00390 
00391 
00392 /* Parser/tokenizer state handling */
00393 
00394 void save_parse_state(pb)
00395 ptr_parse_block pb;
00396 {
00397    if (pb) {
00398      pb->lc   = line_count;
00399      pb->sol  = start_of_line;
00400      pb->sc   = saved_char;
00401      pb->osc  = old_saved_char;
00402      pb->spt  = saved_psi_term;
00403      pb->ospt = old_saved_psi_term;
00404      pb->ef   = eof_flag;
00405    }
00406 }
00407 
00408 
00409 void restore_parse_state(pb)
00410 ptr_parse_block pb;
00411 {
00412    if (pb) {
00413      line_count         = pb->lc;
00414      start_of_line      = pb->sol;
00415      saved_char         = pb->sc;
00416      old_saved_char     = pb->osc;
00417      saved_psi_term     = pb->spt;
00418      old_saved_psi_term = pb->ospt;
00419      eof_flag           = pb->ef;
00420    }
00421 }
00422 
00423 
00424 /* Initialize the parser/tokenizer state variables. */
00425 void init_parse_state()
00426 {
00427   line_count=0;
00428   start_of_line=TRUE;
00429   saved_char=0;
00430   old_saved_char=0;
00431   saved_psi_term=NULL;
00432   old_saved_psi_term=NULL;
00433   eof_flag=FALSE;
00434   stringparse=FALSE;
00435 }
00436 
00437 
00438 /****************************************************************************/
00439 
00440 
00441 static long inchange, outchange;
00442 static FILE *out;
00443 ptr_psi_term old_state=NULL; /*  RM: Feb 17 1993  */
00444 
00445 
00446 
00447 /******** BEGIN_TERMINAL_IO()
00448    These two routines must bracket any I/O directed to the terminal.
00449    This is to avoid mix-ups between terminal and file I/O since the
00450    program's input and output streams may be different from stdin stdout.
00451    See the routine what_next_aim(), which uses them to isolate the
00452    user interface I/O from the program's own I/O.
00453 */
00454 void begin_terminal_io()
00455 {
00456   inchange = (input_stream!=stdin);
00457   outchange = (output_stream!=stdout);
00458 
00459   if (outchange) {
00460     out=output_stream;
00461     output_stream=stdout;
00462   }
00463 
00464   if (inchange) {
00465     old_state=input_state;
00466     open_input_file("stdin");
00467   }
00468 }
00469 
00470 
00471 
00472 /******** END_TERMINAL_IO()
00473   End of terminal I/O bracketing.
00474 */
00475 void end_terminal_io()
00476 {
00477   if (inchange) {
00478     input_state=old_state;
00479     restore_state(old_state);
00480     old_state=NULL; /*  RM: Feb 17 1993  */
00481   }
00482   if (outchange)
00483     output_stream=out;
00484 }
00485 
00486 
00487 
00488 /******** EXPAND_FILE_NAME(str)
00489   Return the expansion of file name STR.
00490   For the time being all this does is replace '~' by the HOME directory
00491   if no user is given, or tries to find the user.
00492 */
00493 #ifndef OS2_PORT
00494 char *expand_file_name(s)
00495 char *s;
00496 {
00497   char *r;
00498   char *home, *getenv();
00499   struct passwd *pw;
00500   char *user="eight character name";
00501   char userbuf[STRLEN];
00502   /* char *user=userbuf; 
00503    */
00504   char *t1,*t2;
00505 
00506   r=s;
00507   if (s[0]=='~') {
00508     t1=s+1;
00509     t2=user;
00510     while (*t1!=0 && *t1!='/') {
00511       *t2= *t1;
00512       *t2++;
00513       *t1++;
00514     }
00515     *t2=0;
00516     if ((int)strlen(user)>0) {
00517       pw = getpwnam(user);
00518       if (pw) {
00519         user=pw->pw_dir;
00520         r=(char *)malloc(strlen(user)+strlen(t1)+1);
00521         sprintf(r,"%s%s",user,t1);
00522       }
00523       else
00524         /* if (warning()) printf("couldn't find user '%s'.\n",user) */;
00525     }
00526     else {
00527       home=getenv("HOME");
00528       if (home) {
00529         r=(char *)malloc(strlen(home)+strlen(s)+1);
00530         sprintf(r,"%s%s",home,s+1);
00531       }
00532       else
00533         /* if (warning()) printf("no HOME directory.\n") */;
00534     }
00535   }
00536 
00537   /* printf("*** Using file name: '%s'\n",r); */
00538   
00539   return r;
00540 }
00541 #else
00542 char *expand_file_name(s)
00543 char *s;
00544 {
00545   char *r;
00546   char *home;
00547   char *pw;
00548   char userbuf[STRLEN];
00549   char *user;
00550   char *t1,*t2;
00551    r = s;
00552   if (s[0]=='~') {
00553     t1=s+1;
00554     if (user=getenv("LIFEHOME") ) {
00555         r=(char *)malloc(strlen(user)+strlen(t1)+2);
00556         sprintf(r,"%s\\%s",user,t1);
00557         }
00558       else
00559         {
00560         user = OS2_HOME;
00561         r=(char *)malloc(strlen(user)+strlen(t1)+1);
00562         sprintf(r,"%s%s",user,t1);
00563         }
00564     }
00565   return r; 
00566 }
00567 #endif
00568 #if 0
00569 
00570 char *expand_file_name(s)
00571 char *s;
00572 {
00573   char *r;
00574   char *home, *getenv();
00575   /* char *user="eight character name"; 18.5 */
00576   char userbuf[STRLEN];
00577   char *user=userbuf;
00578   char *t1,*t2;
00579   r=s;
00580   if (s[0]=='~') {
00581     t1=s+1;
00582     t2=user;
00583     while (*t1!=0 && *t1!='/') {
00584       *t2= *t1;
00585       *t2++;
00586       *t1++;
00587     }
00588     *t2=0;
00589     if ((int)strlen(user)>0) {
00590       if (TRUE) {
00591         user=OS2_HOME;
00592         r=(char *)malloc(strlen(user)+strlen(t1)+1);
00593         sprintf(r,"%s%s",user,t1);
00594       }
00595       else
00596         /* if (warning()) printf("couldn't find user '%s'.\n",user) */;
00597     }
00598     else {
00599       home=getenv("HOME");
00600       if (home) {
00601         r=(char *)malloc(strlen(home)+strlen(s)+1);
00602         sprintf(r,"%s%s",home,s+1);
00603       }
00604       else
00605         /* if (warning()) printf("no HOME directory.\n") */;
00606     }
00607   }
00608 
00609   /* printf("*** Using file name: '%s'\n",r); */
00610   
00611   return r;
00612 }
00613 #endif
00614   
00615 /******** OPEN_INPUT_FILE(file)
00616   Open the input file specified by the string FILE.  If the file is "stdin",
00617   restore the stdin state.  Otherwise, open the file and create a new global
00618   state for it.
00619   If the file can't be opened, print an error and open "stdin" instead.
00620 */   
00621 long open_input_file(file)
00622 char *file;
00623 {
00624   long ok=TRUE;
00625   long stdin_flag;
00626 #ifdef OS2_PORT
00627 char *file2;
00628 #endif
00629 
00630   /* Save global input file state */
00631   if (input_state!=NULL) save_state(input_state);
00632 
00633 #ifndef OS2_PORT2
00634   file=expand_file_name(file);
00635   
00636   if (stdin_flag=(!strcmp(file,"stdin"))) {
00637     input_stream=stdin;
00638     noisy=TRUE;
00639   }
00640   else {
00641     input_stream=fopen(file,"r");
00642     noisy=FALSE;
00643   }
00644   
00645   if (input_stream==NULL) {
00646     Errorline("file '%s' does not exist.\n",file);
00647     file="stdin";
00648     input_stream=stdin;
00649     noisy=TRUE;
00650     ok=FALSE;
00651   }
00652 
00653   if (!stdin_flag || stdin_state==NULL) {
00654     /* Initialize a new global input file state */
00655     strcpy(input_file_name,file);
00656     init_parse_state();
00657     /* Create a new state containing the new global values */
00658     new_state(&input_state);
00659     if (stdin_flag) stdin_state=input_state;
00660   }
00661   else {
00662     input_state=stdin_state;
00663     restore_state(input_state);
00664   }
00665 
00666   return ok;
00667 #else
00668   file2=expand_file_name(file);
00669   
00670   if (stdin_flag=(!strcmp(file2,"stdin"))) {
00671     input_stream=stdin;
00672     noisy=TRUE;
00673   }
00674   else {
00675     input_stream=fopen(file2,"r");
00676     noisy=FALSE;
00677   }
00678   
00679   if (input_stream==NULL) {
00680 #ifdef DJD_DEBUG
00681 printf("missing file == %s\n",file2);
00682 #endif
00683 
00684 
00685     Errorline("file '%s' does not exist.\n",file2);
00686     file="stdin";
00687     input_stream=stdin;
00688     noisy=TRUE;
00689     ok=FALSE;
00690   }
00691 
00692   if (!stdin_flag || stdin_state==NULL) {
00693     /* Initialize a new global input file state */
00694     strcpy(input_file_name,file2);
00695     init_parse_state();
00696     /* Create a new state containing the new global values */
00697     new_state(&input_state);
00698     if (stdin_flag) stdin_state=input_state;
00699   }
00700   else {
00701     input_state=stdin_state;
00702     restore_state(input_state);
00703   }
00704 
00705   return ok;
00706 #endif
00707 }
00708 
00709 
00710 
00711 /******** OPEN_OUTPUT_FILE(file)
00712   Same thing as OPEN_INPUT_FILE, only for output. If FILE="stdout" then
00713   output_stream=stdout.
00714 */
00715 long open_output_file(file)
00716 string file;
00717 {
00718   long ok=TRUE;
00719 
00720 
00721   file=expand_file_name(file);
00722   
00723   if (!strcmp(file,"stdout"))
00724     output_stream=stdout;
00725   else
00726     if (!strcmp(file,"stderr"))
00727       output_stream=stderr;
00728     else
00729       output_stream=fopen(file,"w");
00730    
00731   if (output_stream==NULL) {
00732     Errorline("file '%s' could not be opened for output.\n",file);
00733     ok=FALSE;
00734     output_stream=stdout;
00735   }
00736   
00737   return ok;
00738 }
00739 
00740 
00741 
00742 /******** READ_CHAR
00743   Return the char read from the input stream, if end of file reached
00744   then return EOF.
00745   If stringparse==TRUE then read characters from the input string
00746   instead of from a file.
00747 */
00748 long read_char()
00749 {
00750   long c=0;
00751   
00752   if (c=saved_char) {
00753     saved_char=old_saved_char;
00754     old_saved_char=0;
00755   }
00756   else if (stringparse) {
00757     if (c=(*stringinput))
00758       stringinput++;
00759     else
00760       c=EOF;
00761   }
00762   else if (feof(input_stream))
00763       c=EOF;
00764   else {
00765     if (start_of_line) {
00766       start_of_line=FALSE;
00767       line_count++;
00768       if (input_stream==stdin) Infoline("%s",prompt); /* 21.1 */
00769     }
00770      
00771     c=fgetc(input_stream);
00772     
00773     if(trace_input)   /*  RM: Jan 13 1993  */
00774       if(c!=EOF)
00775         printf("%c",c);
00776       else
00777         printf(" <EOF>\n");
00778 #ifdef OS2_PORT
00779 fflush(stdout);
00780 #endif
00781     if (c==EOLN)
00782       start_of_line=TRUE;
00783   }
00784 
00785   /* printf("%c\n",c); RM: Jan  5 1993  Just to trace the parser */
00786   
00787   return c;
00788 }
00789 
00790 
00791 
00792 /******** PUT_BACK_CHAR
00793   Put back one character, if there already are 2 saved characters then report
00794   an error (= bug).
00795 */
00796 void put_back_char(c)
00797 long c;
00798 {
00799   if (old_saved_char)
00800     Errorline("in tokenizer, put_back_char three times (last=%d).\n",c);
00801   old_saved_char=saved_char;
00802   saved_char=c;
00803 }
00804 
00805 
00806 /******** PUT_BACK_TOKEN
00807   Put back a psi_term, if there already are two saved then report an
00808   error (= bug).
00809 */
00810 void put_back_token(t)
00811 psi_term t;
00812 {  
00813   if (old_saved_psi_term!=NULL)
00814     Errorline("in parser, put_back_token three times (last=%P).\n",t);
00815   old_saved_psi_term=saved_psi_term;
00816   saved_psi_term=stack_copy_psi_term(t);
00817 }
00818 
00819 
00820 
00821 /******** PSI_TERM_ERROR
00822   Print the line number at which the current psi_term started.
00823 */
00824 void psi_term_error()
00825 {
00826   perr_i("near line %d",psi_term_line_number);
00827   if (strcmp(input_file_name,"stdin")) {
00828     perr_s(" in file \042%s\042",input_file_name);
00829   }
00830   /* prompt="error>"; 20.8 */
00831   parse_ok=FALSE;
00832 }
00833 
00834 
00835 
00836 /******** READ_COMMENT
00837   Read a comment starting with '%' to the end of the line.
00838 */
00839 void read_comment(tok)
00840 ptr_psi_term tok;
00841 {
00842   long c;
00843   
00844   do {
00845     c=read_char();
00846   } while (c!=EOF && c!=EOLN);
00847   
00848   tok->type=comment;
00849 }
00850 
00851 void
00852 read_string_error(n)
00853      int n;
00854 {
00855   if (stringparse) parse_ok=FALSE;
00856   else
00857     switch (n) {
00858     case 0:
00859       Syntaxerrorline("end of file reached before end of string (%E).\n");
00860       break;
00861     case 1:
00862       Syntaxerrorline("Hexadecimal digit expected (%E).\n");
00863       break;
00864     }
00865 }
00866 
00867 int
00868 base2int(n)
00869      int n;
00870 {
00871   switch (n) {
00872   case '0': return 0;
00873   case '1': return 1;
00874   case '2': return 2;
00875   case '3': return 3;
00876   case '4': return 4;
00877   case '5': return 5;
00878   case '6': return 6;
00879   case '7': return 7;
00880   case '8': return 8;
00881   case '9': return 9;
00882   case 'a':
00883   case 'A': return 10;
00884   case 'b':
00885   case 'B': return 11;
00886   case 'c':
00887   case 'C': return 12;
00888   case 'd':
00889   case 'D': return 13;
00890   case 'e':
00891   case 'E': return 14;
00892   case 'f':
00893   case 'F': return 15;
00894   default:
00895     fprintf(stderr,"base2int('%c'): illegal argument\n",n);
00896     exit(-1);
00897   }
00898 }
00899 
00900 #define isoctal(c) (c=='0'||c=='1'||c=='2'||c=='3'||c=='4'||c=='5'||c=='6'||c=='7')
00901 
00902 /******** READ_STRING(e)
00903   Read a string ending with character E, where E=" or '. Transform a double
00904   occurrence into a single one so that 'ab""cd' is the string 'ab"cd'.
00905 */
00906 void read_string(tok,e)
00907 ptr_psi_term tok;
00908 long e;
00909 {
00910   long c;
00911   string str;
00912   long len=0;
00913   long store=TRUE;
00914   long flag=TRUE;
00915   
00916   str[len]=0;
00917   
00918   do {
00919     c=read_char();
00920     if (c==EOF) {
00921       store=FALSE;
00922       flag=FALSE;
00923       read_string_error(0);
00924     }
00925     else if (e=='"' && c=='\\') {
00926       c=read_char();
00927       if (c==EOF) {
00928         store=FALSE;
00929         flag=FALSE;
00930         put_back_char('\\');
00931         read_string_error(0);
00932       }
00933       else {
00934         switch (c) {
00935         case 'a': c='\a'; break;
00936         case 'b': c='\b'; break;
00937         case 'f': c='\f'; break;
00938         case 'n': c='\n'; break;
00939         case 'r': c='\r'; break;
00940         case 't': c='\t'; break;
00941         case 'v': c='\v'; break;
00942           /* missing \ooo and \xhh */
00943         case 'x':
00944           {
00945             int n;
00946             c=read_char();
00947             if (c==EOF) {
00948               store=flag=FALSE;
00949               read_string_error(0);
00950               break;
00951             }
00952             else if (!isxdigit(c)) {
00953               store=flag=FALSE;
00954               read_string_error(1);
00955               break;
00956             }
00957             else {
00958               n = base2int(c);
00959             }
00960             c=read_char();
00961             if (isxdigit(c)) n = 16*n+base2int(c);
00962             else put_back_char(c);
00963             c=n;
00964             break;
00965           }
00966         default: 
00967           if (isoctal(c)) {
00968             int n,i;
00969             for(i=n=0;i<3&&isoctal(c);i++,c=read_char())
00970               n = n*8 + base2int(c);
00971             if (c!=EOF) put_back_char(c);
00972             c=n;
00973             break;
00974           }
00975           else break;
00976         }
00977       }
00978     }
00979     else
00980       if (c==e) {
00981         c=read_char();
00982         if (c!=e) {
00983           store=FALSE;
00984           flag=FALSE;
00985           put_back_char(c);
00986         }
00987       }
00988     if (store)
00989       if (len==STRLEN) {
00990         Warningline("string too long, extra ignored (%E).\n");
00991         store=FALSE;
00992       }
00993       else {
00994         str[len++]=c;
00995         str[len]=0;
00996       }
00997   } while(flag);
00998   
00999   if (e=='"')
01000     tok->value=(GENERIC)heap_copy_string(str);
01001   else {
01002     tok->type=update_symbol(NULL,str); /* Maybe no_module would be better */
01003     tok->value=NULL;
01004     TOKEN_ERROR(tok);           /*  RM: Feb  1 1993  */
01005   }
01006 }
01007 
01008 
01009 
01010 /******** SYMBOLIC(character)
01011   Tests if character is a symbol (see macro).
01012 */
01013 long symbolic(c)
01014 long c;
01015 {
01016   return SYMBOL(c);
01017 }
01018 
01019 
01020 
01021 /******** LEGAL_IN_NAME(character)
01022   Tests if character is legal in a name or a variable (see macros).
01023 */
01024 long legal_in_name(c)
01025 long c;
01026 {
01027   return
01028     UPPER(c) ||
01029       LOWER(c) ||
01030         DIGIT(c);
01031 
01032   /* || c=='\'' RM: Dec 16 1992  */ ;
01033 }
01034 
01035 
01036 
01037 /******** READ_NAME(C,F,TYP)
01038   Read in the name starting with character C followed by character of whose
01039   type function is F. The result is a psi_term of symbol type TYP.
01040 */
01041 void read_name(tok,ch,f,typ)
01042 ptr_psi_term tok;
01043 long ch;
01044 long (*f)();
01045 ptr_definition typ;
01046 {
01047   long c;
01048   string str;
01049   long len=1;
01050   long store=TRUE;
01051   long flag=TRUE;
01052   ptr_module module=NULL;
01053   ptr_node n; /*  RM: Feb  9 1993  */
01054 
01055   tok->coref=NULL;
01056   tok->resid=NULL;
01057   tok->attr_list=NULL;
01058 
01059   str[0]=ch;
01060   
01061   do {
01062     c=read_char();
01063     flag=(*f)(c);
01064     
01065     if(c=='#' &&       /*  RM: Feb  3 1993  */
01066        f==legal_in_name &&
01067        len>0 &&
01068        len<STRLEN &&
01069        !module) {
01070       str[len]=0;
01071       module=create_module(str);
01072       len=0;
01073       flag=TRUE;
01074 
01075       /*  RM: Sep 21 1993  */
01076       /* Change the type function if required */
01077       c=read_char();
01078       if SYMBOL(c)
01079         f=symbolic;
01080       put_back_char(c);
01081     }
01082     else
01083       if (flag) {
01084         if (store)
01085           if (len==STRLEN) {
01086             Warningline("name too long, extra ignored (%E).\n");
01087             store=FALSE;
01088           }
01089           else
01090             str[len++]=c;
01091       }
01092       else
01093         put_back_char(c);
01094   } while(flag);
01095 
01096   if(module && len==0) { /*  RM: Feb  3 1993  */
01097     strcpy(str,module->module_name);
01098     len=strlen(str);
01099     put_back_char('#');
01100     module=NULL;
01101   }
01102   
01103   str[len]=0;
01104   
01105   tok->type=typ;
01106   
01107   if(typ==constant) {
01108     /* printf("module=%s\n",module->module_name); */
01109     tok->type=update_symbol(module,str); /*  RM: Feb  3 1993  */
01110     tok->value=NULL;
01111 
01112     TOKEN_ERROR(tok); /*  RM: Feb  1 1993  */
01113 
01114     /* PVR 4.2.94 for correct level incrementing */
01115     if (tok->type->type==global) {
01116       var_occurred=TRUE;
01117     }
01118     if (FALSE /*tok->type->type==global && tok->type->global_value*/) {
01119       /*  RM: Nov 10 1993  */
01120       
01121       /* Remove this for Bruno who didn't like it, and doesn't like
01122          to use "print_depth" */
01123       
01124       /*  RM: Feb  9 1993  */
01125       /* Add into the variable tree */
01126       var_occurred=TRUE;
01127       n=find(strcmp,tok->type->keyword->symbol,var_tree);
01128       if (n==NULL) {
01129         /* The change is always trailed. */
01130         bk2_stack_insert(strcmp,
01131                          tok->type->keyword->symbol,
01132                          &var_tree,
01133                          tok->type->global_value);
01134       }
01135     }
01136     
01137   }
01138   else  
01139     tok->value=(GENERIC)heap_copy_string(str);
01140 }
01141 
01142 
01143 
01144 /******** READ_NUMBER(c)
01145   Read in the number whose first character is c.
01146   Accepted syntax: digit+ [ . digit+ ] [ {e|E} {+|-|empty} digit* ]
01147   Negative numbers are dealt with in the parser.
01148 */
01149 void read_number(tok,c)
01150 ptr_psi_term tok;
01151 long c;
01152 {
01153   long c2;
01154   REAL f,p;
01155   long sgn,pwr,posflag;
01156 
01157   /* if (sgn=(c=='-')) c=read_char(); */
01158 
01159   /* tok->type=integer;   RM: Mar  8 1993  */
01160 
01161   f=0.0;
01162   do { f=f*10.0+(c-'0'); c=read_char(); } while (DIGIT(c));
01163 
01164   if (c=='.') {
01165     c2=read_char();
01166     if DIGIT(c2) {
01167       /* tok->type=real;     RM: Mar  8 1993  */
01168       p=10.0;
01169       while (DIGIT(c2)) { f=f+(c2-'0')/p; p=p*10.0; c2=read_char(); }
01170       put_back_char(c2);
01171     }
01172     else {
01173       put_back_char(c2);
01174       put_back_char(c);
01175     }
01176   }
01177   else
01178     put_back_char(c);
01179 
01180   c=read_char();
01181   if (c=='e' || c=='E') {
01182     c2=read_char();
01183     if (c2=='+' || c2=='-' || DIGIT(c2)) {
01184       tok->type=real;
01185       posflag = (c2=='+' || DIGIT(c2));
01186       if (!DIGIT(c2)) c2=read_char();
01187       pwr=0;
01188       while (DIGIT(c2)) { pwr=pwr*10+(c2-'0'); c2=read_char(); }
01189       put_back_char(c2);
01190       p=1.0;
01191       while (pwr>=100) { pwr-=100; if (posflag) p*=1e100; else p/=1e100; }
01192       while (pwr>=10 ) { pwr-=10;  if (posflag) p*=1e10;  else p/=1e10;  }
01193       while (pwr>0   ) { pwr-=1;   if (posflag) p*=1e1;   else p/=1e1;   }
01194       f*=p;
01195     }
01196     else {
01197       put_back_char(c2);
01198       put_back_char(c);
01199     }
01200   }
01201   else
01202     put_back_char(c);
01203 
01204   /* if (sgn) f = -f; */
01205   tok->value=heap_alloc(sizeof(REAL)); /* 12.5 */
01206   *(REAL *)tok->value=f;
01207 
01208   /*  RM: Mar  8 1993  */
01209   if(f==floor(f))
01210     tok->type=integer;
01211   else
01212     tok->type=real;
01213 }
01214 
01215 
01216 
01217 /******** READ_TOKEN
01218   Read in one token from the input stream, represented as a psi_term.
01219   Return the psi_term 'end_of_file' if that is the case.
01220 */
01221 
01222 void read_token_main(); /* Forward declaration */
01223 
01224 /* Used in the parser */
01225 /* Set prompt to the 'partial input' prompt */
01226 void read_token(tok)
01227 ptr_psi_term tok;
01228 { read_token_main(tok, TRUE); }
01229 
01230 /* Used as a built-in */
01231 /* Prompt is unchanged */
01232 void read_token_b(tok)
01233 ptr_psi_term tok;
01234 { read_token_main(tok, FALSE); }
01235 
01236 void read_token_main(tok, for_parser)
01237 ptr_psi_term tok;
01238 long for_parser;
01239 {
01240   long c, c2;
01241   ptr_node n;
01242   char p[2];
01243 
01244   if (for_parser && (saved_psi_term!=NULL)) {
01245     *tok= *saved_psi_term;
01246     saved_psi_term=old_saved_psi_term;
01247     old_saved_psi_term=NULL;
01248   }
01249   else {
01250     tok->type=nothing;
01251     
01252     do {
01253       c=read_char();
01254     } while(c!=EOF && (c<=32));
01255     
01256     if (for_parser) psi_term_line_number=line_count;
01257     
01258     switch(c) {
01259     case EOF:
01260       tok->type=eof;
01261       tok->value=NULL;
01262       break;
01263     case '%':
01264       read_comment(tok);
01265       break;
01266     case '"':
01267       read_string(tok,c);
01268       tok->type=quoted_string;
01269       break;
01270     case 39: /* The quote symbol "'" */
01271       read_string(tok,c);
01272       break;
01273       
01274     default:
01275       
01276       /* Adding this results in problems with terms like (N-1) */
01277       /* if (c=='-' && (c2=read_char()) && DIGIT(c2)) {
01278         put_back_char(c2);
01279         read_number(tok,c);
01280       }
01281       else */
01282 
01283       if(c=='.' || c=='?') { /*  RM: Jul  7 1993  */
01284         c2=read_char();
01285         put_back_char(c2);
01286         /*printf("c2=%d\n",c2);*/
01287         if(c2<=' ' || c2==EOF) {
01288           if(c=='.')
01289             tok->type=final_dot;
01290           else
01291             tok->type=final_question;
01292           
01293           tok->value=NULL;
01294         }
01295         else
01296           read_name(tok,c,symbolic,constant);
01297       }
01298       else
01299         if DIGIT(c)
01300           read_number(tok,c);
01301           else
01302             if UPPER(c) {
01303               read_name(tok,c,legal_in_name,variable);
01304             }
01305             else
01306               if LOWER(c) {
01307                 read_name(tok,c,legal_in_name,constant);
01308               }
01309               else
01310                 if SYMBOL(c) {
01311                   read_name(tok,c,symbolic,constant);
01312                 }
01313                 else /*  RM: Jul  7 1993  Moved this */
01314                   if SINGLE(c) {
01315                     p[0]=c; p[1]=0;
01316                     tok->type=update_symbol(current_module,p);
01317                     tok->value=NULL;
01318                     TOKEN_ERROR(tok); /*  RM: Feb  1 1993  */
01319                   }
01320                   else {
01321                     Errorline("illegal character %d in input (%E).\n",c);
01322                   }
01323     }
01324 
01325     if (tok->type==variable) {
01326       if (tok->value) {
01327         /* If the variable read in has name "_", then it becomes 'top' */
01328         /* and is no longer a variable whose name must be remembered.  */
01329         /* As a result, '@' and '_' are synonyms in the program input. */
01330         if (!strcmp((char *)tok->value,"_")) {
01331           p[0]='@'; p[1]=0;
01332           tok->type=update_symbol(current_module,p);
01333           tok->value=NULL;
01334           TOKEN_ERROR(tok); /*  RM: Feb  1 1993  */
01335         }
01336         else {
01337           /* Insert into variable tree, create 'top' value if need be. */
01338           var_occurred=TRUE;
01339           n=find(strcmp,tok->value,var_tree);
01340           if (n==NULL) {
01341             ptr_psi_term t=stack_psi_term(0);
01342             /* The change is always trailed. */
01343             bk2_stack_insert(strcmp,tok->value,&var_tree,t); /* 17.8 */
01344             tok->coref=t;
01345           }
01346           else
01347             tok->coref=(ptr_psi_term)n->data;
01348         }
01349       }
01350       /* else do nothing */
01351     }
01352   }
01353 
01354   if (tok->type==comment)
01355     read_token(tok);
01356 
01357   if (tok->type!=variable)
01358     tok->coref=NULL;
01359 
01360   tok->attr_list=NULL;
01361   tok->status=0;
01362   tok->flags=FALSE; /* 14.9 */
01363   tok->resid=NULL;
01364 
01365   if (tok->type==cut) /* 12.7 */
01366     tok->value=(GENERIC)choice_stack;
01367 
01368   do {
01369     c=read_char();
01370     if (c==EOLN) {
01371       if (for_parser) put_back_char(c);
01372       c=0;
01373     }
01374     else if (c<0 || c>32) {
01375       put_back_char(c);
01376       c=0;
01377     }
01378   } while(c && c!=EOF);
01379   
01380   if (for_parser) prompt="|    ";
01381 }
01382 
01383 /****************************************************************************/

Generated on Sat Jan 26 08:48:07 2008 for WildLife by  doxygen 1.5.4