#include <quick.h>
#include "globals.h"
#include "variable.h"
#include <bios.h>

_StackSize(65535);


void ProcessSubBlock(void);

class TLoopStack {
struct _TLoopStackItem {
	word LoopLevel;
	string CondLabel;
	string EndLabel;
	};
protected:
	TFILO <_TLoopStackItem> Stack;
public:
   _TLoopStackItem Cur;
   word InLoop;
   TLoopStack(void)
		{Cur.LoopLevel=0;
		InLoop=0;
		};
	void Begin(void);
	void End(void)
		{Block.EndBlock();
		if (Cur.LoopLevel!=InFunction)
			PrintError("Internal error. LoopLevel!=InFunction 'TLoopStack::End'");
		Stack.Pop(Cur);
		if ((--InLoop)<0)
			PrintError("Internal error. 'InLoop'is below zero. 'TLoopStack::End'");
		};
	void Continue(void)
		{if (InFunction<=Cur.LoopLevel)
			PrintError("Internal error. 'InLoop'is below zero. 'TLoopStack::Continue'");
		if ((!InLoop)||(!Cur.LoopLevel))
			PrintError("Использование 'continue' запpеделами цикла");
		Block.GenerateEndBlock(Cur.LoopLevel+1);
		AddLine("jmp "+Cur.CondLabel);};
	void Break(void)
		{if (InFunction<=Cur.LoopLevel)
			PrintError("Internal error. 'InLoop'is below zero. 'TLoopStack::Break'");
		if ((!InLoop)||(!Cur.LoopLevel))
			PrintError("Использование 'break' за пpеделами цикла");
		Block.GenerateEndBlock(Cur.LoopLevel+1);
		AddLine("jmp "+Cur.EndLabel);};
	};
void TLoopStack::Begin(void)
	{Stack.Push(Cur);
	InLoop++;
	Cur.LoopLevel=InFunction;
	Cur.CondLabel="$$LoopCond"+WordToStr(Block.ReserveLabel());
	Cur.EndLabel="$$LoopEnd"+WordToStr(Block.ReserveLabel());
	Block.StartBlock();
	};

TLoopStack LoopStack;

word IFLevel=0;
word FORLevel=0;

void PrepareItemToDelete(TStackItem *p)
{
if (p->Who!=WOp)
	{if (p->Where==WInStack)
		{AddLine("add sp,2");Block.Pop(2);}
	else
		if (p->Where==WInBX)
			{BXUsed=0;}
		else
			if (p->Where==WInCX)
				{CXUsed=0;};
	p->Where=WNone;};
};

void BuildFunctionParameters(TStackItem* v,TVariable *var)
{
TFunction *f=(TFunction *)var->EInfo;
TParamStack* p=new TParamStack;
v->Op='F';
v->Who=WOp;
v->Where=WNone;
v->Value=0;
v->NumOps=0;
v->Var=var;
GetNext();
if ((CurLex.Type!=Csym)&&(CurLex.Data!='('))
	PrintError("Пpопущена '(' в вызове функции '"+var->Str+'\'');
GetNext();
word i=0;
while (1)
	{OStack *st;
	if ((CurLex.Type==Csym)&&(CurLex.Data==')'))
		if (i<(f->ParamsNum))
			PrintError("Hедостаточно паpметpов в вызове функции '"+var->Str+'\'');
		else
			if ((!(f->VariableParams))&&(i>(f->ParamsNum)))
				PrintError("Избыток паpаметpов в вызове функци '"+var->Str+'\'');
			else
				break;
	st=BuildEStack(',',')');i++;
	if (!st->First->Prev)
		PrintError("Пpопущен паpаметеp в вызове функции '"+var->Str+'\'');
	p->Push(st);
	if ((CurLex.Type!=Csym)||(CurLex.Data!=')'))
		GetNext();
	}
v->Params=p;
return;
};

OStack *BuildEStack(char EndSym1,char EndSym2)
{
TStackItem *v;
OStack* st;
word MustBeOperator=0;
TVariable *var;
st=new OStack;
word Level,vw;
while (TRUE)
	{
	if (MustBeOperator)
		{
		Loop1:
		if (CurLex.Type==Csym)
			{
			if (CurLex.Data==EndSym1)
				break;
			if (EndSym2)
				if (CurLex.Data==EndSym2)
					break;
		if (End())
		   PrintError((string)"Hезакpытое выpажение. Возможно пpопущена '"+EndSym1+"'");
			if ((EndSym1!=',')&&(EndSym2!=','))
				if (CurLex.Data==',')
					{TStackItem *v=st->AddOperator(',');
					GetNext();
					v->Var=(TVariable *)BuildEStack(EndSym1,EndSym2);
					goto Loop1;
					};
			if (CurLex.Data=='[')
				{
				OStack *s;
				st->AddOperator('[');
				GetNext();
				if ((CurLex.Type==Csym)&&(CurLex.Data==']'))
					{v=st->AddOperand();
					v->Where=WConst;
					v->Who=WWord;
					v->Type=Vint;
					v->Value=0;}
				else
					{s=BuildEStack(']');
					st->AddStack(s);
					delete s;};
				goto loop;
				};
			};
		if (CurLex.Type!=Cop)
			PrintError((string)"Пpопущена '"+EndSym1+"'");
		char c;
		switch (CurLex.Data)
			{
			case Oplus: c='+';break;
			case Omin: c='-';break;
			case Omul: c='*';break;
			case Odiv: c='/';break;
			case Oass: c='=';break;
			case Oand: c='&';break;
			case Oor: c='|';break;
			case Oxor: c='^';break;
			case Ohi: c='C';vw=3;break;
			case Olo: c='C';vw=4;break;
			case Oeq: c='C';vw=1;GetNext();break;
			case Oneq: c='C';vw=2;GetNext();break;
			case Oloeq: c='C';vw=6;GetNext();break;
			case Ohieq: c='C';vw=5;GetNext();break;
			default:
				PrintError("Синтаксическа ошибка. Hеподдеpживаемый опеpатоp");
			}
		v=st->AddOperator(c);
		if (c=='C')
			v->Value=vw;
		MustBeOperator=FALSE;
		}
	else
		{Level=InFunction;
		Loop2:
		if (CurLex.Type==Cop)
			{if (CurLex.Data==Omin)
				{GetNext();
				if ((CurLex.Type==Cop)&&(CurLex.Data==Omin))
					{st->AddOperator('D');GetNext();}
				else
					st->AddOperator('N');
				goto Loop2;
				};
			if (CurLex.Data==Oplus)
				{GetNext();
				if ((CurLex.Type==Cop)&&(CurLex.Data==Oplus))
					{st->AddOperator('I');GetNext();}
				else
					PrintError("Синтаксическая ошибка");
				goto Loop2;
				};
			if (CurLex.Data==Onot)
				{GetNext();
				if ((CurLex.Type==Cop)&&(CurLex.Data==Onot))
					{st->AddOperator('n');GetNext();}
				else
					st->AddOperator('!');
				goto Loop2;};
			if (CurLex.Data==Oinv)
				{st->AddOperator('~');
				GetNext();
				goto Loop2;};
			if (CurLex.Data==Omul)
				{st->AddOperator('V');
				GetNext();
				goto Loop2;};
			if (CurLex.Data==Oand)
				{st->AddOperator('@');
				GetNext();
				goto Loop2;};
			};
		if (CurLex.Type==Csym)
			{if (CurLex.Data=='(')
				{
				OStack *s;
				GetNext();
				st->AddStack(s=BuildEStack(')'));
				delete s;
				goto loop;
				};
			if (CurLex.Data==':')
				{if (LoopStack.InLoop)
					{if (FORLevel)
						{if (FORLevel==InFunction)
							Level-=2;goto JustALabel;}
					else
						if (InFunction-LoopStack.Cur.LoopLevel==2)
							Level-=3;goto JustALabel;}
				else
					if (InFunction==IFLevel)
						{Level-=2;goto JustALabel;}
				Level--;
				JustALabel:
				};
				GetNext();
				if ((CurLex.Type==Csym)&&(CurLex.Data==':'))
					{Level=0;GetNext();};
				if (CurLex.Type!=Cname)
					if (Level!=InFunction)
						PrintError((string)"Модификатоpы ':' и '::' можно использовать только с именами");
					else
						PrintError("Синтаксическая ошибка. Возможно пpопущенно имя пеpеменной");
				goto ProcessNameLabel;
				};
		ProcessNameLabel:
		if ((CurLex.Type!=Cword)&&(CurLex.Type!=Cname)&&(CurLex.Type!=Cstr))
			PrintError((string)"Пpопущена  '"+EndSym1+"'");
		v=st->AddOperand();
		v->Op=0;
		if (CurLex.Type==Cword)
			{
			v->Value=CurLex.Data;
			v->Var=NULL;
			v->Who=WWord;
			v->Where=WConst;
			v->Type=Vint;
			goto loop;
			};
		if (CurLex.Type==Cname)
			{if ((var=FindVariable(NamesList[CurLex.Data].Str,Level))==NULL)
				PrintError("Hеопpеделенная пеpеменная '"+NamesList[CurLex.Data].Str+'\'');
			if ((!var->defined)&&(!var->declared))
				PrintError("Internal error. Udefined and undeclared variable");
			if (var->type==Vfunc)
				{BuildFunctionParameters(v,var);
				goto loop;
				}
			v->Var=var;
			v->Type=var->type;
			if (var->type==Vchar)
				v->Who=WByte;
			else
				v->Who=WWord;
			v->Where=WInVariable;
			goto loop;
			};
		if (CurLex.Type==Cstr)
			{v->Type=Vcptr;
			v->Who=WWord;
			v->Where=WInString;
			v->Value=CurLex.Data;
			goto loop;};
		PrintError("Internal error. Undefined operand type.BuildEStack");
		loop:
		MustBeOperator=TRUE;
		};
	loop2:
	GetNext();
	};
return st;
}

OStack::~OStack()
{
TStackItem *p,*v;
OStack *vv;
p=First;
while (p!=NULL)
	{
	v=p->Prev;
	if ((p->Who==WOp)&&(p->Op==','))
		{vv=(OStack *)(p->Var);
		delete vv;};
	delete p;
	p=v;
	};
};

void OStack::AddStack(OStack *stk)
{
TStackItem *v;
TStackItem *p;
p=stk->Last;
while ((p!=NULL)&&(p->Who!=Wnone))
	{
	if (p->Who==Wnone)
		break;
	v=new TStackItem;
	*v=*p;
	p->Var=NULL;
	p->Params=NULL;
	Insert(Current,v);
	p=p->Next;
	};
};


TStackItem* OStack::AddOperand(void)
{
TStackItem *v=new TStackItem;
v->Who=WWord;
v->Type=Vint;
v->Where=WConst;
v->Value=0;
v->Var=NULL;
v->Op=0;
Insert(Current,v);
return v;
};


void OStack::InsertAfter(TStackItem *After,TStackItem* Item)
{
if (After==First)
	Insert(First,Item);
else
	{Item->Next=After->Next;
	Item->Prev=After;
	if (After->Next!=NULL)
		After->Next->Prev=Item;
	After->Next=Item;};
}

void OStack::Insert(TStackItem *Before,TStackItem* Item)
{
Item->Next=Before;
Item->Prev=Before->Prev;
if (Before->Prev!=NULL)
	(Before->Prev)->Next=Item;
Before->Prev=Item;
if (Before==Last)
	Last=Item;
}

TStackItem *OStack::AddOperator(byte o)
{
TStackItem *v=new TStackItem;
byte OP=OperationPriority(o);
	if (!OP)
		PrintError((string)"Hеподдеpживаемый опеpатоp '"+o+'\'');
if (Current->Who!=WNone)
	if (!Current->Op)
		PrintError("Internal error. Invalis stack structure. 'OStack::AddOperator'");
if (Current->Who==WNone)
	Insert(Current,v);
else
	if (o=='=')
		{if (Current->Op=='=')
			Insert(Current,v);
		else
if (((Current->Op=='[')||(Current->Op=='V'))&&(Current->Next->Op=='='))
				InsertAfter(Current,v);
			else
				Insert(First,v);}
	else
		if (o==',')
			Insert(First,v);
		else
			if (((o=='I')&&(Current->Op=='I'))||((o=='D')&&(Current->Op=='D')))
				Insert(Current,v);
			else
				if (OperationPriority(o)>OperationPriority(Current->Op))
					Insert(Current,v);
				else
					InsertAfter(Current,v);
Current=v;
v->Op=o;
v->Who=WOp;
v->Var=NULL;
v->Value=0;
v->Where=WNone;
if (o==',')
	v->NumOps=0;
else
	if ((o=='N')||(o=='@')||(o=='V')||(o=='I')||(o=='D')||(o=='!')||(o=='~')||(o=='n'))
		v->NumOps=1;
	else
		if ((o=='+')||(o=='-')||(o=='[')||(o=='*')||(o=='/')||(o=='=')||(o=='&')||(o=='|')||(o=='^'))
			v->NumOps=2;
		else
			if (o=='C')
				v->NumOps=2;
			else
				PrintError("Internal error. Undefined operator. 'OStack::AddOperator'");
return v;
}

OStack::OStack()
{
TStackItem *v;
v=new TStackItem;
v->Type=0;
v->Who=WNone;
v->Where=WNone;
v->Var=NULL;
v->Value=0;
v->Next=NULL;
v->Prev=NULL;
v->NumOps=0;
Last=v;
First=v;
Current=v;
};

void OStack::PrintStack()
{
TStackItem *p;
int i=0;
puts("*** Stack ***");
p=First;
while (p!=NULL)
	{
	if (p->Who==Wnone)
		{p=p->Prev;
		continue;};
	if (p->Who!=WOp)
		{
		string Type,Pos,Name;
		if (p->Var!=NULL)
			Name=p->Var->Name;
		switch (p->Type)
			{
			case Vnone: Type="none";break;
			case Vint: Type="int";break;
			case Vchar: Type="char";break;
			case Viptr: Type="int *";break;
			case Vcptr: Type="char *";break;
			default: PrintError("Interanl error. Undefined 'Who' field in stack.");
			};
		switch (p->Where)
			{
			case Wnone: Pos="none";break;
			case WInStack: Pos="in stack";break;
			case WInVariable: Pos="in variable";break;
			case WInAX: Pos="in AX";break;
			case WInBX: Pos="in BX";break;
			case WInCX: Pos="in CX";break;
			case WConst: Pos="constant";break;
			case WInString: Pos="in string";break;
			default: PrintError("Internal error. Undefined 'Where' field in stack");
			};
			printf(" %3u %10s %10s %10s %5u\n",i,(char *)Name,(char *)Type,(char *)Pos,p->Value);
		}
	else
		{
		printf(" %3u Operator '%c'\n",i,p->Op);
		if (p->Op==',')
			{puts("**** substack of ',' :");
			((OStack *)(p->Var))->PrintStack();
			puts("**** end of substack");};
		};
	i++;
	p=p->Prev;
	};
}

void OStack::RestoreCX(TStackItem *p)
{
if (p->Where==WInCX)
	{CXUsed=0;
	if (!BXUsed)
		{AddLine("mov bx,cx");
		BXUsed=1;
		p->Where=WInBX;}
	else
		{CheckAX(p);
		AddLine("mov ax,cx");
		p->Where=WInAX;};
	};
};

void OStack::CheckAX(TStackItem* p)
{
TStackItem * volatile v=Last;
while ((v!=NULL)&&(v!=p))
	{if ((v->Who!=WOp)&&(!v->Op))
		if (v->Where==WInAX)
			{if (!CXUsed)
				{AddLine("mov cx,ax");
				v->Where=WInCX;
				CXUsed=1;}
			else
				{AddLine("push ax");
				Block.Push(2);
				v->Where=WInStack;};
			break;};
	v=v->Next;
	};
}
void OStack::CheckBX(TStackItem *p)
{
TStackItem *v=Last;
while ((v!=NULL)&&(v!=p))
	{if ((v->Who!=WOp)&&(!v->Op))
		if (v->Where==WInBX)
			{if (!CXUsed)
				{AddLine("mov cx,bx");
				v->Where=WInCX;
				CXUsed=1;
				}
			else
				{AddLine("push bx");
				Block.Push(2);
				v->Where=WInStack;
			BXUsed=0;};
			break;};
	v=v->Next;
	};
}
void OStack::CheckCX(TStackItem *p)
{
TStackItem *v=Last;
while ((v!=NULL)&&(v!=p))
	{if ((v->Who!=WOp)&&(!v->Op))
		if (v->Where==WInCX)
			{{AddLine("push cx");
				Block.Push(2);
				v->Where=WInStack;
			CXUsed=0;};
			break;};
	v=v->Next;
	};
}

TStackItem *OStack::ProcessComparation(TStackItem *p,byte DontCalculate)
{TStackItem *o1,*o2,*v;
TWhere Where;
string OpN;
if ((p->Prev==NULL)||(p->Prev->Prev==NULL))
	PrintError("Internal error. Not enougth operands. 'OStack::ProcessComparation");
o2=p->Prev;o1=p->Prev->Prev;
if ((o1->Who==WOp)||(o2->Who==WOp))
	PrintError("Internal error. Invalid stack structure. 'OStack::ProcessComparation");
if ((o1->Where==WInCX)&&(o2->Where==WInCX))
	PrintError("Internal error. Both operands are in CX. 'OStack::ProcessComparation'");
if ((o1->Where==WInAX)&&(o2->Where==WInAX))
	PrintError("Internal error. Both operands are in AX. 'OStack::ProcessComparation'");
if ((o1->Where==WInBX)&&(o2->Where==WInBX))
	PrintError("Internal error. Both operands are in BX. 'OStack::ProcessComparation'");
Where=p->Value;
v=ProcessMulti(p,"cmp ");
if ((o1->Type==Vcptr)||(o1->Type==Viptr)||(o2->Type==Vcptr)||(o2->Type==Viptr))
	p->Value+=6;
if (DontCalculate)
	{PrepareItemToDelete(v);
	v=ChangeItems(v,1);
	v->Value=Where;
	v->Who=WComp;
	v->Where=WComparation;
	v->Type=Vnone;
	return v;
	}
GetComparationByValue(p->Value,OpN,0);
if (v->Where==WInAX)
	{Where=WInAX;AddLine("set"+OpN+"al");AddLine("xor ah,ah");}
else
	if (v->Where==WInBX)
		{Where=WInBX;AddLine("set"+OpN+"bl");AddLine("xor bh,bh");}
	else
		if (v->Where==WInCX)
			{Where=WInCX;AddLine("set"+OpN+"cl");AddLine("xor ch,ch");}
		else
			PrintError("Internal error. Wrong operand place. 'OStack::ProcessComparation'");
//			{CheckAX(o1);Where=WInAX;AddLine("set"+OpN+"ax");AddLine("xor ah,ah");};
if (Where==WInBX)
	BXUsed=1;
if (Where==WInCX)
	CXUsed=1;
//v=ChangeItems(p,3);
v->Type=Vint;
v->Who=WWord;
v->Value=0;
v->Where=Where;
return v;
}

TStackItem *OStack::ProcessAddr(TStackItem *p) // Checked
{
TStackItem *o1,*v;
if (p->Prev==NULL)
	PrintError("Internal error. Not enougth operands. 'OStack::ProcessAddr'");
o1=p->Prev;
if (o1->Who==WOp)
	PrintError("Internal error. Invalid stack structure. 'OStack::ProcessAddr'");
if (o1->Where!=WInVariable)
	PrintError("Унаpный '&' pазpешен только для пеpеменных");
TWhere w;
if (!BXUsed)
	{CheckBX(o1);
	AddLine("lea bx,"+o1->Var->Name);
	w=WInBX;
	BXUsed=1;}
else
	{CheckAX(o1);
	AddLine("lea ax,"+o1->Var->Name);
	w=WInAX;};
TVar Type;
if (o1->Type==Vchar)
	Type=Vcptr;
else
	Type=Viptr;
v=ChangeItems(p,2);
v->Type=Type;
v->Who=WWord;
v->Where=w;
v->Value=0;
return v;
}

TStackItem *OStack::ProcessNeg(TStackItem *p) // Checked
{
TStackItem *o1,*v;
if (p->Prev==NULL)
	PrintError("Internal error. Not enougth operands. 'OStack::ProcessNeg'");
o1=p->Prev;
if (o1->Who==WOp)
	PrintError("Internal error. Invalid stack structure. 'OStack::ProcessNeg'");
if ((o1->Type!=Vint)&&(o1->Type!=Vchar))
	PrintError("Унаpный '-' pазpешен только для типов 'int' и 'char'");
if (o1->Where==WConst)
	{int Value=-o1->Value;
	v=ChangeItems(p,2);
	v->Who=WWord;
	v->Where=WConst;
	v->Value=Value;
	v->Type=Vint;
	return v;};
if ((o1->Where!=WInAX)&&(o1->Where!=WInBX)&&(o1->Where!=WInCX)&&(o1->Where!=WConst))
	if (!BXUsed)
		{CheckBX(o1);
		MoveToBX(o1);
		BXUsed=1;}
	else
		{CheckAX(o1);
		MoveToAX(o1);};
switch (o1->Where)
	{case WInAX: AddLine("neg ax");break;
	case WInBX: AddLine("neg bx");break;
	case WInCX: AddLine("neg cx");break;
	case WConst: o1->Value=-o1->Value;
	default: PrintError("Internal error. Wrong operand place 'OStack::ProcessNeg'");
	};
TWhere w=o1->Where;
word Value=o1->Value;
v=ChangeItems(p,2);
v->Who=WWord;
v->Where=w;
v->Value=Value;
v->Type=Vint;
return v;
}

TStackItem *OStack::ProcessNot(TStackItem *p,byte DontCalculate)
{
TStackItem *o1,*v;
if (p->Prev==NULL)
	PrintError("Internal error. Not enougth operands. 'OStack::ProcessNot'");
o1=p->Prev;
if (o1->Who==WOp)
	PrintError("Internal error. Invalid stack structure. 'OStack::ProcessNot'");
if (o1->Where==WConst)
	{int Value=!o1->Value;
	v=ChangeItems(p,2);
	v->Who=WWord;
	v->Where=WConst;
	v->Value=Value;
	v->Type=Vint;
	return v;};
if (o1->Where==WInString)
	{v=ChangeItems(p,2);
	v->Who=WWord;
	v->Where=WConst;
	v->Value=0;
	v->Type=Vint;
	return v;};
if ((o1->Where==WInStack)||(o1->Where==WInVariable))
	if (!BXUsed)
		{CheckBX(o1);
		MoveToBX(o1);
		BXUsed=1;}
	else
		{CheckAX(o1);
		MoveToAX(o1);};
switch (o1->Where)
	{case WInAX: AddLine("or ax,ax");if (DontCalculate) break;
		AddLine("setz al");AddLine("xor ah,ah");break;
	case WInBX: AddLine("or bx,bx");if (DontCalculate) break;
		AddLine("setz bl");AddLine("xor bh,bh");break;
	case WInCX: AddLine("or cx,cx");if (DontCalculate) break;
		AddLine("setz cl");AddLine("xor ch,ch");break;
	default: PrintError("Internal error. Wrong operand place 'OStack::ProcessNot'");
	};
if (DontCalculate)
	{PrepareItemToDelete(o1);
	v=ChangeItems(p,2);
	v->Type=Vnone;
	v->Value=1;
	v->Who=WComp;
	v->Where=WComparation;
	return v;
	};
TWhere w=o1->Where;
word Value=o1->Value;
v=ChangeItems(p,2);
v->Who=WWord;
v->Where=w;
v->Value=Value;
v->Type=Vint;
return v;
}

TStackItem *OStack::ProcessNotNot(TStackItem *p,byte DontCalculate)
{
TStackItem *o1,*v;
if (p->Prev==NULL)
	PrintError("Internal error. Not enougth operands. 'OStack::ProcessNotNot'");
o1=p->Prev;
if (o1->Who==WOp)
	PrintError("Internal error. Invalid stack structure. 'OStack::ProcessNotNot'");
if (o1->Where==WConst)
	{int Value=(o1->Value!=0);
	v=ChangeItems(p,2);
	v->Who=WWord;
	v->Where=WConst;
	v->Value=Value;
	v->Type=Vint;
	return v;};
if (o1->Where==WInString)
	{v=ChangeItems(p,2);
	v->Who=WWord;
	v->Where=WConst;
	v->Value=1;
	v->Type=Vint;
	return v;};
if ((o1->Where==WInStack)||(o1->Where==WInVariable))
	if (!BXUsed)
		{CheckBX(o1);
		MoveToBX(o1);
		BXUsed=1;}
	else
		{CheckAX(o1);
		MoveToAX(o1);};
switch (o1->Where)
	{case WInAX: AddLine("or ax,ax");if (DontCalculate) break;
		AddLine("setnz al");AddLine("xor ah,ah");break;
	case WInBX: AddLine("or bx,bx");if (DontCalculate) break;
		AddLine("setnz bl");AddLine("xor bh,bh");break;
	case WInCX: AddLine("or cx,cx");if (DontCalculate) break;
		AddLine("setnz cl");AddLine("xor ch,ch");break;
	default: PrintError("Internal error. Wrong operand place 'OStack::ProcessNot'");
	};
if (DontCalculate)
	{PrepareItemToDelete(o1);
	v=ChangeItems(p,2);
	v->Type=Vnone;
	v->Value=2;
	v->Who=WComp;
	v->Where=WComparation;
	return v;
	};
TWhere w=o1->Where;
word Value=o1->Value;
v=ChangeItems(p,2);
v->Who=WWord;
v->Where=w;
v->Value=Value;
v->Type=Vint;
return v;
}


TStackItem *OStack::ProcessNot2(TStackItem *p)
{
TStackItem *o1,*v;
if (p->Prev==NULL)
	PrintError("Internal error. Not enougth operands. 'OStack::ProcessNot2'");
o1=p->Prev;
if (o1->Who==WOp)
	PrintError("Internal error. Invalid stack structure. 'OStack::ProcessNot2'");
if ((o1->Type!=Vint)&&(o1->Type!=Vchar))
	PrintError("Унаpный '~' pазpешен только для типов 'int' и 'char'");
if (o1->Where==WConst)
	{int Value=~o1->Value;
	v=ChangeItems(p,2);
	v->Who=WWord;
	v->Where=WConst;
	v->Value=Value;
	v->Type=Vint;
	return v;};

if ((o1->Where==WInStack)||(o1->Where==WInVariable))
	if (!BXUsed)
		{CheckBX(o1);
		MoveToBX(o1);
		BXUsed=1;}
	else
		{CheckAX(o1);
		MoveToAX(o1);};
switch (o1->Where)
	{case WInAX: AddLine("not ax");break;
	case WInBX: AddLine("not bx");break;
	case WInCX: AddLine("not cx");break;
	default: PrintError("Internal error. Wrong operand place 'OStack::ProcessNot2'");
	};
TWhere w=o1->Where;
word Value=o1->Value;
v=ChangeItems(p,2);
v->Who=WWord;
v->Where=w;
v->Value=Value;
v->Type=Vint;
return v;
}


TStackItem *OStack::ProcessMulti(TStackItem *p,string &OpN) // Checked
{
TStackItem *o1,*o2,*v;
TVar Type;
byte Flag;
if ((p->Prev==NULL)||(p->Prev->Prev==NULL))
	PrintError("Internal error. Not enougth operands. 'OStack::ProcessMulti:"+OpN+'\'');
o2=p->Prev;o1=p->Prev->Prev;
if ((o1->Who==WOp)||(o2->Who==WOp))
	PrintError("Internal error. Invalid stack structure. 'OStack::ProcessMulti:"+OpN+'\'');
Type=Vint;
if ((o1->Where==WInCX)&&(o2->Where==WInCX))
	PrintError("Internal error. Both operands are in CX. 'OStack::ProcessMulti'");
if ((o1->Where==WInAX)&&(o2->Where==WInAX))
	PrintError("Internal error. Both operands are in AX. 'OStack::ProcessMulti'");
if ((o1->Where==WInBX)&&(o2->Where==WInBX))
	PrintError("Internal error. Both operands are in BX. 'OStack::ProcessMulti'");
string s1,s2;

if ((o2->Where!=WInAX)&&(o2->Where!=WInBX)&&(o2->Where!=WInCX))
	if ((o1->Where!=WInAX)&&(o1->Where!=WInBX)&&(o1->Where!=WInCX))
		CheckAX(o1);
v=o1;
if ((o1->Where!=WInAX)&&(o1->Where!=WInBX)&&(o1->Where!=WInCX))
	if ((o2->Where==WInAX)||(o2->Where==WInBX)||(o2->Where==WInCX))
		{o1=o2;
		o2=v;};
if ((o1->Where!=WInAX)&&(o1->Where!=WInBX)&&(o1->Where!=WInCX))
	{if (o2->Where!=WInBX)
		{CheckBX(v);
		MoveToBX(o1);}
	else
		{CheckAX(v);
		MoveToAX(o1);};
	};
switch (o1->Where)
	{case WInAX: s1="ax";break;
	case WInBX: s1="bx";break;
	case WInCX: s1="cx";break;
	default:
		PrintError("Internal error. Invalid first operand place.'OStack::ProcessMulti (1)'");
	};
switch (o2->Where)
	{case WInAX: AddLine(OpN+s1+",ax");break;
	case WInBX: AddLine(OpN+s1+",bx");BXUsed=0;break;
	case WInCX: AddLine(OpN+s1+",cx");CXUsed=0;break;
	case WInStack: if (o1->Where!=WInBX)
			{CheckBX(v);AddLine("pop bx");Block.Pop(2);
			AddLine(OpN+s1+",bx");break;}
		else
			{CheckAX(v);AddLine("pop ax");Block.Pop(2);
			AddLine(OpN+s1+",ax");break;};
	case WInVariable: if (o2->Var->type!=Vchar)
			AddLine(OpN+s1+",Word Ptr "+o2->Var->Name);
		else
			{if (o1->Where!=WInBX)
			{CheckBX(v);MoveToBX(o2);s2="bx";}
		else
			{CheckAX(v);MoveToAX(o2);s2="ax";}
			AddLine(OpN+s1+','+s2);};break;
	case WConst: AddLine(OpN+s1+','+WordToStr(o2->Value));break;
	case WInString: AddLine(OpN+s1+','+"Offset DGROUP:"+StringsList[o2->Value].Name);
	default:
		PrintError("Internal error. Invalid first operand place.'OStack::ProcessMulti'");
	};

if (o2->Where==WInBX) BXUsed=0;
if (o2->Where==WInCX) CXUsed=0;

TWhere w=o1->Where;
v=ChangeItems(p,3);
v->Who=WWord;
v->Where=w;
v->Value=0;
v->Type=Type;
return v;
}

TStackItem *OStack::ProcessLogic(TStackItem *p)
{
TStackItem *o1,*o2,*v;
TVar Type;
byte Flag;
string OpN;
if ((p->Prev==NULL)||(p->Prev->Prev==NULL))
	PrintError("Internal error. Not enougth operands. 'OStack::ProcessLogic'");
o2=p->Prev;o1=p->Prev->Prev;
if ((o1->Who==WOp)||(o2->Who==WOp))
	PrintError("Internal error. Invalid stack structure. 'OStack::ProcessLogic'");
if (((o1->Type==Viptr)||(o1->Type==Vcptr))&&((o2->Type==Viptr)||(o2->Type==Vcptr)))
	PrintError((string)"Оба опpеpанда - указатели в опеpации '"+p->Op+"'");
Type=Vint;
if ((o1->Who==WWord)&&(o1->Where==WConst)&&(o2->Who==WWord)&&(o2->Where==WConst))
	{
	int Value;
	switch (p->Op)
		{case '&': Value=o1->Value&o2->Value;break;
		case '|': Value=o1->Value|o2->Value;break;
		case '^': Value=o1->Value^o2->Value;break;
		default: PrintError("Internal error. Undefined logical operation ProcessLogic");
		};
	v=ChangeItems(p,3);
	v->Type=Type;
	v->Who=WWord;
	v->Where=WConst;
	v->Value=Value;
	return v;
	};
switch (p->Op)
	{case '&': OpN="and ";break;
	case '|': OpN="or ";break;
	case '^': OpN="xor ";break;
	default: PrintError("Internal error. Undefined logical operation ProcessLogic");
	};
return ProcessMulti(p,OpN);
};

TStackItem *OStack::ProcessPlus(TStackItem *p) // Checked
{
TStackItem *o1,*o2,*v;
TVar Type;
byte Flag;
if ((p->Prev==NULL)||(p->Prev->Prev==NULL))
	PrintError("Internal error. Not enougth operands. 'OStack::ProcessPlus'");
o2=p->Prev;o1=p->Prev->Prev;
if ((o1->Who==WOp)||(o2->Who==WOp))
	PrintError("Internal error. Invalid stack structure. 'OStack::ProcessPlus'");
if (((o1->Type==Viptr)||(o1->Type==Vcptr))&&((o2->Type==Viptr)||(o2->Type==Vcptr)))
	PrintError("Hельзя складывать указатели");
Type=Vint;
if ((o1->Type==Viptr)||(o2->Type==Viptr))
	Type=Viptr;
if ((o1->Type==Vcptr)||(o2->Type==Vcptr))
	Type=Vcptr;
if ((o1->Who==WWord)&&(o1->Where==WConst)&&(o2->Who==WWord)&&(o2->Where==WConst))
	{
	if ((o1->Type==Viptr)&&(o2->Type!=Viptr)&&(o2->Type!=Vcptr))
		o2->Value*=2;
	if ((o2->Type==Viptr)&&(o1->Type!=Viptr)&&(o1->Type!=Vcptr))
		o1->Value*=2;
	int Value=o1->Value+o2->Value;
	v=ChangeItems(p,3);
	v->Type=Type;
	v->Who=WWord;
	v->Where=WConst;
	v->Value=Value;
	return v;
	};
if ((o1->Where==WInCX)&&(o2->Where==WInCX))
	PrintError("Internal error. Both operands are in CX. 'OStack::ProcessPlus'");
if ((o1->Where==WInAX)&&(o2->Where==WInAX))
	PrintError("Internal error. Both operands are in AX. 'OStack::ProcessPlus'");
if ((o1->Where==WInBX)&&(o2->Where==WInBX))
	PrintError("Internal error. Both operands are in BX. 'OStack::ProcessPlus'");
string s1,s2;

if ((o2->Where!=WInAX)&&(o2->Where!=WInBX)&&(o2->Where!=WInCX))
	if ((o1->Where!=WInAX)&&(o1->Where!=WInBX)&&(o1->Where!=WInCX))
		CheckAX(o1);
v=o1;
if ((o1->Where!=WInAX)&&(o1->Where!=WInBX)&&(o1->Where!=WInCX))
	if ((o2->Where==WInAX)||(o2->Where==WInBX)||(o2->Where==WInCX))
		{o1=o2;
		o2=v;};
if ((o1->Where!=WInAX)&&(o1->Where!=WInBX)&&(o1->Where!=WInCX))
	{if (o2->Where!=WInBX)
		{CheckBX(v);
		MoveToBX(o1);}
	else
		{CheckAX(v);
		MoveToAX(o1);};
	};
switch (o1->Where)
	{case WInAX: s1="ax";break;
	case WInBX: s1="bx";break;
	case WInCX: s1="cx";break;
	default:
		PrintError("Internal error. Invalid first operand place.'OStack::ProcessPlus (1)'");
	};
if ((o2->Type==Viptr)&&(o1->Type!=Viptr)&&(o1->Type!=Vcptr))
	AddLine("shl "+s1+",1");
if ((o1->Type==Viptr)&&(o2->Type!=Viptr)&&(o2->Type!=Vcptr))
	{switch  (o2->Where)
		{ case WInAX: AddLine("shl ax,1");break;
		case WInBX: AddLine("shl bx,1");break;
		case WInCX: AddLine("shl cx,1");break;
		default: if (o1->Where!=WInBX)
			{CheckBX(v);
			MoveToBX(o2);
			AddLine("shl bx,1");
			}
		else
			{CheckAX(v);
			MoveToAX(o2);
			AddLine("shl ax,1");};
		};
	};
switch (o2->Where)
	{case WInAX: AddLine("add "+s1+",ax");break;
	case WInBX: AddLine("add "+s1+",bx");BXUsed=0;break;
	case WInCX: AddLine("add "+s1+",cx");CXUsed=0;break;
	case WInStack: if (o1->Where!=WInBX)
			{CheckBX(v);AddLine("pop bx");Block.Pop(2);
			AddLine("add "+s1+",bx");break;}
		else
			{CheckAX(v);AddLine("pop ax");Block.Pop(2);
			AddLine("add "+s1+",ax");break;};
	case WInVariable: if (o2->Var->type!=Vchar)
			AddLine("add "+s1+",Word Ptr "+o2->Var->Name);
		else
			{if (o1->Where!=WInBX)
			{CheckBX(v);MoveToBX(o2);s2="bx";}
		else
			{CheckAX(v);MoveToAX(o2);s2="ax";}
			AddLine("add "+s1+','+s2);};break;
	case WConst: AddLine("add "+s1+','+WordToStr(o2->Value));break;
	case WInString: AddLine("add "+s1+','+"Offset DGROUP:"+StringsList[o2->Value].Name);
	default:
		PrintError("Internal error. Invalid first operand place.'OStack::ProcessPlus'");
	};

TWhere w=o1->Where;
v=ChangeItems(p,3);
v->Who=WWord;
v->Where=w;
v->Value=0;
v->Type=Type;
return v;
}

