⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 common.w

📁 模拟器提供了一个简单易用的平台
💻 W
📖 第 1 页 / 共 4 页
字号:
  }}@ @<If the current line starts with \.{@@y}...@>=if (buffer[1]=='x' || buffer[1]=='z') {  loc=buffer+2; err_print("! Where is the matching @@y?");@.Where is the match...@>  }else if (buffer[1]=='y') {  if (n>0) {    loc=buffer+2;    printf("\n! Hmm... %d ",n);    err_print("of the preceding lines failed to match");@.Hmm... n of the preceding...@>  }  change_depth=include_depth;  return;}@ The |reset_input| procedure, which gets \.{CWEB} ready to read theuser's \.{CWEB} input, is used at the beginning of phase one of \.{CTANGLE},phases one and two of \.{CWEAVE}.@cvoidreset_input(){  limit=buffer; loc=buffer+1; buffer[0]=' ';  @<Open input files@>;  include_depth=0; cur_line=0; change_line=0;  change_depth=include_depth;  changing=1; prime_the_change_buffer(); changing=!changing;  limit=buffer; loc=buffer+1; buffer[0]=' '; input_has_ended=0;}@ The following code opens the input files.@^system dependencies@>@<Open input files@>=if ((web_file=fopen(web_file_name,"r"))==NULL) {  strcpy(web_file_name,alt_web_file_name);  if ((web_file=fopen(web_file_name,"r"))==NULL)       fatal("! Cannot open input file ", web_file_name);}@.Cannot open input file@>@.Cannot open change file@>web_file_open=1;if ((change_file=fopen(change_file_name,"r"))==NULL)       fatal("! Cannot open change file ", change_file_name);@ The |get_line| procedure is called when |loc>limit|; it puts the nextline of merged input into the buffer and updates the other variablesappropriately. A space is placed at the right end of the line.This procedure returns |!input_has_ended| because we often want tocheck the value of that variable after calling the procedure.If we've just changed from the |cur_file| to the |change_file|, or ifthe |cur_file| has changed, we tell \.{CTANGLE} to print thisinformation in the \CEE/ file by means of the |print_where| flag.@d max_sections 2000 /* number of identifiers, strings, section names;  must be less than 10240 */@<Defin...@>=typedef unsigned short sixteen_bits;sixteen_bits section_count; /* the current section number */boolean changed_section[max_sections]; /* is the section changed? */boolean change_pending; /* if the current change is not yet recorded in  |changed_section[section_count]| */boolean print_where=0; /* should \.{CTANGLE} print line and file info? */@ @cint get_line() /* inputs the next line */{  restart:  if (changing && include_depth==change_depth)   @<Read from |change_file| and maybe turn off |changing|@>;  if (! changing || include_depth>change_depth) {    @<Read from |cur_file| and maybe turn on |changing|@>;    if (changing && include_depth==change_depth) goto restart;  }  loc=buffer; *limit=' ';  if (*buffer=='@@' && (*(buffer+1)=='i' || *(buffer+1)=='I')) {    loc=buffer+2;    while (loc<=limit && (*loc==' '||*loc=='\t'||*loc=='"')) loc++;    if (loc>=limit) {      err_print("! Include file name not given");@.Include file name ...@>      goto restart;    }    if (include_depth>=max_include_depth-1) {      err_print("! Too many nested includes");@.Too many nested includes@>      goto restart;    }    include_depth++; /* push input stack */    @<Try to open include file, abort push if unsuccessful, go to |restart|@>;  }  return (!input_has_ended);}@ When an \.{@@i} line is found in the |cur_file|, we must temporarilystop reading it and start reading from the named include file.  The\.{@@i} line should give a complete file name with or withoutdouble quotes.If the environment variable \.{CWEBINPUTS} is set, or if the compiler flagof the same name was defined at compile time,\.{CWEB} will look for include files in the directory thus named, ifit cannot find them in the current directory.(Colon-separated paths are not supported.)The remainder of the \.{@@i} line after the file name is ignored.@d too_long() {include_depth--;        err_print("! Include file name too long"); goto restart;}@<Include...@>=#include <stdlib.h> /* declaration of |getenv| and |exit| */@ @<Try to open...@>= {  char temp_file_name[max_file_name_length];  char *cur_file_name_end=cur_file_name+max_file_name_length-1;  char *k=cur_file_name, *kk;  int l; /* length of file name */  while (*loc!=' '&&*loc!='\t'&&*loc!='"'&&k<=cur_file_name_end) *k++=*loc++;  if (k>cur_file_name_end) too_long();@.Include file name ...@>  *k='\0';  if ((cur_file=fopen(cur_file_name,"r"))!=NULL) {    cur_line=0; print_where=1;    goto restart; /* success */  }  kk=getenv("CWEBINPUTS");  if (kk!=NULL) {    if ((l=strlen(kk))>max_file_name_length-2) too_long();    strcpy(temp_file_name,kk);  }  else {#ifdef CWEBINPUTS    if ((l=strlen(CWEBINPUTS))>max_file_name_length-2) too_long();    strcpy(temp_file_name,CWEBINPUTS);#else    l=0;#endif /* |CWEBINPUTS| */  }  if (l>0) {    if (k+l+2>=cur_file_name_end)  too_long();@.Include file name ...@>    for (; k>= cur_file_name; k--) *(k+l+1)=*k;    strcpy(cur_file_name,temp_file_name);    cur_file_name[l]='/'; /* \UNIX/ pathname separator */    if ((cur_file=fopen(cur_file_name,"r"))!=NULL) {      cur_line=0; print_where=1;      goto restart; /* success */    }  }  include_depth--; err_print("! Cannot open include file"); goto restart;}@ @<Read from |cur_file|...@>= {  cur_line++;  while (!input_ln(cur_file)) { /* pop the stack or quit */    print_where=1;    if (include_depth==0) {input_has_ended=1; break;}    else {      fclose(cur_file); include_depth--;      if (changing && include_depth==change_depth) break;      cur_line++;    }  }  if (!changing && !input_has_ended)   if (limit-buffer==change_limit-change_buffer)    if (buffer[0]==change_buffer[0])      if (change_limit>change_buffer) check_change();}@ @<Read from |change_file|...@>= {  change_line++;  if (!input_ln(change_file)) {    err_print("! Change file ended without @@z");@.Change file ended...@>    buffer[0]='@@'; buffer[1]='z'; limit=buffer+2;  }  if (limit>buffer) { /* check if the change has ended */    if (change_pending) {      if_section_start_make_pending(0);      if (change_pending) {        changed_section[section_count]=1; change_pending=0;      }    }    *limit=' ';    if (buffer[0]=='@@') {      if (xisupper(buffer[1])) buffer[1]=tolower(buffer[1]);      if (buffer[1]=='x' || buffer[1]=='y') {        loc=buffer+2;        err_print("! Where is the matching @@z?");@.Where is the match...@>      }      else if (buffer[1]=='z') {        prime_the_change_buffer(); changing=!changing; print_where=1;      }    }  }}@ At the end of the program, we will tell the user if the change filehad a line that didn't match any relevant line in |web_file|.@cvoidcheck_complete(){  if (change_limit!=change_buffer) { /* |changing| is 0 */    strncpy(buffer,change_buffer,change_limit-change_buffer+1);    limit=buffer+(int)(change_limit-change_buffer);    changing=1; change_depth=include_depth; loc=buffer;    err_print("! Change file entry did not match");@.Change file entry did not match@>  }}@** Storage of names and strings.Both \.{CWEAVE} and \.{CTANGLE} store identifiers, section names andother strings in a large array of |char|s, called |byte_mem|.Information about the names is kept in the array |name_dir|, whoseelements are structures of type |name_info|, containing a pointer intothe |byte_mem| array (the address where the name begins) and other data.A |name_pointer| variable is a pointer into |name_dir|.@d max_bytes 90000 /* the number of bytes in identifiers,  index entries, and section names; must be less than $2^{24}$ */@d max_names 4000 /* number of identifiers, strings, section names;  must be less than 10240 */@<Definitions that...@>=typedef struct name_info {  char *byte_start; /* beginning of the name in |byte_mem| */  @<More elements of |name_info| structure@>@;} name_info; /* contains information about an identifier or section name */typedef name_info *name_pointer; /* pointer into array of |name_info|s */char byte_mem[max_bytes]; /* characters of names */char *byte_mem_end = byte_mem+max_bytes-1; /* end of |byte_mem| */name_info name_dir[max_names]; /* information about names */name_pointer name_dir_end = name_dir+max_names-1; /* end of |name_dir| */@ The actual sequence of characters in the name pointed to by a |name_pointerp| appears in positions |p->byte_start| to |(p+1)->byte_start-1|, inclusive.The |print_id| macro prints this text on the user's terminal.@d length(c) (c+1)->byte_start-(c)->byte_start /* the length of a name */@d print_id(c) term_write((c)->byte_start,length((c))) /* print identifier */@ The first unused position in |byte_mem| and |name_dir| iskept in |byte_ptr| and |name_ptr|, respectively.  Thus weusually have |name_ptr->byte_start==byte_ptr|, and certainlywe want to keep |name_ptr<=name_dir_end| and |byte_ptr<=byte_mem_end|.@<Defini...@>=name_pointer name_ptr; /* first unused position in |byte_start| */char *byte_ptr; /* first unused position in |byte_mem| */@ @<Init...@>=name_dir->byte_start=byte_ptr=byte_mem; /* position zero in both arrays */name_ptr=name_dir+1; /* |name_dir[0]| will be used only for error recovery */name_ptr->byte_start=byte_mem; /* this makes name 0 of length zero */@ The names of identifiers are found by computing a hash address |h| andthen looking at strings of bytes signified by the |name_pointer|s|hash[h]|, |hash[h]->link|, |hash[h]->link->link|, \dots,until either finding the desired name or encountering the null pointer.@<More elements of |name...@>=struct name_info *link;@ The hash table itselfconsists of |hash_size| entries of type |name_pointer|, and isupdated by the |id_lookup| procedure, which finds a given identifierand returns the appropriate |name_pointer|. The matching is done by thefunction |names_match|, which is slightly different in\.{CWEAVE} and \.{CTANGLE}.  If there is no match for the identifier,it is inserted into the table.@d hash_size 353 /* should be prime */@<Defini...@>=typedef name_pointer *hash_pointer;name_pointer hash[hash_size]; /* heads of hash lists */hash_pointer hash_end = hash+hash_size-1; /* end of |hash| */hash_pointer h; /* index into hash-head array */@ @<Predec...@>=extern int names_match();@ Initially all the hash lists are empty.@<Init...@>=for (h=hash; h<=hash_end; *h++=NULL) ;@ Here is the main procedure for finding identifiers:@cname_pointerid_lookup(first,last,t) /* looks up a string in the identifier table */char *first; /* first character of string */char *last; /* last character of string plus one */char t; /* the |ilk|; used by \.{CWEAVE} only */{  char *i=first; /* position in |buffer| */  int h; /* hash code */  int l; /* length of the given identifier */  name_pointer p; /* where the identifier is being sought */  if (last==NULL) for (last=first; *last!='\0'; last++);  l=last-first; /* compute the length */  @<Compute the hash code |h|@>;  @<Compute the name location |p|@>;  if (p==name_ptr) @<Enter a new name into the table at position |p|@>;  return(p);}@ A simple hash code is used: If the sequence ofcharacter codes is $c_1c_2\ldots c_n$, its hash value will be$$(2^{n-1}c_1+2^{n-2}c_2+\cdots+c_n)\,\bmod\,|hash_size|.$$@<Compute the hash...@>=h=(unsigned char)*i;while (++i<last) h=(h+h+(int)((unsigned char)*i)) % hash_size;@^high-bit character handling@>@ If the identifier is new, it will be placed in position |p=name_ptr|,otherwise |p| will point to its existing location.@<Compute the name location...@>=p=hash[h];while (p && !names_match(p,first,l,t)) p=p->link;if (p==NULL) {  p=name_ptr; /* the current identifier is new */  p->link=hash[h]; hash[h]=p; /* insert |p| at beginning of hash list */}@ The information associated with a new identifier must be initializedin a slightly different way in \.{CWEAVE} than in \.{CTANGLE}; hence the|init_p| procedure.@<Pred...@>=void init_p();@ @<Enter a new name...@>= {  if (byte_ptr+l>byte_mem_end) overflow("byte memory");  if (name_ptr>=name_dir_end) overflow("name");  strncpy(byte_ptr,first,l);  (++name_ptr)->byte_start=byte_ptr+=l;  if (program==cweave) init_p(p,t);}@ The names of sections are stored in |byte_mem| together

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -