// ---- ‡ ­¥á¥­¨¥ ¯®¨¬¥­®¢ ­­®© ª®­áâ ­âë ¢ ᯨ᮪
AddConstToTree(dword keystring,constvalue)
dword ptr,newptr; // idrec structure
{
	newptr=LocalAlloc(0x40,recsize);
	IF(EAX==NULL){
		preerror("Compiler out of memory for identifier tree");
		ExitProcess(e_outofmemory);
	}
	ptr=treestart;
	IF(EAX == NULL ) // ãá⮩ ᯨ᮪?
	treestart = newptr;
	ELSE{
		for(;;){
// ®¨áª ᢮¡®¤­®© áá뫪¨
			ESI=ptr;
			EAX=lstrcmpA(DSDWORD[ESI+recid],keystring);
			ESI=ptr;
			IF(long EAX<0){
			// ptr.left
				IF(DSDWORD[ESI+left]==0){ //  è«¨ ¯ãá⮩ «¥¢ë© - ¤®¡ ¢¨¬
					DSDWORD[ESI+left]=newptr;
					BREAK;	// ptr.left=newptr
				}
				ptr=DSDWORD[ESI+left];
			}
			ELSE IF(EAX!=0){
			// ptr.right
				IF(DSDWORD[ESI+right]==0){	//  è«¨ ¯ãá⮩ ¯à ¢ë© - ¤®¡ ¢¨¬
					DSDWORD[ESI+right]=newptr;
					BREAK;
				}
				ptr=DSDWORD[ESI+right];
			}
			ELSE internalerror("string found in tree when trying to add to	it");
		}
	}
// ”®à¬¨à㥬 ­®¢ãî § ¯¨áì ¢ ᯨ᪥
	ESI=newptr;
	DSDWORD[ESI+recid]=LocalAlloc(0x40,lstrlenA(keystring)+1);
	lstrcpyA(DSDWORD[ESI+recid],keystring);
	ESI=newptr;
	DSDWORD[ESI+newid]= NULL;
	DSDWORD[ESI+rectok]=tk_number;
	DSDWORD[ESI+recnumber]=constvalue;
	DSDWORD[ESI+recpost]=0;
	DSDWORD[ESI+left]=NULL;
	DSDWORD[ESI+right]=NULL;
	DSDWORD[ESI+recmodline] = currmod<<16+linenumber;
}

// ---- „®¡ ¢¨âì «®ª «ì­ãî ¯¥à¥¬¥­­ãî ¢ ᯨ᮪
AddLocalvar(dword str,tk,ltype,num)
dword newptr;
{
	newptr=LocalAlloc(0x40,local_size);
	IF(EAX==NULL){
		preerror("Compiler out of memory for local symbol linked list");
		ExitProcess(e_outofmemory);
	}
	IF(locallist==NULL)locallist = newptr;
	ELSE{
		EAX=locallist;
		EBX><EAX;	//ptr;
		for(;;){
			EAX=DSDWORD[EBX+localnext];
			IF(EAX==0)BREAK;
			EBX><EAX;
		}
		DSDWORD[EBX+localnext]=newptr;
	}
	EBX=newptr;
	lstrcpyA(EBX+localid,str);
	EBX=newptr;
	DSDWORD[EBX+localtok] = tk;
	DSDWORD[EBX+localtype] = ltype;
	DSDWORD[EBX+localnumber] = num;
	DSDWORD[EBX+localnext] = NULL;
	localptr=EBX;
}

// ---- „®¡ ¢¨âì ¨¤¥­â¨ä¨ª â®à ¢ ᯨ᮪
AddToTree(dword keystring)
dword ptr,newptr;
{
	newptr=LocalAlloc(0x40,recsize);
	IF(EAX==NULL)outofmemory();
	ptr = treestart;
//WRITESTR(keystring);WRITESTR("\n");
	IF(EAX==NULL)treestart = newptr;
	ELSE{
		for(;;){
// ®¨áª ᢮¡®¤­®© áá뫪¨
			ESI=ptr;
			EAX=lstrcmpA(DSDWORD[ESI+recid],keystring);
			ESI=ptr;
			IF(long EAX<0){
			// ptr.left
				IF(DSDWORD[ESI+left]==0){ //  è«¨ ¯ãá⮩ «¥¢ë© - ¤®¡ ¢¨¬
					DSDWORD[ESI+left]=newptr;
					BREAK;	// ptr.left=newptr
				}
				ptr=DSDWORD[ESI+left];
			}
			ELSE IF(EAX!=0){
				// ptr.right
				IF(DSDWORD[ESI+right]==0){	//  è«¨ ¯ãá⮩ ¯à ¢ë© - ¤®¡ ¢¨¬
					DSDWORD[ESI+right]=newptr;
					BREAK;
				}
				ptr=DSDWORD[ESI+right];
			}
			ELSE internalerror("string found in tree when trying to add to	it");
		}
	}
	ESI=newptr;
	DSDWORD[ESI+recid]=LocalAlloc(0x40,lstrlenA(keystring)+1);
	lstrcpyA(EAX,keystring);
	IF(tok == tk_string){
		ESI=newptr;
		DSDWORD[ESI+newid] = LocalAlloc(0x40,number+1);
		IF( EAX == NULL )outofmemory();
		ECX=number;
		EDI=EAX;
		ESI=#string;
		$REP $MOVSB
	}
	ELSE{
		IF( lstrlenA(#string) == 0 ){
			ESI=newptr;
			DSDWORD[ESI+newid]=NULL;
		}
		ELSE{
			ESI=newptr;
			DSDWORD[ESI+newid]=LocalAlloc(0x40,lstrlenA(#string)+1);
			IF( EAX == NULL )outofmemory();
			lstrcpyA(EAX,#string);
		}
	}
	ESI=newptr;
	DSDWORD[ESI+rectok] = tok;
	DSDWORD[ESI+recnumber] = number;
	DSDWORD[ESI+rectype] = type;
	DSDWORD[ESI+recsrc] = src;
	DSDWORD[ESI+recpost] = post;
	DSDWORD[ESI+left] = NULL;
	DSDWORD[ESI+right] = NULL;
	DSDWORD[ESI+recmodline] = modline;
	treeptr = newptr;
}

// ---- ‚뢮¤ ¢á¥å ¨¤¥­â¨ä¨ª â®à®¢
void DisplayTree ()
{ 	// dump all identifiers to MAP file
	fprint(mapfile,"ALL GLOBAL IDENTIFIERS LIST:\n");
	fprint(mapfile,"tok    type      number    post\tIDENTIFIER\n");
	numberofids = 0;
	DisplayTreeAll(treestart);
	wsprintfA(#mapstr,"\n    %u Unique Global Identifiers.\n\n",numberofids);
	fprint(mapfile,#mapstr);
	fprint(mapfile,"GLOBAL CONSTANT IDENTIFIER LIST:\n");
	numberofids = 0;
	DisplayTreeConstants(treestart);
	wsprintfA(#mapstr,"\n    %u Unique Global Constant Value Identifiers.\n\n",numberofids);
	fprint(mapfile,#mapstr);
}

// ---- ‚뢮¤ ¢á¥£® ᯨ᪠ ¨¤¥­â¨ä¨ ªâ®à®¢
DisplayTreeAll(dword ptr)
{
if( ptr != NULL ){
	ESI=ptr;
	DisplayTreeAll(DSDWORD[ESI+right]);
	ESI=ptr;
	if(DSDWORD[ESI+rectok]-DSDWORD[ESI+recpost]!=tk_API){
		wsprintfA(#mapstr,"%3d %8lXh %8lXh %6Xh\t%s\n",DSDWORD[ESI+rectok],
			DSDWORD[ESI+rectype],DSDWORD[ESI+recnumber],DSDWORD[ESI+recpost],
			DSDWORD[ESI+recid]);
		fprint(mapfile,#mapstr);
		EAX=DSDWORD[ESI+newid];
		IF(EAX!=0){
			IF(lstrcmpA(DSDWORD[ESI+recid],EAX) != 0 ){
				ESI=ptr;
				wsprintfA(#mapstr,"Alias=%s\n",DSDWORD[ESI+newid]);
				fprint(mapfile,#mapstr);
			}
		}
		IF(list){
			ESI=ptr;
			EAX=DSDWORD[ESI+recsrc];
			IF(EAX!=0){
				EBX=DSDWORD[ESI+recmodline]>>16;
				EAX=FILENAMESIZE*EBX+#modules;
				EBX=EAX;
				wsprintfA(#mapstr,"File:%s, line=%-d:\n%s\n",EBX,
					DSDWORD[ESI+recmodline]&0xFFFF,DSDWORD[ESI+recsrc]);
				fprint(mapfile,#mapstr);
				ESI=ptr; LocalFree(DSDWORD[ESI+recsrc]);	// Žá¢®¡®¤¨¬ ¯ ¬ïâì
				DSDWORD[ESI+recsrc]=0;
			}
		}
		numberofids++;
	}
	ESI=ptr;
	DisplayTreeAll(DSDWORD[ESI+left]);
}
}

// ---- ‚뢮¤ ᯨ᪠ £«®¡ «ì­ëå ª®­áâ ­â
DisplayTreeConstants(dword ptr)
{
	IF( ptr != NULL ){
		ESI=ptr;
		DisplayTreeConstants(DSDWORD[ESI+right]);
		ESI=ptr;
		EAX=DSDWORD[ESI+rectok];
		IF(EAX == tk_number){
			wsprintfA(#mapstr,"#define %10ld /* %8lX hex */ %s\n",
				DSDWORD[ESI+recnumber],DSDWORD[ESI+recnumber],DSDWORD[ESI+recid]);
			fprint(mapfile,#mapstr);
			numberofids++;
		}
		ESI=ptr;
		DisplayTreeConstants(DSDWORD[ESI+left]);
	}
}

// ---- ‚ëç¨á«¥­¨¥ §­ ç¥­¨ï ¡¥§§­ ª®¢®	ª®­áâ ­âë
dword DoConstDwordMath()
dword value;
{
	IF(tok == tk_minus){
		NextTok();
		IF(tok != tk_number){
			numexpected();
			return(0);
		}
		number = -number;
	}
	IF(tok != tk_number){
		numexpected();
		return(0);
	}
	value = number;
	while(tok2isopperand()){
		NextTok();
		IF(tok2!=tk_number)return(value);
		switch(tok){
			case tk_minus:	 value -= number2; break;
			case tk_plus:  value += number2;	 break;
			case tk_xor:		value ^= number2;  break;
			case tk_and:		value &= number2;  break;
			case tk_or: 	value |= number2; 	 break;
			case tk_mod:		value = value % number2; BREAK;
			case tk_div:		value = value / number2; BREAK;
			case tk_mult: 	value = value * number2; BREAK;
			case tk_rr: 	value >>= number2;				 BREAK;
			case tk_ll: 	value <<= number2;				 BREAK;
			case tk_xorminus:  value ^= -number2; 	 BREAK;
			case tk_andminus:  value &= -number2; 	 BREAK;
			case tk_orminus:	 value |= -number2; 	 BREAK;
/*		case(tok==tk_modminus)	value %= -number2;
		case(tok==tk_divminus)	value /= -number2;
		case(tok==tk_multminus) value *= -number2; */
			case tk_rrminus:	 value >>= -number2;	 BREAK;
			case tk_llminus:	 value <<= -number2;	 BREAK;
		}
		NextTok();
	}
	return(value);
}

// ---- ‚ëç¨á«¥­¨¥ §­ ç¥­¨ï §­ ª®¢®© ª®­áâ ­âë
long DoConstMath()
long value;
{
	IF(tok == tk_minus){
		NextTok();
		IF(tok != tk_number){
			numexpected();
			return(0);
		}
		number = -number;
	}
	IF(tok != tk_number){
		numexpected();
		return(0);
	}
	value = number;
	while(tok2isopperand()){
		NextTok();
		IF(tok2 != tk_number) return(value);
		switch(tok){
			case tk_minus:	 value -= number2; break;
			case tk_plus:  value += number2;	 break;
			case tk_xor:		value ^= number2;  break;
			case tk_and:		value &= number2;  break;
			case tk_or: 	value |= number2; 	 break;
			case tk_mod:		value = value % number2; BREAK;
			case tk_div:		value = value / number2; BREAK;
			case tk_mult: 	value = value * number2; BREAK;
			case tk_rr: 	value >>= number2;				 BREAK;
			case tk_ll: 	value <<= number2;				 BREAK;
			case tk_xorminus:  value ^= -number2; 	 BREAK;
			case tk_andminus:  value &= -number2; 	 BREAK;
			case tk_orminus:	 value |= -number2; 	 BREAK;
/*		case(tok==tk_modminus)	value %= -number2;
		case(tok==tk_divminus)	value /= -number2;
		case(tok==tk_multminus) value *= -number2; */
			case tk_rrminus:	 value >>= -number2;	 BREAK;
			case tk_llminus:	 value <<= -number2;	 BREAK;
		}
		NextTok();
	}
	return(value);
}

// ---- ‚ëç¨á«¥­¨¥ §­ ç¥­¨ï §­ ª®¢®© ª®­áâ ­âë
long DoConstLongMath()
long value;
{
	value=DoConstMath();
	NextTok();
	return(value);
}

// ---- ‘«¥¤ãî騩 token - ®¯¥à æ¨ï?
dword tok2isopperand()
{
	EAX=tok2;
	IF(EAX==tk_plus)||(EAX==tk_minus)||(EAX==tk_mult)||(EAX==tk_div)||(EAX==tk_mod)||
	(EAX==tk_rr)||(EAX==tk_ll)||(EAX==tk_or)||(EAX==tk_and)||(EAX==tk_xor)||
	(EAX==tk_divminus)||(EAX==tk_modminus)||(EAX==tk_multminus)||(EAX==tk_xorminus)||
	(EAX==tk_orminus)||(EAX==tk_andminus)||(EAX==tk_llminus)||(EAX==tk_rrminus)return(1);
	return(0);
}

// ---- ‘«¥¤ãî騩 token § ªà뢠¥â ¢ëà ¦¥­¨¥?
dword tok2notstopper ()
{
	EAX=tok2;
	IF(EAX==tk_semicolon)||(EAX==tk_comma)||(EAX==tk_closebracket)||
	(EAX==tk_openblock)EAX=0;
	ELSE EAX=1;
}

// ---- ®¨áª ¢ ᯨ᪥ «®ª «ì­ëå ¯¥à¥¬¥­­ëå
SearchLocals(dword tok4,type4,string4,number4)
{
	if( locallist != NULL ){
		localptr = locallist;
S00:
		ESI=EAX;	//localptr;
		lstrcmpA(string4,ESI+localid);
		ESI=localptr;
		IF(EAX==0){ 	// ¥à¥¬¥­­ ï ­ ©¤¥­ 
			EBX=number4;
			DSDWORD[EBX]=DSDWORD[ESI+localnumber];
			EBX=type4;
			DSDWORD[EBX]=DSDWORD[ESI+localtype];
			EBX=tok4;
			EAX=DSDWORD[ESI+localtok];
			DSDWORD[EBX]=EAX;
			IF(EAX==tk_local){
				EBX=number4;
				DSDWORD[EBX]-=localsize;
			}
			ELSE IF(EAX==tk_param){
				EBX=number4;
				EAX=DSDWORD[EBX]+4;
				DSDWORD[EBX]=EAX;
				IF(current_proc_type==cpt_far)DSDWORD[EBX]+=4;	// move over seg on stack
			}
			ELSE IF(EAX!=tk_locallabel)&&(EAX!=tk_number)internalerror("Bad *tok4 value in SearchLocals");
		}
		ELSE{
			IF(DSDWORD[ESI+localnext]!=NULL){
				localptr=DSDWORD[ESI+localnext];
				$JMP S00
			}
		}
	}
}

// ---- ®¨áª ¢ ᯨ᪥ £«®¡ «ì­ëå ¨¤¥­â¨ä¨ª â®à®¢
dword SearchTree(dword tok4,type4,src4,post4,string4,number4)
dword ptr;
long cmpresult;
{
	cmpresult=123;
	ptr = treestart;
// ®¨áª ᢮¡®¤­®© áá뫪¨
	for(;;){
		ESI=EAX;
		IF(ESI==0){
			treeptr=NULL;
			return(0);	// Not found
		}
		cmpresult = lstrcmpA(DSDWORD[ESI+recid],string4);
		ESI=ptr;
		IF(cmpresult<0)ptr=DSDWORD[ESI+left];
		ELSE IF(cmpresult>0)ptr=DSDWORD[ESI+right];
		ELSE BREAK;
	}
	EBX=number4; DSDWORD[EBX]=DSDWORD[ESI+recnumber];
	EBX=type4; DSDWORD[EBX]=DSDWORD[ESI+rectype];
	EBX=src4; DSDWORD[EBX]=DSDWORD[ESI+recsrc];
	EBX=post4; DSDWORD[EBX]=DSDWORD[ESI+recpost];
	EBX=tok4; EAX=DSDWORD[ESI+rectok]; DSDWORD[EBX]=EAX;
	IF(EAX==tk_string ){
		EBX=number4; ECX=DSDWORD[EBX]; EDI=string4;
		ESI=DSDWORD[ESI+newid]; $REP $MOVSB
	}
	ELSE{
		IF(DSDWORD[ESI+newid])lstrcpyA(string4,DSDWORD[ESI+newid]);
	}
	ESI=ptr;
	IF(lstrcmpA(DSDWORD[ESI+recid],string4)!=0) // à®¢¥à¨¬: ¬¥­ï«®áì «¨ ¨¬ï ¨¤¥­â¨ä¨ª â®à 
		SearchTree(tok4,type4,src4,post4,string4,number4);	// „  - ¯®¢â®à¨¬ ¯®¨áª
	treeptr = ptr;
	return(1);
}

// ---- ®¨áª ­¥®âª®¬¯¨«¨à®¢ ­­ëå ¥é¥ ááë«®ª
dword SeekToDo(dword ptr)
{
	IF(ptr!=NULL){
		ESI=ptr;
		IF(SeekToDo(DSDWORD[ESI+right]))RETURN(1);
		ESI=ptr; EAX=DSDWORD[ESI+recpost];
		IF(EAX>1){
			treeptr=ptr; ESI=ptr;
			number=DSDWORD[ESI+recnumber];
			type=DSDWORD[ESI+rectype]; modline=DSDWORD[ESI+recmodline];
			src=DSDWORD[ESI+recsrc];
			post=DSDWORD[ESI+recpost];
			tok=DSDWORD[ESI+rectok]; RETURN(1);
		}
		ESI=ptr;
		IF(SeekToDo(DSDWORD[ESI+left]))RETURN(1);
	}
	return(0);
}

// ---- ®¨áª ­¥§ ªàëâëå ááë«®ª
SeekUndefined(dword ptr)
{
	IF( ptr != NULL ){
		ESI=ptr;
		SeekUndefined(DSDWORD[ESI+right]);
		ESI=ptr; EAX=DSDWORD[ESI+rectok];
		IF(EAX==tk_undefproc){
			wsprintfA(#mapstr,"'%s' undefined\n",DSDWORD[ESI+recid]);
			IF( makemapfile )fprint(mapfile,#mapstr);
			WRITESTR(#mapstr);
		}
		ESI=ptr;
		SeekUndefined(DSDWORD[ESI+left]);
	}
}