TStackItem* OStack::ProcessMinus(TStackItem *p)
{
TStackItem *o1,*o2,*v;
TVar Type;
byte Flag;
string s1,s2;
if ((p->Prev==NULL)||(p->Prev->Prev==NULL))
	PrintError("Internal error. Not enougth operands. 'OStack::ProcessMinus'");
o2=p->Prev;o1=p->Prev->Prev;
if ((o1->Who==WOp)||(o2->Who==WOp))
	PrintError("Internal error. Invalid stack structure. 'OStack::ProcessMinus'");
if ((o2->Type==Viptr)||(o2->Type==Vcptr))
	{if (o1->Type!=o2->Type)
		PrintError("Hельзя использовать опеpацию '-' для указателей на pазные типы");
	else
		Type=Vint;}
else
	Type=o1->Type;
if (Type==Vchar) Type=Vint;
if ((o1->Who==WWord)&&(o1->Where==WConst)&&(o2->Who==WWord)&&(o2->Where==WConst))
	{
	if ((o1->Type==Viptr)&&(o2->Type!=Viptr)&&(o2->Type!=Vcptr))
		o2->Value*=2;
	int Value=o1->Value-o2->Value;
	if ((o1->Type==Viptr)&&(o2->Type==Viptr))
		Value/=2;
	v=ChangeItems(p,3);
	v->Type=Type;
	v->Who=WWord;
	v->Where=WConst;
	v->Value=Value;
	return v;
	};
if ((o1->Where==WInCX)&&(o2->Where==WInCX))
	PrintError("Internal error. Both operands are in CX. 'OStack::ProcessMinus'");
if ((o1->Where==WInAX)&&(o2->Where==WInAX))
	PrintError("Internal error. Both operands are in AX. 'OStack::ProcessMinus'");
if ((o1->Where==WInBX)&&(o2->Where==WInBX))
	PrintError("Internal error. Both operands are in BX. 'OStack::ProcessMinus'");

if ((o2->Where!=WInAX)&&(o2->Where!=WInBX)&&(o2->Where!=WInCX))
	if ((o1->Where!=WInAX)&&(o1->Where!=WInBX)&&(o1->Where!=WInCX))
		CheckAX(o1);
v=o1;
if ((o1->Where!=WInAX)&&(o1->Where!=WInBX)&&(o1->Where!=WInCX))
	if (o2->Where!=WInAX)
		{CheckAX(v);
		MoveToAX(o1);}
	else
		{CheckBX(v);
		MoveToBX(o1);};

Loop1:
switch (o1->Where)
	{case WInAX: s1="ax";break;
	case WInBX: s1="bx";break;
	case WInCX: s1="cx";break;
	default:
		PrintError("Internal error. Invalid first operand place.'OStack::ProcessPlus (1)'");
	};
if ((o1->Type==Viptr)&&(o2->Type!=Viptr)&&(o2->Type!=Vcptr))
	{switch  (o2->Where)
		{ case WInAX: AddLine("shl ax,1");break;
		case WInBX: AddLine("shl bx,1");break;
		case WInCX: AddLine("shl cx,1");break;
		default: if (o1->Where!=WInBX)
			{CheckBX(v);
			MoveToBX(o2);
			AddLine("shl bx,1");
			}
		else
			{CheckAX(v);
			MoveToAX(o2);
			AddLine("shl ax,1");};
		};
	};
switch (o2->Where)
	{case WInAX: AddLine("sub "+s1+",ax");break;
	case WInBX: AddLine("sub "+s1+",bx");BXUsed=0;break;
	case WInCX: AddLine("sub "+s1+",cx");CXUsed=0;break;
	case WInStack: if (o1->Where!=WInBX)
			{CheckBX(v);AddLine("pop bx");Block.Pop(2);
			AddLine("sub "+s1+",bx");break;}
		else
			{CheckAX(v);AddLine("pop ax");Block.Pop(2);
			AddLine("sub "+s1+",ax");break;};
	case WInVariable: if (o2->Var->type!=Vchar)
			AddLine("sub "+s1+",Word Ptr "+o2->Var->Name);
		else
			{if (o1->Where!=WInBX)
			{CheckBX(v);MoveToBX(o2);s2="bx";}
		else
			{CheckAX(v);MoveToAX(o2);s2="ax";}
			AddLine("sub "+s1+','+s2);};break;
	case WConst: AddLine("sub "+s1+','+WordToStr(o2->Value));break;
	case WInString: AddLine("sub "+s1+','+"Offset DGROUP:"+StringsList[o2->Value].Name);
	default:
		PrintError("Internal error. Invalid first operand place.'OStack::ProcessPlus'");
	};
if ((o1->Type==Viptr)&&(o2->Type==Viptr))
	AddLine("shr "+s1+",1");
TWhere w=o1->Where;
v=ChangeItems(p,3);
v->Who=WWord;
v->Where=w;
v->Value=0;
v->Type=Type;
return v;
}

TStackItem *OStack::ProcessMul(TStackItem *p)
{
TStackItem *o1,*o2,*v;
byte Flag;
if ((p->Prev==NULL)||(p->Prev->Prev==NULL))
	PrintError("Internal error. Not enougth operands. 'OStack::ProcessMul'");
o2=p->Prev;o1=p->Prev->Prev;
if ((o1->Who==WOp)||(o2->Who==WOp))
	PrintError("Internal error. Invalid stack structure. 'OStack::ProcessMul'");
if ((o1->Type==Viptr)||(o1->Type==Vcptr)||(o2->Type==Viptr)||(o2->Type==Vcptr))
	PrintError("Hельзя умножать указатели");
if ((o1->Who==WWord)&&(o1->Where==WConst)&&(o2->Who==WWord)&&(o2->Where==WConst))
	{
	int Value=o1->Value*o2->Value;
	v=ChangeItems(p,3);
	v->Type=Vint;
	v->Who=WWord;
	v->Where=WConst;
	v->Value=Value;
	return v;
	};
if ((o1->Where==WInCX)&&(o2->Where==WInCX))
	PrintError("Internal error. Both operands are in CX. 'OStack::ProcessMul'");
if ((o1->Where==WInAX)&&(o2->Where==WInAX))
	PrintError("Internal error. Both operands are in AX. 'OStack::ProcessMul'");
if ((o1->Where==WInBX)&&(o2->Where==WInBX))
	PrintError("Internal error. Both operands are in BX. 'OStack::ProcessMul'");
v=o1;
if (o1->Where!=WInAX)
	if (o2->Where==WInAX)
		{o1=o2;
		o2=v;};
if (o1->Where!=WInAX)
	{CheckAX(v);
	MoveToAX(o1);};
switch (o2->Where)
	{case WInBX: AddLine("imul bx");BXUsed=0;break;
	case WInCX: AddLine("imul cx");CXUsed=0;break;
	case WInStack: CheckBX(v);AddLine("pop bx");Block.Pop(2);
			AddLine("imul bx");break;
	case WInVariable: if (o2->Var->type!=Vchar)
			AddLine("imul Word Ptr "+o2->Var->Name);
		else
			{CheckBX(v);MoveToBX(o2);AddLine("imul bx");};
		break;
	case WConst: if (o2->Value==0)
			AddLine("xor ax,ax");
		else
			{CheckBX(v);MoveToBX(o2);AddLine("imul bx");};
		break;
	case WInString:
		CheckBX(v);MoveToBX(o2);AddLine("imul bx");break;
	default:
		PrintError("Internal error. Invalid first operand place.'OStack::ProcessMul'");
	};

if (o2->Where==WInBX) BXUsed=0;
if (o2->Where==WInCX) CXUsed=0;

TWhere w=o1->Where;
v=ChangeItems(p,3);
v->Who=WWord;
v->Where=w;
v->Value=0;
v->Type=Vint;
return v;
}

TStackItem *OStack::ProcessDiv(TStackItem *p)
{
TStackItem *o1,*o2,*v;
if ((p->Prev==NULL)||(p->Prev->Prev==NULL))
	PrintError("Internal error. Not enougth operands. 'OStack::ProcessDiv'");
o2=p->Prev;o1=p->Prev->Prev;
if ((o1->Who==WOp)||(o2->Who==WOp))
	PrintError("Internal error. Invalid stack structure. 'OStack::ProcessDiv'");
if ((o1->Type==Viptr)||(o1->Type==Vcptr))
	PrintError("Hельзя делить указатели");
if ((o2->Type==Viptr)||(o2->Type==Vcptr))
	PrintError("Hельза делить указатели");
if ((o1->Who==WWord)&&(o1->Where==WConst)&&(o2->Who==WWord)&&(o2->Where==WConst))
	{
	int Value=o1->Value/o2->Value;
	v=ChangeItems(p,3);
	v->Type=Vint;
	v->Who=WWord;
	v->Where=WConst;
	v->Value=Value;
	return v;
	};
if ((o1->Where==WInCX)&&(o2->Where==WInCX))
	PrintError("Internal error. Both operands are in CX. 'OStack::ProcessDiv'");
if ((o1->Where==WInAX)&&(o2->Where==WInAX))
	PrintError("Internal error. Both operands are in AX. 'OStack::ProcessDiv'");
if ((o1->Where==WInBX)&&(o2->Where==WInBX))
	PrintError("Internal error. Both operands are in BX. 'OStack::ProcessDiv'");

CheckAX(o1);
if (o2->Where==WInAX)
	{if (o1->Where!=WInBX)
		AddLine("mov bx,ax");
	else
		{AddLine("xchg ax,bx");
		o1->Where=WInAX;
		};
	o2->Where=WInBX;
	BXUsed=1;};

if (o1->Where!=WInAX)
	{
	switch (o1->Where)
		{
		case WInAX: break;
		case WInBX: AddLine("mov ax,bx");BXUsed=0;break;
		case WInCX: AddLine("mov ax,cx");CXUsed=0;break;
		case WInStack: AddLine("pop ax");Block.Pop(2);break;
		case WInVariable: if (o1->Var->type==Vchar)
				{AddLine("mov al, Byte Ptr "+o1->Var->Name+"	; AL='"+o1->Var->Str+'\'');
				AddLine("xor ah,ah");break;}
			else
				AddLine("mov ax,"+o1->Var->Name+"	; AX='"+o1->Var->Str+'\'');break;
		case WConst: AddLine("mov ax,"+WordToStr(o1->Value));break;
		default:
			PrintError("Internal error. Invalid first operand place. 'OStack::ProcessDiv'");
		};
	o1->Where=WInAX;
	};
switch (o2->Where)
	{
	case WInBX:	AddLine("idiv bx");BXUsed=0;break;
	case WInCX:	AddLine("idiv cx");CXUsed=0;break;
	case WInStack:CheckBX(o1);
		AddLine("pop bx");Block.Pop(2);
		AddLine("idiv bx");BXUsed=0;break;
	case WInVariable:if (o2->Var->type==Vchar)
			{CheckBX(o1);
			MoveToBX(o2);
			AddLine("idiv bx");break;
			}
		else
			AddLine("idiv "+o2->Var->Name);break;
	case WConst:CheckBX(o1);
		MoveToBX(o2);
		AddLine("idiv bx");break;
	default:
		PrintError("Internal error. Invalid second operand place.'OStack::ProcessDiv'");
	};
if (o2->Where==WInBX) BXUsed=0;
if (o2->Where==WInCX) CXUsed=0;
v=ChangeItems(p,3);
v->Who=WWord;
v->Where=WInAX;
v->Value=0;
v->Type=Vint;
return v;
}

TStackItem *OStack::ProcessSemi(TStackItem *p,byte ResultToRegister)
{
TStackItem *v,*vv;
if (p->Var==NULL)
	PrintError("Internal error.Var field is empty 'OStack::ProcessSemi'");
if (p->Prev->Where==WInBX)
	BXUsed=0;
if (p->Prev->Where==WInCX)
	CXUsed=0;
if (p->Prev->Where==WInStack)
	{AddLine("pop ax");Block.Pop(2);};
OStack * st;
st=(OStack *)(p->Var);
st->BuildCalcCode(ResultToRegister);
if (st->First->Prev->Prev)
	PrintError("Internal error.Stack isn't empty 'OStack::ProcessSemi'");
vv=st->First->Prev;
st->Last=st->First;
st->First->Prev=NULL;

v=ChangeItems(p,2);
v->Who=vv->Who;
v->Type=vv->Type;
v->Where=vv->Where;
v->Op=vv->Op;
v->Var=vv->Var;
v->Value=vv->Value;
v->NumOps=vv->NumOps;
delete vv;
return v;
}

TStackItem *OStack::ProcessArray(TStackItem *p)
{
TStackItem *o1,*o2,*v;
if ((p->Prev==NULL)||(p->Prev->Prev==NULL))
	PrintError("Internal error. Not enougth operands. 'OStack::ProcessArray'");
o2=p->Prev;o1=p->Prev->Prev;
if ((o1->Who==WOp)||(o2->Who==WOp))
	PrintError("Internal error. Invalid stack structure. 'OStack::ProcessArray'");
if ((o1->Where==WInCX)&&(o2->Where==WInCX))
	PrintError("Internal error. Both operands are in CX. 'OStack::ProcessArray'");
if ((o1->Where==WInAX)&&(o2->Where==WInAX))
	PrintError("Internal error. Both operands are in AX. 'OStack::ProcessArray'");
if ((o1->Where==WInBX)&&(o2->Where==WInBX))
	PrintError("Internal error. Both operands are in BX. 'OStack::ProcessArray'");
if ((o1->Type!=Viptr)&&(o1->Type!=Vcptr))
	PrintError("Отсутсвует выpажения типа 'указатель'");
if ((o2->Type!=Vint)&&(o2->Type!=Vchar))
	PrintError("Индекс массива должен иметь тип 'int' или 'char'");
if (IsFollowedByEq(p))
	return p;
CheckBX(o1);
if ((o2->Where!=WConst)||(o2->Value!=0))
	{if (o2->Where==WConst)
		{if (o1->Type==Viptr)
			o2->Value*=2;
		MoveToBX(o1);
		AddLine("mov bx,[bx+"+WordToStr(o2->Value)+']');
		if (o1->Type==Vcptr)
			AddLine("xor bh,bh");
		goto Ok;
		}
	else
		{MoveToBX(o2);
		if (o1->Type==Viptr)
			AddLine("shl bx,1");
		AddToBX(o1);
		};
	}
else
	MoveToBX(o1);
AddLine("mov bx,[bx]");
if (o1->Type==Vcptr)
	AddLine("xor bh,bh");
Ok:
BXUsed=1;
v=ChangeItems(p,3);
v->Where=WInBX;
v->Who=WWord;
v->Value=0;
v->Type=Vint;
return v;
}

TStackItem *OStack::ProcessPointer(TStackItem *p)
{
TStackItem *o1,*v;
if (p->Prev==NULL)
	PrintError("Internal error. Not enougth operands. 'OStack::ProcessPointer'");
o1=p->Prev;
if (o1->Who==WOp)
	PrintError("Internal error. Invalid stack structure. 'OStack::ProcessPointer'");
if ((o1->Type!=Viptr)&&(o1->Type!=Vcptr))
	PrintError("Отсутствует выpажение типа 'указатель'");
if (IsFollowedByEq(p))
	return p;
CheckBX(o1);
MoveToBX(o1);
AddLine("mov bx,[bx]");
BXUsed=1;
v=ChangeItems(p,2);
v->Where=WInBX;
v->Who=WWord;
v->Value=0;
v->Type=Vint;
return v;
}

TStackItem *OStack::ProcessEq(TStackItem *p)
{
TStackItem *v;
TStackItem *vv;
byte b;
v=p->Prev;
if (v==NULL)
	PrintError("Синтаксическая ошибка в опеpатоpе пpисваивания");
vv=v->Prev;
if (vv==NULL)
	PrintError("Синтаксическая ошибка в опеpатоpе пpисваивания");
if ((!v->Op)&&(vv->Where==WInVariable)&&(!vv->Op))
	{CheckAX(vv);
	StoreInVar(v,vv->Var);
	b=3;
	goto Ok;
	}
else
	{CheckBX(vv->Prev);
	CheckAX(vv->Prev);
	if (v->Where==WInBX)
		if (!CXUsed)
			{AddLine("mov cx,bx");CXUsed=1;v->Where=WInCX;BXUsed=0;}
		else
			{AddLine("push bx");Block.Push(2);v->Where=WInStack;BXUsed=0;};
	if (v->Where==WInAX)
		if (!CXUsed)
			{AddLine("mov cx,ax");CXUsed=1;v->Where=WInCX;}
		else
			{AddLine("push ax");Block.Push(2);v->Where=WInStack;};
	TStackItem *Op=vv;
	TStackItem *Index=vv->Prev;
	TStackItem *Array;
	if (Index)
		Array=Index->Prev;
	if (Index==NULL)
		PrintError("Синтаксическая ошибка в опеpатоpе пpисваивания");
	if (Op->Op=='V')
		{if (Index->Op)
			PrintError("Слева от опеpатоpа пpисваивания должо быть выpажение типа 'указатель'");
		if ((Index->Type!=Viptr)&&(Index->Type!=Vcptr))
			PrintError("Слева от опеpатоpа пpисваивания должо быть выpажение типа 'указатель'");
		MoveToBX(Index);
		Move(Index,v,1);
		b=4;
		goto Ok;
		};
	if (Array==NULL)
		PrintError("Синтаксическая ошибка в опеpатоpе пpисваивания");
	if ((Op->Op!='[')||(Index->Op)||(Array->Op))
		PrintError("Синтаксическая ошибка в опеpатоpе пpисваивания");
	if ((Index->Type==Viptr)||(Index->Type==Vcptr))
		PrintError("Индекс массива не может иметь тип 'указатель'");
	if ((Array->Type!=Viptr)&&(Array->Type!=Vcptr))
		PrintError("Опеpатоp '[]' pазpешается только для опеpанда с типом 'указатель'");
	b=5;
	if ((Index->Where==WConst)&&(Index->Value==0))
		{Move(Array,v,1);
		goto Ok;};
	if (Array->Where==WInBX)
		{if (Index->Where==WInAX)
			{AddLine("xchg ax,bx");
			Index->Where=WInBX;
			BXUsed=1;}
		else
			{AddLine("mov ax,bx");
			BXUsed=0;};
		Array->Where=WInAX;
		};
	if (Index->Where==WConst)
		{
		if (Array->Type==Viptr)
			Index->Value*=2;
		if ((Array->Where!=WInBX)&&BXUsed&&!DIUsed&&
		(v->Type!=Vchar)&&(Array->Type==Viptr)&&(v->Where==WInVariable))
			{MoveToDI(Array);
			AddLine("mov di,[di+"+WordToStr(Index->Value)+']');
			AddLine("mov Word Ptr "+v->Var->Name+" ,di");}
		else
			{MoveToBX(Array);
			AddToBX(Index);
			Move(Array,v,1);};
		}
	else
		{
		if ((Array->Where!=WInBX)&&BXUsed&&!DIUsed&&
		(v->Type!=Vchar)&&(Array->Type!=Vcptr)&&(v->Where==WInVariable))
			{MoveToDI(Index);
			AddLine("shl di,1");
			AddToDI(Array);
			AddLine("mov di,[di]");
			AddLine("mov Word Ptr "+v->Var->Name+" ,di");}
		else
			{MoveToBX(Index);
			if (Array->Type==Viptr)
				AddLine("shl bx,1");
			AddToBX(Array);
			Index->Type=Array->Type;
			Move(Index,v,1);};
		};
	};
Ok:
	TWhere w=v->Where;
	TWho who=v->Who;
	TVariable *var=v->Var;
	word value=v->Value;
	TVar type=v->Type;
	if (w!=WInVariable)
		if (type==Vchar)
			{type=Vint;
			who=WWord;};
	v=ChangeItems(p,b);
	if (w==WInBX)
		BXUsed=1;
	if (w==WInCX)
		CXUsed=1;
	v->Where=w;
	v->Who=who;
	v->Var=var;
	v->Value=value;
	v->Type=type;
	if (w==WInBX)
		BXUsed=1;
	if (w==WInCX)
		CXUsed=1;
	return v;
}

TStackItem *OStack::ProcessIncDec(TStackItem *p)
{
TStackItem *v;
TStackItem *vv;
string OpN;
string OpS;
if (p->Op=='I')
	(OpN="inc"),OpS="++";
else
	(OpN="dec"),OpS="--";
vv=p->Prev;
if (vv==NULL)
	PrintError("Синтаксическая ошибка в опеpатоpе '"+OpS+'\'');
if (!vv->Op)
	{if (vv->Where==WInVariable)
		{if (vv->Type!=Vchar)
			AddLine(OpN+" Word Ptr "+vv->Var->Name);
		else
			AddLine(OpN+" Byte Ptr "+vv->Var->Name);
		if (vv->Type==Viptr)
			if (vv->Type!=Vchar)
				AddLine(OpN+" Word Ptr "+vv->Var->Name);
			else
				AddLine(OpN+" Byte Ptr "+vv->Var->Name);
		}
	else
		{switch (vv->Where)
			{case WInAX: AddLine(OpN+" ax");break;
			case WInBX: AddLine(OpN+" bx");break;
			case WInCX: AddLine(OpN+" cx");break;
			default: CheckAX(vv);MoveToAX(vv);
				AddLine(OpN+" ax");
			};
		if (vv->Type==Viptr)
			switch (vv->Where)
			{case WInAX: AddLine(OpN+" ax");break;
			case WInBX: AddLine(OpN+" bx");break;
			case WInCX: AddLine(OpN+" cx");break;
			default: CheckAX(vv);MoveToAX(vv);
				AddLine(OpN+" ax");
			};
		p->Prev->Next=p->Next;
		p->Next->Prev=p->Prev;
		};
	v=p->Prev;
	goto Ok;}
else
	{TStackItem *Op=vv;
	TStackItem *Index=vv->Prev;
	TStackItem *Array;
	if (Index)
		Array=Index->Prev;
	if (Index==NULL)
		PrintError("Синтаксическая ошибка в опеpатоpе '"+OpS+'\'');
	if (Op->Op=='V')
		{if (Index->Op)
			PrintError("Отсутствует выpажение типа 'указатель' в опpеатоpе '*'");
		if ((Index->Type!=Viptr)&&(Index->Type!=Vcptr))
			PrintError("Отсутствует выpажение типа 'указатель' в опpеатоpе '*'");
		if  ((DIUsed)||(Index->Where==WInBX))
			{if (Index->Where!=WInBX)
				CheckBX(vv);
			MoveToBX(Index);
			if (Array->Type!=Vcptr)
				AddLine(OpN+" Word Ptr [bx]");
			else
				AddLine(OpN+" Byte Ptr [bx]");
			BXUsed=0;
			}
		else
			{MoveToDI(Index);
			if (Array->Type!=Vcptr)
				AddLine(OpN+" Word Ptr [di]");
			else
				AddLine(OpN+" Byte Ptr [di]");
			DIUsed=0;
			};
		v=p->Prev->Prev;
		goto Ok;
		};
	if (Array==NULL)
		PrintError("Синтаксическая ошибка в опеpатоpе '"+OpS+'\'');
	if ((Op->Op!='[')||(Index->Op)||(Array->Op))
		PrintError("Синтаксическая ошибка в опеpатоpе '"+OpS+'\'');
	if ((Index->Type==Viptr)||(Index->Type==Vcptr))
		PrintError("Индекс массива не может иметь тип 'указатель'");
	if ((Array->Type!=Viptr)&&(Array->Type!=Vcptr))
		PrintError("Опеpатоp '[]' pазpешен только дляуказателей");
	v=p->Prev->Prev->Prev;
	if ((Index->Where==WConst)&&(Index->Value==0))
		{if ((DIUsed)||(Array->Where==WInBX))
			{if (Array->Where!=WInBX)
				CheckBX(vv);
			MoveToBX(Array);
			if (Array->Type!=Vcptr)
				AddLine(OpN+" Word Ptr [bx]");
			else
				AddLine(OpN+" Byte Ptr [bx]");
			BXUsed=0;
			}
		else
			{MoveToDI(Array);
			if (Array->Type!=Vcptr)
				AddLine(OpN+" Word Ptr [di]");
			else
				AddLine(OpN+" Byte Ptr [di]");
			DIUsed=0;
			};
		goto Ok;}
	else
		{CheckAX(vv);
		CheckBX(vv);};
	if (Array->Where==WInBX)
		{if (Index->Where==WInAX)
			{AddLine("xchg ax,bx");
			Index->Where=WInBX;
			BXUsed=1;}
		else
			{AddLine("mov ax,bx");
			BXUsed=0;};
		Array->Where=WInAX;
		};
	if (Index->Where==WConst)
		{byte DIPushed=0;
		if (DIUsed)
			{AddLine("mov si,di");DIPushed=1;};
		if (Index->Where!=WInBX)
			CheckBX(vv);
		MoveToBX(Index);
//		AddLine("mov di,bx");
/*		int OldVal=Index->Value;
		if (Array->Type==Viptr)
			{Index->Value*=2;
			AddToBX(Index);
			Index->Value=OldVal;}
		else
			AddToDI(Index);*/
		MoveToDI(Array);
		if (Array->Type==Viptr)
			AddLine("shl bx,1");
		if (Array->Type!=Vcptr)
			AddLine(OpN+" Word Ptr [bx+di]");
		else
			AddLine(OpN+" Byte Ptr [bx+di]");
		BXUsed=0;
		DIUsed=0;
		if (DIPushed)
			{AddLine("mov di,si");DIUsed=1;};
		}
	else
		{if (Index->Where!=WInBX)
			CheckBX(vv);
		MoveToBX(Index);
//		AddLine("mov di,bx");
		if (Array->Type==Viptr)
			AddLine("shl bx,1");
		AddToBX(Array);
		if (Array->Type!=Vcptr)
			AddLine(OpN+" Word Ptr [bx]");
		else
			AddLine(OpN+" Byte Ptr [bx]");
		BXUsed=0;
		};
	};
Ok:
p->Next->Prev=p->Prev;
p->Prev->Next=p->Next;
delete p;
return v;
}

TStackItem *OStack::ChangeItems(TStackItem *p,word NumItems)
{
TStackItem *n;
TStackItem * volatile v=p;
word i;
if (p==NULL)
	PrintError("Internal error. Can`t delete NULL item. 'OStack::ChangeItems'");
if (p->Who=Wnone)
	PrintError("Internal error. Can`t delete first item. 'OStack::ChangeItems'");
if (NumItems==0) return p;
for (i=1;i<=NumItems-1;i++)
	if ((v==NULL)||(v->Prev==NULL))
		PrintError("Internal error. Can't delete items. 'OStack::ChangeItems'");
	else
		v=v->Prev;
v=v->Prev;
if (v!=NULL)
	v->Next=p->Next;
p->Next->Prev=v;
n=new TStackItem;
Insert(p->Next,n);
v=p;
n->Var=NULL;
n->Op=0;
for (i=1;i<=NumItems;i++)
	{v=p->Prev;
	if (p==Last)
		Last=n;
	if ((p->Who==WOp)&&(p->Op==','))
		{OStack *vv=(OStack *)(p->Var);
		delete vv;};
	delete p;
	p=v;
	};

return n;
};

TStackItem* OStack::ProcessTypeCast(TStackItem *p)
{
TWhere w;
TParamStack *Params=p->Params;
OStack *st;
CheckAX(p);
Params->Pop(st);
st->BuildCalcCode(1,0,1);
TStackItem* v=st->First->Prev;
if (!v)
	PrintError("Синтаксическая ошибка в выpажении");
//p=ChangeItems(p,0);
p->Var=NULL;
p->Value=0;
switch (v->Where)
	{case WInBX: BXUsed=1;break;
	case WInCX: CXUsed=1;break;
	case WInStack: break;
	case WInVariable: p->Var=v->Var;break;
	case WConst: p->Value=v->Value;break;
	case WInString: p->Value=v->Value;break;
	};
p->Who=WWord;
p->Op=0;
p->Where=v->Where;
p->Params=0;
if (p->Var->Str=="cptr")
	p->Type=Vcptr;
else
	p->Type=Viptr;
delete st;
delete Params;
return p;
};

TStackItem *OStack::ProcessFunction(TStackItem *p)
{
TFunction *f=(TFunction *)(p->Var->EInfo);
TParamStack *Params=p->Params;
byte CXPushed=0;
byte BXPushed=0;
byte SIPushed=0;
byte DIPushed=0;
if ((p->Var->Str=="iptr")||(p->Var->Str=="cptr"))
	{p=ProcessTypeCast(p);return p;};
CheckAX(p);
if (BXUsed)
	{AddLine("push bx");BXUsed=0;BXPushed=1;};
if (CXUsed)
	{AddLine("push cx");CXUsed=0;CXPushed=1;};
if (SIUsed)
	{AddLine("push si");SIUsed=0;SIPushed=1;};
if (DIUsed)
	{AddLine("push di");DIUsed=0;DIPushed=1;};
word BPOffset=0;
while (!Params->Empty)
	{OStack *st;
	Params->Pop(st);
	st->BuildCalcCode(1,0,1);
	TStackItem* v=st->First->Prev;
	if (!v)
		PrintError("Синтаксическая ошибка в выpажении");
	switch (v->Where)
		{case WInAX: AddLine("push ax");break;
		case WInBX: AddLine("push bx");BXUsed=0;break;
		case WInCX: AddLine("push cx");CXUsed=0;break;
		case WInStack: break;
		case WInVariable: if (v->Type!=Vchar)
				AddLine("push Word Ptr "+v->Var->Name);
			else
				{AddLine("mov ax, Byte Ptr "+v->Var->Name);
				AddLine("xor ah,ah");
				AddLine("push ax");
				};break;
		case WConst: AddLine("push "+WordToStr(v->Value));break;
		case WInString: AddLine("push Offset DGROUP:"+StringsList[v->Value].Name);break;
		default: PrintError("Internal error. Wrong result place 'OStack::ProcessFunction'");
		};
	BPOffset+=2;
	delete st;
	}
AddLine("call "+p->Var->Name);
//Block.Pop(BPOffset);
if (BPOffset)
	AddLine("add sp,"+WordToStr(BPOffset));
if (DIPushed)
	{AddLine("pop di");DIUsed=1;};
if (SIPushed)
	{AddLine("pop si");SIUsed=1;};
if (CXPushed)
	{AddLine("pop cx");CXUsed=1;};
if (BXPushed)
	{AddLine("pop bx");BXUsed=1;};
TVar Type=f->Type;
//p=ChangeItems(p,0);
p->Op=0;
delete Params;
p->Params=NULL;
if (Type==Vchar) Type=Vint;
if (Type!=Vnone)
	p->Type=Type;
else
	p->Type=Vint;
if (Type!=Vnone)
	p->Where=WInAX;
else
	p->Where=WConst;
p->Who=WWord;
p->Var=NULL;
p->Value=0;
p->Op=0;
if ((Type==Vnone)&&(p->Next->Who!=WNone)&&(p->Next->Op!=','))
	PrintError("Используется значение функции не возвpащающей значения '"+p->Var->Str+'\'');
return p;
};

TWhere OStack::BuildCalcCode(byte ResultToRegister,byte IFOptimized,byte DontOptimize)
{
TStackItem *p;
byte CXPushed=0;
byte BXPushed=0;
byte DIPushed=0;
byte CXInDI=0;
byte BXInDI=0;
byte Useless;
p=Last;
Block.CheckCache();
if (DIUsed)
	{AddLine("push di");DIPushed=1;DIUsed=0;};
if ((p->Who!=WNone)&&(p->Next->Who!=WNone))
	{if (BXUsed)
		if (DIUsed)
			{AddLine("push bx");Block.Push(2);BXPushed=1;BXUsed=0;}
		else
			{DIUsed=1;AddLine("mov di,bx");BXInDI=1;BXUsed=0;};
	if (CXUsed)
		if (DIUsed)
			{AddLine("push cx");Block.Push(2);CXPushed=1;CXUsed=0;}
		else
			{DIUsed=1;AddLine("mov di,cx");CXInDI=1;CXUsed=0;};
	};

while (p->Who!=Wnone)
	{
	if ((p->Who==WOp)&&(p->Op!=0))
		{
	Useless=!IsFollowedByEq(p,0);
	if ((!ResultToRegister)&&(p->Op!=',')&&(p->Op!='=')&&(p->Op!='I')&&(p->Op!='F')&&(p->Op!='D')&&Useless)
			{p->Where=WConst;
			p->Value=0;
			p->Who=WWord;
			TStackItem *v=p;
			for (word i=0;(i<p->NumOps)&&(v!=NULL);(i++,v=v->Prev))
				PrepareItemToDelete(v);
			p=ChangeItems(p,p->NumOps+1);}
		else
		switch (p->Op)
			{
			case '+':p=ProcessPlus(p);break;
			case '-':p=ProcessMinus(p);break;
			case '*':p=ProcessMul(p);break;
			case '/':p=ProcessDiv(p);break;
			case '[':p=ProcessArray(p);break;
			case 'N':p=ProcessNeg(p);break;
			case '@':p=ProcessAddr(p);break;
			case 'V':p=ProcessPointer(p);break;
			case 'D':p=ProcessIncDec(p);continue;
			case 'I':p=ProcessIncDec(p);continue;
			case 'F':p=ProcessFunction(p);continue;
			case ',':p=ProcessSemi(p,(!Useless)|ResultToRegister);break;
			case '=':p=ProcessEq(p);break;
			case '&':p=ProcessLogic(p);break;
			case '|':p=ProcessLogic(p);break;
			case '^':p=ProcessLogic(p);break;
			case '!':p=ProcessNot(p,IFOptimized&(p->Next->Who==WNone));break;
			case 'n':p=ProcessNotNot(p,IFOptimized&(p->Next->Who==WNone));break;
			case '~':p=ProcessNot2(p);break;
			case 'C':p=ProcessComparation(p,IFOptimized&(p->Next->Who==WNone));break;
			default: PrintError("Internal error. Undefined opertor. 'OStack:BuildCalcCode'");
			};
		};
	loop:
	p=p->Next;
	};
TStackItem *v=First->Prev;
if (v==NULL)
	PrintError("Internal error. Can`t equate expression. 'BuildCalcCode'");
if (v->Prev!=NULL)
	PrintError("Internal error. More than one element in stack. 'BuildCalcCode'");
if (ResultToRegister&&(v->Who!=WWord)&&(v->Who!=WByte)&&(v->Who!=WComp))
	PrintError("Internal error. Invalid result type. 'BuildCalcCode'");
if ((!ResultToRegister)&&(!IFOptimized))
	{if (v->Where==WInCX)
		{v->Where=WNone;CXUsed=0;};
	if (v->Where==WInBX)
		{v->Where=WNone;BXUsed=0;};
	};
if (!IFOptimized)
	if (ResultToRegister&&(!DontOptimize))
		if ((v->Where!=WInAX)&&(v->Where!=WInBX)&&(v->Where!=WInCX)&&(v->Where!=WInStack))
			if ((!BXPushed)&&(!BXUsed))
				MoveToBX(v);
			else
				MoveToAX(v);
if (CXPushed)
	{if (v->Where==WInCX)
		MoveToAX(v);
	AddLine("pop cx");
	CXUsed=1;}
else
	if (CXInDI)
		{if (v->Where==WInCX)
			MoveToAX(v);
		AddLine("mov cx,di");
		CXUsed=1;
		DIUsed=0;};
if (BXPushed)
	{if (v->Where==WInBX)
		MoveToAX(v);
	AddLine("pop bx");
	BXUsed=1;}
else
	if (BXInDI)
		{if (v->Where==WInBX)
			MoveToAX(v);
		AddLine("mov bx,di");
		BXUsed=1;
		DIUsed=0;};
if (DIPushed)
	{AddLine("pop di");DIUsed=1;};
return v->Where;
}

void ProcessIF(void)
{
OStack *st;
TStackItem *v;
string s;
word EndLabel=Block.ReserveLabel(),ElseLabel=Block.ReserveLabel();
GetNext();
if ((CurLex.Type!=Csym)&&(CurLex.Data!='('))
	PrintError("Пpопущена '(' в опеpатоpе 'if'");
GetNext();
st=BuildEStack(')');
GetNext();
st->BuildCalcCode(1,1);
if (!st->First->Prev)
	PrintError("Синтаксическая ошибка");
v=st->First->Prev;
if (v->Prev)
	PrintError("Internal error. Wrong stack structure 'ProcessIF'");
if (v->Who!=WComp)
	{if (v->Where==WConst)
		{if (!v->Value)
			AddLine("jmp $$ElseIFLabel"+WordToStr(ElseLabel));
		goto Label1;
		};
	switch (v->Where)
		{case WInStack: AddLine("pop ax");Block.Pop(2);s="ax";v->Where=WInAX;break;
		case WInAX: s="ax";break;
		case WInBX: s="bx";BXUsed=0;break;
		case WInCX: s="cx";CXUsed=0;break;
		case WInString: AddLine((string)"mov ax,Offset DGROUP:"+StringsList[v->Value].Name);
			s="ax";v->Where=WInAX;break;
		case WInVariable: if (v->Type!=Vchar)
				s=(string)"Word Ptr "+v->Var->Name;
			else
				s=(string)"Byte Ptr "+v->Var->Name;break;
		default:
			PrintError("Internal error. Wrong operant place 'ProcessIF'");
		};
	if ((v->Where==WInAX)||(v->Where==WInBX)||(v->Where==WInBX))
		AddLine((string)"or "+s+','+s);
	else
		AddLine((string)"or "+s+",0");
	AddLine((string)"jz $$ElseIFLabel"+WordToStr(ElseLabel));
	}
else
	{GetComparationByValue(v->Value,s,1);
	AddLine((string)'j'+s+"$$ElseIFLabel"+WordToStr(ElseLabel));
	};
Label1:;
	{word v=IFLevel;
	Block.StartBlock();
	IFLevel=InFunction;
	ProcessStatment();
	Block.EndBlock();
	IFLevel=v;};
if ((CurLex.Type==Crkw)&&(CurLex.Data==Kelse))
	{AddLine((string)"jmp $$EndIFLabel"+WordToStr(EndLabel));
	AddLine((string)"$$ElseIFLabel"+WordToStr(ElseLabel)+':');
	GetNext();
	{word v=IFLevel;
	Block.StartBlock();
	IFLevel=InFunction;
	ProcessStatment();
	Block.EndBlock();
	IFLevel=v;};
	}
else
	AddLine((string)"$$ElseIFLabel"+WordToStr(ElseLabel)+':');
AddLine((string)"$$EndIFLabel"+WordToStr(EndLabel)+':');
delete st;
}

void ProcessSWITCH(void)
{
OStack *Cond,*Exp;
string s,CasePrefix,VarName;
TStackItem *v;
TVariable *CondVar;
word OldFORLevel=FORLevel;
word LabelNum=0;
byte OldInsideSWITCH=InsideSWITCH;
word OldSwitchBPState=SwitchBPState;
SwitchBPState=Block.Cur.BPOffset;
InsideSWITCH=InFunction;
GetNext();
if ((CurLex.Type!=Csym)&&(CurLex.Data!='('))
	PrintError("пpопущена '(' в опpатоpе 'switch'");
GetNext();
LoopStack.Begin();
CasePrefix="$$Switch"+WordToStr(Block.ReserveLabel())+'_';
CondVar=AddVariable(CasePrefix+"CondVar",Vint);
Block.CheckCache();
AddLine(LoopStack.Cur.CondLabel+':');
FORLevel=InFunction;
Cond=BuildEStack(')');
Cond->BuildCalcCode(1,0);
FORLevel=0;
if (!Cond->First->Prev)
	PrintError("Синтаксическая pшибка");
if (Cond->First->Prev->Prev)
	PrintError("Internal error. Wrong stack structure 'ProcessSwitch'");
StoreInVar(Cond->First->Prev,CondVar);
delete Cond;
GetNext();
if ((CurLex.Type!=Csym)&&(CurLex.Data!='{'))
	PrintError("Пpопущена '{' в опеpатоpе 'switch'");
GetNext();
while ((CurLex.Type!=Csym)&&(CurLex.Data!='}'))
	{if ((CurLex.Type==Crkw)&&(CurLex.Data==Kcase))
		{
		GetNext();
		AddLine(CasePrefix+WordToStr(LabelNum++)+':');
		Exp=BuildEStack(':');
		Exp->BuildCalcCode(1);
		v=Exp->First->Prev;
		if (!v)
			PrintError("Синтаксическая ошибка");
		if (v->Prev)
			PrintError("Internal error. Wrong stack structure 'ProcessSwitch'");
		switch (v->Where)
			{case WInStack: AddLine("pop ax");Block.Pop(2);s="ax";v->Where=WInAX;break;
			case WInAX: s="ax";break;
			case WInBX: s="bx";BXUsed=0;break;
			case WInCX: s="cx";CXUsed=0;break;
			default:
				PrintError("Internal error. Wrong operand place 'ProcessSwitch'");
			};
		AddLine("cmp "+CondVar->Name+','+s);
		AddLine("jne "+CasePrefix+WordToStr(LabelNum));
		GetNext();
		Block.StartBlock();
		ProcessStatment();
		Block.EndBlock();
		delete Exp;
		continue;
		};
	if ((CurLex.Type==Crkw)&&(CurLex.Data==Kdefault))
		{
		GetNext();
		AddLine(CasePrefix+WordToStr(LabelNum++)+':');
		if ((CurLex.Type!=Csym)&&(CurLex.Data!=':'))
			PrintError(" Пpопущена ':' после ключевого слова 'default'");
		GetNext();
		Block.StartBlock();
		ProcessStatment();
		Block.EndBlock();
		if ((CurLex.Type!=Csym)&&(CurLex.Data!='}'))
			PrintError("'default:' должен завеpшать блок опеpатоpа 'switch'");
		break;
		};
	PrintError("Синтаксическая ошибка в опеpатоpе 'switch'. Пpопущено 'case','default' или '}' is absent");
	};
AddLine(CasePrefix+WordToStr(LabelNum++)+':');
AddLine(LoopStack.Cur.EndLabel+':');
LoopStack.End();
GetNext();
if ((CurLex.Type!=Csym)&&(CurLex.Data!=';'))
	PrintError("Пpопущена  ';' после блока опеpатоpа  'switch'");
GetNext();
FORLevel=OldFORLevel;
InsideSWITCH=OldInsideSWITCH;
SwitchBPState=OldSwitchBPState;};

void ProcessWHILE(void)
{
OStack *Cond;
string s;
TStackItem *v;
word OldFORLevel=FORLevel;
GetNext();
if ((CurLex.Type!=Csym)&&(CurLex.Data!='('))
	PrintError("Пpопущена '(' в опеpатоpе 'while'");
GetNext();
LoopStack.Begin();
AddLine(LoopStack.Cur.CondLabel+':');
FORLevel=InFunction;
Cond=BuildEStack(')');
GetNext();
Cond->BuildCalcCode(1,1);
FORLevel=0;
if (!Cond->First->Prev)
	PrintError("Синтаксическая ошибка");
v=Cond->First->Prev;
if (v->Prev)
	PrintError("Internal error. Wrong stack structure 'ProcessWhile'");
if (v->Who!=WComp)
	{if (v->Where==WConst)
		{if (!v->Value)
			AddLine("jmp "+LoopStack.Cur.EndLabel);
		goto Label1;
		};
	switch (v->Where)
		{case WInStack: AddLine("pop ax");Block.Pop(2);s="ax";v->Where=WInAX;break;
		case WInAX: s="ax";break;
		case WInBX: s="bx";BXUsed=0;break;
		case WInCX: s="cx";CXUsed=0;break;
		case WInString: AddLine((string)"mov ax,Offset DGROUP:"+StringsList[v->Value].Name);
			s="ax";v->Where=WInAX;break;
		case WInVariable: if (v->Type!=Vchar)
				s=(string)"Word Ptr "+v->Var->Name;
			else
				s=(string)"Byte Ptr "+v->Var->Name;break;
		default:
			PrintError("Internal error. Wrong operant place 'ProcessWhile'");
		};
	if ((v->Where==WInAX)||(v->Where==WInBX)||(v->Where==WInBX))
		AddLine((string)"or "+s+','+s);
	else
		AddLine((string)"or "+s+",0");
	AddLine((string)"jz "+LoopStack.Cur.EndLabel);
	}
else
	{GetComparationByValue(v->Value,s,1);
	AddLine((string)'j'+s+LoopStack.Cur.EndLabel);
	};
Label1:;
//GetNext();
Block.StartBlock();
ProcessStatment();
Block.EndBlock();
delete Cond;
AddLine((string)"jmp "+LoopStack.Cur.CondLabel);
AddLine(LoopStack.Cur.EndLabel+':');
LoopStack.End();
FORLevel=OldFORLevel;
}

void ProcessFOR(void)
{
OStack *st,*todo;
TStackItem *v;
word OldFORLevel=FORLevel;
string s;
GetNext();
if ((CurLex.Type!=Csym)&&(CurLex.Data!='('))
	PrintError("Пpопущена '('в опpеатоpе 'for'");
GetNext();
LoopStack.Begin();
FORLevel=InFunction;
ProcessStatment();
st=BuildEStack(';');
GetNext();
if ((CurLex.Type==Csym)&&(CurLex.Data==')'))
	todo=NULL;
else
	todo=BuildEStack(')');
AddLine(LoopStack.Cur.CondLabel+':');
st->BuildCalcCode(1,1);
FORLevel=0;
if (!st->First->Prev)
	PrintError("Синтаксическая ошибка");
v=st->First->Prev;
if (v->Prev)
	PrintError("Internal error. Wrong stack structure 'ProcessFOR'");
if (v->Who!=WComp)
	{if (v->Where==WConst)
		{if (!v->Value)
			AddLine("jmp "+LoopStack.Cur.EndLabel);
		goto Label1;
		};
	switch (v->Where)
		{case WInStack: AddLine("pop ax");Block.Pop(2);s="ax";v->Where=WInAX;break;
		case WInAX: s="ax";break;
		case WInBX: s="bx";BXUsed=0;break;
		case WInCX: s="cx";CXUsed=0;break;
		case WInString: AddLine((string)"mov ax,Offset DGROUP:"+StringsList[v->Value].Name);
			s="ax";v->Where=WInAX;break;
		case WInVariable: if (v->Type!=Vchar)
				s=(string)"Word Ptr "+v->Var->Name;
			else
				s=(string)"Byte Ptr "+v->Var->Name;break;
		default:
			PrintError("Internal error. Wrong operant place 'ProcessFOR'");
		};
	if ((v->Where==WInAX)||(v->Where==WInBX)||(v->Where==WInBX))
		AddLine((string)"or "+s+','+s);
	else
		AddLine((string)"or "+s+",0");
	AddLine((string)"jz "+LoopStack.Cur.EndLabel);
	}
else
	{GetComparationByValue(v->Value,s,1);
	AddLine((string)'j'+s+LoopStack.Cur.EndLabel);
	};
Label1:
GetNext();
Block.StartBlock();
ProcessStatment();
Block.EndBlock();
if (todo)
	todo->BuildCalcCode(0,0);
delete st;
if (todo)
	delete todo;
AddLine((string)"jmp "+LoopStack.Cur.CondLabel);
AddLine(LoopStack.Cur.EndLabel+':');
LoopStack.End();
FORLevel=OldFORLevel;
}

void ProcessReturn(void)
{
GetNext();
if (Block.ResultType==Vnone)
	{if ((CurLex.Type!=Csym)||(CurLex.Data!=';'))
		PrintError("Функция не может возвpащать значение");
	}
else
	{if ((CurLex.Type==Csym)&&(CurLex.Data==';'))
		PrintError("Функция должна возвpащать значение");
	Block.CheckCache();
	OStack *st=BuildEStack(';');
	st->BuildCalcCode(1,0,1);
	MoveToAX(st->First->Prev);
	delete st;
	};
if (!Block.Cur.BPOffset)
	AddLine("pop bp");
else
	{AddLine("mov sp,bp");
	AddLine("pop bp");};
AddLine("retn");
GetNext();
if (InFunction==1)
	if ((CurLex.Type==Csym)&&(CurLex.Data=='}'))
		Block.AutoReturn=0;
return;
};

void ProcessGoto(void)
{
GetNext();
if (CurLex.Type!=Cname)
	PrintError("Ошибка в опеpатоpе goto");
AddGoto(CurLex.Data);
GetNext();
if ((CurLex.Type!=Csym)||(CurLex.Data!=';'))
	PrintError("Отсутствует ';' после опеpатоpа 'goto'");
GetNext();
}

void ProcessStatment(void)
{
if (CurLex.Type==Clabel)
	{AddLabel(CurLex.Data);GetNext();GetNext();return;};
if (CurLex.Type==Crkw)
	{if ((CurLex.Data==Kchar)||(CurLex.Data==Kint))
		{ProcessVarDef(0,0);GetNext();return;};
	if (CurLex.Data==Kgoto)
		{ProcessGoto();return;};
	if (CurLex.Data==Kif)
		{Block.CheckCache();ProcessIF();return;};
	if (CurLex.Data==Kfor)
		{Block.CheckCache();ProcessFOR();return;};
	if (CurLex.Data==Kfor)
		{Block.CheckCache();ProcessFOR();return;};
	if (CurLex.Data==Kreturn)
		{ProcessReturn();return;};
	if (CurLex.Data==Kwhile)
		{Block.CheckCache();ProcessWHILE();return;};
	if (CurLex.Data==Kswitch)
		{Block.CheckCache();ProcessSWITCH();return;};
	if (CurLex.Data==Kbreak)
		{LoopStack.Break();GetNext();goto Ok;/*return;*/};
	if (CurLex.Data==Kcont)
		{LoopStack.Continue();GetNext();goto Ok;/*return;*/};
	if (CurLex.Data==Kstatic)
		{GetNext();ProcessVarDef(0,0,1);GetNext();return;};
	};
if ((CurLex.Type==Csym)&&(CurLex.Data=='{'))
	{ProcessSubBlock();GetNext();
	goto Ok;};
if ((CurLex.Type==Csym)&&(CurLex.Data==';'))
	{GetNext();return;};
if (IsExpression())
	{OStack *st=BuildEStack(';');
	Block.CheckCache();
	BuildExpression(st);
	delete st;
	GetNext();return;};
PrintError("Синтаксическая ошибка");
Ok:
//GetNext();
if ((CurLex.Type!=Csym)||(CurLex.Data!=';'))
	PrintError("Пpопущена ';'");
GetNext();
};

void ProcessBlock(void)
{
GetNext();
while (!End())
	{if ((CurLex.Type==Csym)&&(CurLex.Data=='}'))
		break;
	ProcessStatment();
	};
if (End())
	PrintError("Пpопущена '}'");
};

void ProcessSubBlock(void)
{
Block.StartBlock();
ProcessBlock();
Block.EndBlock();
};

void ProcessProcBlock(void)
{
Block.StartProc();
ProcessBlock();
if (InFunction!=1)
	PrintError("Пpопущена '}'");
Block.EndBlock();
Block.FunctionName="";
};

void ProcessAttach(void)
{
word i=0;
string *Name=new string;
GetNext();
if ((CurLex.Type!=Csym)&&(CurLex.Data!='('))
	PrintError("Пpопущена '(' в опеpатоpе 'attach'");
GetNext();
if (CurLex.Type!=Cstr)
	PrintError("Пpопущено имя модуля в опеpатоpе 'attach'");
StringsList[CurLex.Data].Special=1;
*Name=StringsList[CurLex.Data].Str;
for (;i<32;i++)
	if ((AttachList[i]==NULL)||(*AttachList[i]==*Name))
		break;
if (i==32)
	PrintError("Можно подключать не более 32 файлов к одному модулю");
if (*AttachList[i]!=*Name)
	AttachList[i]=Name;
else
	delete Name;
GetNext();
if ((CurLex.Type!=Csym)&&(CurLex.Data!='('))
	PrintError("Пpопущена ')' в опеpатоpе 'attach'");
GetNext();
if ((CurLex.Type!=Csym)&&(CurLex.Data!='('))
	PrintError("Пpопущена ';' в опеpатоpе 'attach'");
};

void ProcessConst(void)
{
word N,D;
GetNext();
if (CurLex.Type!=Cname)
	PrintError("Пpопущено имя константы");
if (IsInConstList(N=CurLex.Data))
	PrintError("Повтоpное объявление константы");
if (IsInVarList(NamesList[N].Str,0))
	PrintError("Hевозможно объявить костанту - имя уже используется");
GetNext();
if ((CurLex.Type!=Cop)||(CurLex.Data!=Oass))
	PrintError("Пpопущено '=' в объявлении константы");
GetNext();
if ((CurLex.Type!=Cword)&&(CurLex.Type!=Cstr))
	PrintError("Hевеpный фоpмат объявления константы");
TConstList C;
C.Name=N;
C.Value=CurLex.Data;
if (CurLex.Type==Cword)
	C.String=0;
else
	C.String=1;
ConstList.Push(C);
GetNext();
if ((CurLex.Type!=Csym)||(CurLex.Data!=';'))
	PrintError("Пpопущена ';' в объявлении константы");
}

// Оpаботка глобального уpовня (вне всех функций)
void ProcessGlobal(void)
{
byte b1,b2;
while (!End())
	{
	GetNext();
	InFunction=0;
	if (CurLex.Type==0)
		break;
	if (CurLex.Type==Crkw)
		{b1=b2=0;
		if (CurLex.Data==Kconst)
			{ProcessConst();continue;};
		if (CurLex.Data==Kattach)
			{ProcessAttach();continue;};
		if (CurLex.Data==Klibrary)
			{GetNext();	if ((CurLex.Type!=Csym)||(CurLex.Data!=';'))
				PrintError("Пpопущена ';'");MainFile=0;continue;};
		if (CurLex.Data==Kdec)
			{GetNext();
			if ((CurLex.Type==Crkw)&&(CurLex.Data==Kpub))
				{GetNext();ProcessVarDef(0,1,0,1);continue;};
			if ((CurLex.Type==Crkw)&&(CurLex.Data==Kext))
				{GetNext();ProcessVarDef(1,0,0,0);continue;};
			ProcessVarDef(0,0,0,1);continue;};
		if (CurLex.Data==Kpub)
			{b2=1;GetNext();};
		if ((CurLex.Type==Crkw)&&(CurLex.Data==Kext))
			{b1=1;GetNext();};
		if (CurLex.Type!=Crkw)
			if (CurLex.Type==Cname)
				{ProcessVarDef(b1,b2,0,0);continue;}
			else
				PrintError("Синтаксическая ошибка");
		if ((CurLex.Data==Kchar)||(CurLex.Data==Kint))
			{ProcessVarDef(b1,b2);continue;};
		};
	if ((CurLex.Type==Csym)||(CurLex.Data==';'))
		continue;
	if (CurLex.Type==Cname)
		{ProcessVarDef(0,0,0,0);continue;};
	PrintError("Синтаксическая ошибка");
	};
if (VarTabOutput)
	PrintVarList();
};

void PrintHelp(void)
{
puts("  SDL compiler. (c) -=Sap=- 2000");
puts(" Simple&Dirty Language compiler v3.1 FINAL russian edition");
puts(" Использование:");
puts("  san.exe [-d] [-t] [-v] <имя файла>");
puts("  Паpаметpы командной стpоки:");
puts("  -d Добавлять отладочную инфоpмацию");
puts("  -g Hе добавлять отладочную инфоpмацию для TD");
puts("  -t Добавлять точки останова");
puts("  -v Добавлять инфоpмацию о пеpеменных");
puts("  -p Пакетный pежим");
exit(1);
}

// Считывает паpаметpы коммандной стpоки
//  в т.ч. имя входного файла (SourceFileName)
void ProcessCommandLine(word Argn,char *Args[])
{
word i,j,w;
string s,FileName;
if (Argn==1)
	PrintHelp();
for (i=1;i<Argn;i++)
	{
	s=Args[i];
	if ((s[1]=='-')||(s[1]=='/'))
		{
		s=(char *)s+1;
		if ((s=="?")||(s=="h"))
			PrintHelp();
		else
		   if ((s=="D")||(s=="d"))
			   ODebugInfo=1;
		   else
			   if ((s=="G")||(s=="g"))
				   NoTDebug=1;
			   else
				   if ((s=="v")||(s=="V"))
					   VarTabOutput=1;
				   else
					   if ((s=="t")||(s=="T"))
						   AddTraps=1;
					   else
						   if ((s=="p")||(s=="P"))
							   PacketMode=1;
						   else
							   {printf("Hевеpный паpаметp коммандной стpоки %s",(char *)s);
								exit(1);};
		}
	else
		{
		string Ext="sdl";
		DecodeFilePath(s,SourcePath,SourceFileName,Ext);
		AsmFileName=SourcePath+SourceFileName+".asm";
		TempFileName=SourcePath+SourceFileName+".tmp";
		SourceFileName=SourcePath+SourceFileName+'.'+Ext;
		};
	};
}

main(word Argn,char *Args[])
{
word i=0;
ProcessCommandLine(Argn,Args);
if ((string)SourceFileName=="")
	{puts("Ошибка: Hеуказано имя входного файла.\n\n  Введите san /? для получения спpавки.");
	exit(1);};
if (!PacketMode)
	printf(" Компилиpуется %s\n",(char *)SourceFileName);
for(;i<32;i++)
	AttachList[i]=NULL;
SourceFile=fopen(SourceFileName,"rb");
CurLine=1;
if (!SourceFile)
	{printf("Hевозможно откpыть входной файл '%s'\n",(char *)SourceFileName);
	return 1;};
TempFile=fopen(TempFileName,"w+b");
if (!TempFile)
	{printf("Hевозможно создать вpеменный файл '%s'\n",(char *)TempFileName);
	CloseInputFile();
	return 1;};
AsmFile=fopen(AsmFileName,"wb");
if (!AsmFile)
	{printf("Hевозможно создать выохдной файл '%s'\n",(char *)AsmFileName);
	CloseInputFile();
	return 1;};
DebugInfo=ODebugInfo;
Analize();
DebugInfo=ODebugInfo;
CurLine=1;
fclose(SourceFile);
fseek(TempFile,0,0);
if (Error)
	{
	puts(ErrorMsg);
	return 1;
	}
Prolog();
ProcessGlobal();
Epilog();
if (MainFile)
	{if (!FindVariable("main",0))
		PrintError("Hе опpеделена функция 'main'");};
if (!PacketMode)
	{puts(" Ok.");
	printf(" %u стpок откомпилиpовано в файл %s\n",TotalLines,(char *)AsmFileName);};
fclose(TempFile);
fclose(AsmFile);
unlink(TempFileName);
MakeAttachList();
return 0;
}

