{
    The Personal GNU Text Editor.
    Copyright (C) Sandul Yura Valentinovich.
    (R) Monday, 3 March 2003 year.
    All rights reserved.
    This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option) any
later version.
    This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
    You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc., 675
Mass Ave, Cambridge, MA 02139, USA.
}
Program GNUText;
Uses Crt,Dos;
Const
    MaxLines          = 10240;
    MaxWhiles         = 256;
    MaxFroms          = 256;
    MaxFiles          = 256;
    MaxDefFnS         = 256;
    MaxDefFnSArgs     = 64;
    MaxVars           = 768;
    MaxGoSubS         = 256;
    MaxANSIParameters = 4;
    TextLinesCount    = 32768;
Type
   BASICLine = Record
    Line        : String;
    LineNumber  : Word;
   end;
   WhileLoop = Record
    StartLine   : Word;
    EndLine     : Word;
    Conditional : String;
    IsFree      : Boolean;
   end;
   FromLoop = Record
    VarName     : String;
    StartLine   : Word;
    EndLine     : Word;
    BeginValue  : LongInt;
    EndValue    : LongInt;
    IsFree      : Boolean;
   end;
   BASICFile = Record
    FileMode    : Boolean;
    IsUse       : Boolean;
    WorkFile    : Text;
   end;
   VariableData = Record
    VarName     : String;
    StringValue : String;
    NumberValue : Real;
    ValueType   : Boolean;
   end;
Var
  Lines            : Array[1..MaxLines] Of BASICLine;
  BASICLinesCount  : Word;
  TextLines        : Array[1..TextLinesCount] Of String;
  StatusLine       : String;
  GNUTextFileName  : String;
  CursorRow        : LongInt;
  CursorColumn     : LongInt;
  TextPosition     : LongInt;
  LinePosition     : LongInt;
  Key              : Char;
  Whiles           : Array[1..MaxWhiles] Of WhileLoop;
  Froms            : Array[1..MaxFroms] Of FromLoop;
  Files            : Array[1..MaxFiles] Of BASICFile;
  GoSubS           : Array[1..MaxGoSubS] Of Word;
  GoSubSCount      : Word;
  Vars             : Array[1..MaxVars] Of VariableData;
  VarsCount        : Word;
  DefFnS           : Array[1..MaxDefFnS] Of String;
  DefFnSArgs       : Array[1..MaxDefFnS] Of Array[1..MaxDefFnSArgs] Of VariableData;
  DefFnSArgsCount  : Array[1..MaxDefFnS] Of Word;
  DefFnSCount      : Word;
  CurrentDefFn     : Word;
  DefFnMode        : Boolean;
  CurrentLine      : Word;
  RunMode          : Boolean;
  TraceMode        : Boolean;
  NumStr           : Boolean;
  IsSystem         : Boolean;
  Error            : String;
  Prompt           : String;
  Parameters       : Array[1..MaxANSIParameters] Of Byte;
  ParametersCount  : Byte;
  ANSICursorColumn : Byte;
  ANSICursorRow    : Byte;
  ANSICursorSaved  : Boolean;
  Mode             : Byte;
  NumberLine       : String;
  Number           : Word;
Function InMeaning(Var Line : String) : String; ForWard;
Function ParseInMeaning(Var Line : String) : String; ForWard;
Function IsLeapYear(Year : Word) : Boolean;
Begin
 IsLeapYear:=((Year Div 4)*4)=Year;
end;
Function MonthDay(Year : Word; Month : Byte) : Byte;
Begin
 Case Month Of
  1:  MonthDay:=31;
  2:  MonthDay:=28+Ord(IsLeapYear(Year));
  3:  MonthDay:=31;
  4:  MonthDay:=30;
  5:  MonthDay:=31;
  6:  MonthDay:=30;
  7:  MonthDay:=31;
  8:  MonthDay:=31;
  9:  MonthDay:=30;
  10: MonthDay:=31;
  11: MonthDay:=30;
  12: MonthDay:=31;
 end;
end;
Function MonthDays(Year : Word; Month : Byte) : Word;
Begin
 Case Month Of
  1:  MonthDays:=0;
  2:  MonthDays:=31;
  3:  MonthDays:=59+Ord(IsLeapYear(Year));
  4:  MonthDays:=90+Ord(IsLeapYear(Year));
  5:  MonthDays:=120+Ord(IsLeapYear(Year));
  6:  MonthDays:=151+Ord(IsLeapYear(Year));
  7:  MonthDays:=181+Ord(IsLeapYear(Year));
  8:  MonthDays:=212+Ord(IsLeapYear(Year));
  9:  MonthDays:=243+Ord(IsLeapYear(Year));
  10: MonthDays:=273+Ord(IsLeapYear(Year));
  11: MonthDays:=304+Ord(IsLeapYear(Year));
  12: MonthDays:=334+Ord(IsLeapYear(Year));
 end;
end;
Function DaysCount(Year : Word; Month,Day : Byte) : LongInt;
Begin
 DaysCount:=(LongInt(Year)*365)+(Year Div 4)+(Year Div 100)+MonthDays(Year,Month)+Day;
end;
Function DayOfWeek(Year : Word; Month,Day : Byte) : Byte;
Begin
 Case DaysCount(Year,Month,Day)-((DaysCount(Year,Month,Day) Div 7)*7) Of
  0: DayOfWeek:=6;
  1: DayOfWeek:=7;
  2: DayOfWeek:=1;
  3: DayOfWeek:=2;
  4: DayOfWeek:=3;
  5: DayOfWeek:=4;
  6: DayOfWeek:=5;
 end;
end;
Function CRC32(Line : String) : LongInt;
Var
  Crc32Table : Array[0..255] Of LongInt;
  CrcValue   : LongInt;
  Count      : Byte;
  Index      : Byte;
Begin
 For Index:=0 To 255 Do
 Begin
  CRCValue:=Index;
  For Count:=1 To 8 Do If Odd(CRCValue) Then CRCValue:=(CRCValue Div 2) XOr LongInt($EDB88320) Else CRCValue:=CRCValue Div 2;
  Crc32Table[Index]:=CRCValue;
 end;
 CRCValue:=LongInt($FFFFFFFF);
 For Index:=1 To Length(Line) Do CRCValue:=Crc32Table[Byte(CRCValue) XOr Ord(Line[Index])] XOr (CRCValue Div $100);
 CRC32:=CRCValue;
end;
Procedure WriteANSILine(Line : String);
 Procedure WriteSymbol(Symbol : Char);
 Var
   Index        : Byte;
   ErrorInteger : Integer;
  Procedure ClearParameters;
  Var
    ParameterIndex : Byte;
  Begin
   For ParameterIndex:=1 To MaxANSIParameters Do Parameters[ParameterIndex]:=0;
   ParametersCount:=0;
   NumberLine:=''
  end;
 Begin
  Case Mode Of
  0: Case Symbol Of
     #27: Mode:=1;
     Else Write(Symbol);
     end;
  1: Case Symbol Of
     '[': Mode:=2;
     Else
      Begin
       Mode:=0;
       WriteSymbol(Symbol);
      end;
     end;
  2: Case Symbol Of
     '0'..'9':
     Begin
      Mode:=3;
      ClearParameters;
      ParametersCount:=1;
      NumberLine:='';
      Number:=0;
      WriteSymbol(Symbol);
     end;
     's':
     Begin
      ANSICursorColumn:=WhereX;
      ANSICursorRow:=WhereY;
      ANSICursorSaved:=True;
      ClearParameters;
      Mode:=0;
     end;
     'u':
     Begin
      If ANSICursorSaved Then
      Begin
       GoToXY(ANSICursorColumn,ANSICursorRow);
       ANSICursorColumn:=0;
       ANSICursorRow:=0;
       ANSICursorSaved:=False;
      end;
      ClearParameters;
      Mode:=0;
     end;
     'H','f':
     Begin
      For Index:=1 To 2 Do If Parameters[Index]=0 Then Parameters[Index]:=1;
      GoToXY(Parameters[2],Parameters[1]);
      ClearParameters;
      Mode:=0;
     end;
     'J':
     Begin
      ClrScr;
      ClearParameters;
      Mode:=0;
     end;
     'A':
     Begin
      If Parameters[1]=0 Then Parameters[1]:=1;
      GoToXY(WhereX,WhereY-Parameters[1]);
      ClearParameters;
      Mode:=0;
     end;
     'B':
     Begin
      If Parameters[1]=0 Then Parameters[1]:=1;
      GoToXY(WhereX,WhereY+Parameters[1]);
      ClearParameters;
      Mode:=0;
     end;
     'C':
     Begin
      If Parameters[1]=0 Then Parameters[1]:=1;
      GoToXY(WhereX+Parameters[1],WhereY);
      ClearParameters;
      Mode:=0;
     end;
     'D':
     Begin
      If Parameters[1]=0 Then Parameters[1]:=1;
      GoToXY(WhereX-Parameters[1],WhereY);
      ClearParameters;
      Mode:=0;
     end;
     'K':
     Begin
      ClrEol;
      ClearParameters;
      Mode:=0;
     end;
     'm':
     Begin
      If ParametersCount=0 Then NormVideo Else For Index:=1 To ParametersCount Do Case Parameters[Index] Of
      00: NormVideo;
      01: HighVideo;
      04: TextAttr:=(TextAttr And $F8) Or Blue;
      05: TextAttr:=TextAttr Or $80;
      07:
      Begin
       Number:=(TextAttr And $77);
       TextAttr:=(TextAttr And $88) Or ((Number Div $10) And $07);
       TextAttr:=TextAttr Or ((Number*$10) And $70);
       Number:=0;
      end;
      08: TextAttr:=TextAttr And $88;
      30: TextColor(Black);
      31: TextColor(Red);
      32: TextColor(Green);
      33: TextColor(Brown);
      34: TextColor(Blue);
      35: TextColor(Magenta);
      36: TextColor(Cyan);
      37: TextColor(LightGray);
      40: TextBackGround(Black);
      41: TextBackGround(Red);
      42: TextBackGround(Green);
      43: TextBackGround(Brown);
      44: TextBackGround(Blue);
      45: TextBackGround(Magenta);
      46: TextBackGround(Cyan);
      47: TextBackGround(LightGray);
      end;
      ClearParameters;
      Mode:=0;
     end;
     Else
      Begin
       Mode:=0;
       WriteSymbol(Symbol);
      end;
     end;
  3: Case Symbol Of
     '0'..'9': NumberLine:=NumberLine+Symbol;
     ';':
     Begin
      If NumberLine<>'' Then
      Begin
       If Length(NumberLine)>2 Then NumberLine:=Copy(NumberLine,1,2);
       Val(NumberLine,Number,ErrorInteger);
       NumberLine:='';
       If Number>255 Then Number:=255;
       If ParametersCount<MaxANSIParameters Then
       Begin
        Parameters[ParametersCount]:=Number;
        Inc(ParametersCount);
       end;
      end Else
      Begin
       Mode:=2;
       WriteSymbol(Symbol);
      end;
     end;
     Else
      Begin
       If NumberLine<>'' Then
        Begin
         If Length(NumberLine)>2 Then NumberLine:=Copy(NumberLine,1,2);
         Val(NumberLine,Number,ErrorInteger);
         NumberLine:='';
         If Number>255 Then Number:=255;
         If ParametersCount<MaxANSIParameters Then Parameters[ParametersCount]:=Number;
        end;
       Mode:=2;
       WriteSymbol(Symbol);
      end;
     end;
  end;
 end;
Var
  LineIndex : Byte;
Begin
 For LineIndex:=1 To Length(Line) Do WriteSymbol(Line[LineIndex]);
end;
Function Trim(LineToTrim : String) : String;
Begin
 While LineToTrim<>'' Do If Ord(LineToTrim[1])<33 Then Delete(LineToTrim,1,1) Else Break;
 While LineToTrim<>'' Do If Ord(LineToTrim[Length(LineToTrim)])<33 Then Delete(LineToTrim,Length(LineToTrim),1) Else Break;
 Trim:=LineToTrim;
end;
Function InName(Var Line : String) : String;
Var
  OutName : String;
Begin
 Line:=Trim(Line);
 OutName:='';
 While Line<>'' Do
 Case UpCase(Line[1]) Of
 'A'..'Z':
  Begin
   OutName:=OutName+UpCase(Line[1]);
   Delete(Line,1,1);
  end;
 '0'..'9':
  Begin
   OutName:=OutName+Copy(Line,1,1);
   Delete(Line,1,1);
  end;
 Else Break;
 end;
 If OutName='' Then Error:='Syntax error' Else InName:=OutName;
end;
Function InNumber(Var Line : String) : Real;
Var
  OutNumber    : String;
  PointPresent : Boolean;
  Value        : Real;
  ErrorInteger : Integer;
Begin
 Line:=Trim(Line);
 OutNumber:='';
 PointPresent:=False;
 While Line<>'' Do
 Case Line[1] Of
 '0'..'9':
  Begin
   OutNumber:=OutNumber+Copy(Line,1,1);
   Delete(Line,1,1);
  end;
 '.':
  Begin
   Delete(Line,1,1);
   If (Line='') Or (OutNumber='') Or (Not ((Ord(Line[1])>(Ord('0')-1)) And (Ord(Line[1])<(Ord('9')+1)))) Or PointPresent Then
   Begin
    Error:='Invalid number';
    Exit;
   end;
   PointPresent:=True;
   OutNumber:=OutNumber+'.';
  end;
 Else Break;
 end;
 If OutNumber='' Then Error:='Syntax error' Else
 Begin
  Val(OutNumber,Value,ErrorInteger);
  If ErrorInteger<>0 Then Error:='Invalid number' Else InNumber:=Value;
 end;
end;
Function NumberToString(Value : Real) : String;
Var
  OutValue : String;
Begin
 If Value=Trunc(Value) Then Str(Trunc(Value),OutValue) Else Str(Value:255:15,OutValue);
 OutValue:=Trim(OutValue);
 If Pos('.',OutValue)>0 Then While OutValue<>'' Do If Copy(OutValue,Length(OutValue),1)='0' Then
 Delete(OutValue,Length(OutValue),1) Else Break;
 NumberToString:=OutValue;
end;
Function StringToNumber(Value : String) : Real;
Var
  OutValue     : Real;
  ErrorInteger : Integer;
Begin
 Val(Value,OutValue,ErrorInteger);
 If ErrorInteger<>0 Then Error:='Invalid number' Else StringToNumber:=OutValue;
end;
Function Calculate(Var Line : String) : String;
Var
  Result     : String;
  Value      : String;
  TempNumStr : Boolean;
  Action     : String;
  TempLine   : String;
Begin
 Result:=InMeaning(Line);
 If Error<>'' Then Exit;
 Line:=Trim(Line);
 While Line<>'' Do
 Case UpCase(Line[1]) Of
 '+':
  Begin
   Delete(Line,1,1);
   TempNumStr:=NumStr;
   Value:=InMeaning(Line);
   If Error<>'' Then Exit;
   If TempNumStr<>NumStr Then
   Begin
    Error:='Type mismatch';
    Exit;
   end;
   If NumStr Then Result:=Result+Value Else Result:=NumberToString(StringToNumber(Result)+StringToNumber(Value));
   If Error<>'' Then Exit;
  end;
 '-':
  Begin
   Delete(Line,1,1);
   If NumStr Then
   Begin
    Error:='Type mismatch';
    Exit;
   end;
   Value:=InMeaning(Line);
   If Error<>'' Then Exit;
   If NumStr Then
   Begin
    Error:='Type mismatch';
    Exit;
   end;
   Result:=NumberToString(StringToNumber(Result)-StringToNumber(Value));
   If Error<>'' Then Exit;
  end;
 '/','\':
  Begin
   Delete(Line,1,1);
   If NumStr Then
   Begin
    Error:='Type mismatch';
    Exit;
   end;
   Value:=InMeaning(Line);
   If Error<>'' Then Exit;
   If NumStr Then
   Begin
    Error:='Type mismatch';
    Exit;
   end;
   If StringToNumber(Value)=0.0 Then
   Begin
    Error:='Divide by zero';
    Exit;
   end;
   Result:=NumberToString(StringToNumber(Result)/StringToNumber(Value));
   If Error<>'' Then Exit;
  end;
 '*':
  Begin
   Delete(Line,1,1);
   If NumStr Then
   Begin
    Error:='Type mismatch';
    Exit;
   end;
   Value:=InMeaning(Line);
   If Error<>'' Then Exit;
   If NumStr Then
   Begin
    Error:='Type mismatch';
    Exit;
   end;
   Result:=NumberToString(StringToNumber(Result)*StringToNumber(Value));
   If Error<>'' Then Exit;
  end;
 '=':
  Begin
   Delete(Line,1,1);
   Line:=Trim(Line);
   If Line='' Then
   Begin
    Error:='Syntax error';
    Exit;
   end;
   Case Line[1] Of
   '<':
    Begin
     Delete(Line,1,1);
     TempNumStr:=NumStr;
     Value:=InMeaning(Line);
     If Error<>'' Then Exit;
     If NumStr<>TempNumStr Then
     Begin
      Error:='Type mismacth';
      Exit;
     end;
     If NumStr Then
     Begin
      If Result<=Value Then Result:='-1' Else Result:='0';
     end Else
     Begin
      If StringToNumber(Result)<=StringToNumber(Value) Then Result:='-1' Else Result:='0';
     end;
    end;
   '>':
    Begin
     Delete(Line,1,1);
     TempNumStr:=NumStr;
     Value:=InMeaning(Line);
     If Error<>'' Then Exit;
     If NumStr<>TempNumStr Then
     Begin
      Error:='Type mismacth';
      Exit;
     end;
     If NumStr Then
     Begin
      If Result>=Value Then Result:='-1' Else Result:='0';
     end Else
     Begin
      If StringToNumber(Result)>=StringToNumber(Value) Then Result:='-1' Else Result:='0';
     end;
    end;
   Else
    Begin
     TempNumStr:=NumStr;
     Value:=InMeaning(Line);
     If Error<>'' Then Exit;
     If NumStr<>TempNumStr Then
     Begin
      Error:='Type mismacth';
      Exit;
     end;
     If NumStr Then
     Begin
      If Result=Value Then Result:='-1' Else Result:='0';
     end Else
     Begin
      If StringToNumber(Result)=StringToNumber(Value) Then Result:='-1' Else Result:='0';
     end;
    end;
   end;
   NumStr:=False;
  end;
 '<':
  Begin
   Delete(Line,1,1);
   Line:=Trim(Line);
   If Line='' Then
   Begin
    Error:='Syntax error';
    Exit;
   end;
   Case Line[1] Of
   '>':
    Begin
     Delete(Line,1,1);
     TempNumStr:=NumStr;
     Value:=InMeaning(Line);
     If Error<>'' Then Exit;
     If NumStr<>TempNumStr Then
     Begin
      Error:='Type mismacth';
      Exit;
     end;
     If NumStr Then
     Begin
      If Result<>Value Then Result:='-1' Else Result:='0';
     end Else
     Begin
      If StringToNumber(Result)<>StringToNumber(Value) Then Result:='-1' Else Result:='0';
     end;
    end;
   '=':
    Begin
     Delete(Line,1,1);
     TempNumStr:=NumStr;
     Value:=InMeaning(Line);
     If Error<>'' Then Exit;
     If NumStr<>TempNumStr Then
     Begin
      Error:='Type mismacth';
      Exit;
     end;
     If NumStr Then
     Begin
      If Result<=Value Then Result:='-1' Else Result:='0';
     end Else
     Begin
      If StringToNumber(Result)<=StringToNumber(Value) Then Result:='-1' Else Result:='0';
     end;
    end;
   Else
    Begin
     TempNumStr:=NumStr;
     Value:=InMeaning(Line);
     If Error<>'' Then Exit;
     If NumStr<>TempNumStr Then
     Begin
      Error:='Type mismacth';
      Exit;
     end;
     If NumStr Then
     Begin
      If Result<Value Then Result:='-1' Else Result:='0';
     end Else
     Begin
      If StringToNumber(Result)<StringToNumber(Value) Then Result:='-1' Else Result:='0';
     end;
    end;
   end;
   NumStr:=False;
  end;
 '>':
  Begin
   Delete(Line,1,1);
   Line:=Trim(Line);
   If Line='' Then
   Begin
    Error:='Syntax error';
    Exit;
   end;
   Case Line[1] Of
   '<':
    Begin
     Delete(Line,1,1);
     TempNumStr:=NumStr;
     Value:=InMeaning(Line);
     If Error<>'' Then Exit;
     If NumStr<>TempNumStr Then
     Begin
      Error:='Type mismacth';
      Exit;
     end;
     If NumStr Then
     Begin
      If Result<>Value Then Result:='-1' Else Result:='0';
     end Else
     Begin
      If StringToNumber(Result)<>StringToNumber(Value) Then Result:='-1' Else Result:='0';
     end;
    end;
   '=':
    Begin
     Delete(Line,1,1);
     TempNumStr:=NumStr;
     Value:=InMeaning(Line);
     If Error<>'' Then Exit;
     If NumStr<>TempNumStr Then
     Begin
      Error:='Type mismacth';
      Exit;
     end;
     If NumStr Then
     Begin
      If Result>=Value Then Result:='-1' Else Result:='0';
     end Else
     Begin
      If StringToNumber(Result)>=StringToNumber(Value) Then Result:='-1' Else Result:='0';
     end;
    end;
   Else
    Begin
     TempNumStr:=NumStr;
     Value:=InMeaning(Line);
     If Error<>'' Then Exit;
     If NumStr<>TempNumStr Then
     Begin
      Error:='Type mismacth';
      Exit;
     end;
     If NumStr Then
     Begin
      If Result>Value Then Result:='-1' Else Result:='0';
     end Else
     Begin
      If StringToNumber(Result)>StringToNumber(Value) Then Result:='-1' Else Result:='0';
     end;
    end;
   end;
   NumStr:=False;
  end;
 'A'..'Z':
  Begin
   TempLine:=Line;
   Action:=InName(Line);
   If Error<>'' Then Exit;
   If Action='AND' Then
   Begin
    If NumStr Then
    Begin
     Error:='Type mismatch';
     Exit;
    end;
    Value:=InMeaning(Line);
    If Error<>'' Then Exit;
    If NumStr Then
    Begin
     Error:='Type mismatch';
     Exit;
    end;
    Result:=NumberToString(Trunc(StringToNumber(Result)) And Trunc(StringToNumber(Value)));
   end Else If Action='OR' Then
   Begin
    If NumStr Then
    Begin
     Error:='Type mismatch';
     Exit;
    end;
    Value:=InMeaning(Line);
    If Error<>'' Then Exit;
    If NumStr Then
    Begin
     Error:='Type mismatch';
     Exit;
    end;
    Result:=NumberToString(Trunc(StringToNumber(Result)) Or Trunc(StringToNumber(Value)));
   end Else If Action='XOR' Then
   Begin
    If NumStr Then
    Begin
     Error:='Type mismatch';
     Exit;
    end;
    Value:=InMeaning(Line);
    If Error<>'' Then Exit;
    If NumStr Then
    Begin
     Error:='Type mismatch';
     Exit;
    end;
    Result:=NumberToString(Trunc(StringToNumber(Result)) XOr Trunc(StringToNumber(Value)));
   end Else If Action='MOD' Then
   Begin
    If NumStr Then
    Begin
     Error:='Type mismatch';
     Exit;
    end;
    Value:=InMeaning(Line);
    If Error<>'' Then Exit;
    If NumStr Then
    Begin
     Error:='Type mismatch';
     Exit;
    end;
    Result:=NumberToString(Trunc(StringToNumber(Result)) Mod Trunc(StringToNumber(Value)));
   end Else
   Begin
    Line:=TempLine;
    Break;
   end;
  end;
 Else Break;
 end;
 Calculate:=Result;
end;
Function InDefFn(FnName : String; FnType : Boolean; Var Line : String) : String;
Var
  OldDefFnMode : Boolean;
  DefFnName    : String;
  DefFnType    : Boolean;
  ArgName      : String;
  ArgType      : Boolean;
  WorkLine     : String;
  Index        : Word;
  Result       : String;
Begin
 If DefFnSCount=0 Then
 Begin
  Error:='User - defined functions is not declare';
  Exit;
 end;
 For Index:=1 To DefFnSCount+1 Do
 Begin
  If Index=DefFnSCount+1 Then
  Begin
   Error:='User - defined function is not declare';
   Exit;
  end;
  WorkLine:=DefFnS[Index];
  DefFnName:=InName(WorkLine);
  If Error<>'' Then Exit;
  WorkLine:=Trim(WorkLine);
  If WorkLine='' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  DefFnType:=False;
  Case WorkLine[1] Of
  '$':
   Begin
    Delete(WorkLine,1,1);
    DefFnType:=True;
   end;
  '!': Delete(WorkLine,1,1);
  '@': Delete(WorkLine,1,1);
  '#': Delete(WorkLine,1,1);
  '%': Delete(WorkLine,1,1);
  '&': Delete(WorkLine,1,1);
  end;
  If (DefFnName=FnName) And (DefFnType=FnType) Then Break;
 end;
 WorkLine:=Trim(WorkLine);
 If CurrentDefFn=MaxDefFnS Then
 Begin
  Error:='Too many calculated user - defined functions';
  Exit;
 end;
 Inc(CurrentDefFn);
 For Index:=1 To MaxDefFnSArgs Do
 Begin
  DefFnSArgs[CurrentDefFn,Index].VarName:='';
  DefFnSArgs[CurrentDefFn,Index].StringValue:='';
  DefFnSArgs[CurrentDefFn,Index].NumberValue:=0.0;
  DefFnSArgs[CurrentDefFn,Index].ValueType:=False;
 end;
 DefFnSArgsCount[CurrentDefFn]:=0;
 If Copy(WorkLine,1,1)='(' Then
 Begin
  Delete(WorkLine,1,1);
  WorkLine:=Trim(WorkLine);
  If WorkLine='' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  DefFnSArgsCount[CurrentDefFn]:=1;
  While WorkLine<>'' Do
  Begin
   ArgName:=InName(WorkLine);
   If Error<>'' Then Exit;
   WorkLine:=Trim(WorkLine);
   If WorkLine='' Then
   Begin
    Error:='Syntax error';
    Exit;
   end;
   ArgType:=False;
   Case WorkLine[1] Of
   '$':
    Begin
     Delete(WorkLine,1,1);
     ArgType:=True;
    end;
   '!': Delete(WorkLine,1,1);
   '@': Delete(WorkLine,1,1);
   '#': Delete(WorkLine,1,1);
   '%': Delete(WorkLine,1,1);
   '&': Delete(WorkLine,1,1);
   end;
   DefFnSArgs[CurrentDefFn,DefFnSArgsCount[CurrentDefFn]].VarName:=ArgName;
   DefFnSArgs[CurrentDefFn,DefFnSArgsCount[CurrentDefFn]].ValueType:=ArgType;
   WorkLine:=Trim(WorkLine);
   If WorkLine='' Then
   Begin
    Error:='Syntax error';
    Exit;
   end;
   Case WorkLine[1] Of
   ',':
    Begin
     Delete(WorkLine,1,1);
     If DefFnSArgsCount[CurrentDefFn]=MaxDefFnSArgs Then
     Begin
      Error:='Too many arguments for user - defined function';
      Exit;
     end;
     Inc(DefFnSArgsCount[CurrentDefFn]);
    end;
   ')':
    Begin
     Delete(WorkLine,1,1);
     WorkLine:=Trim(WorkLine);
     Break;
    end;
   Else
    Begin
     Error:='Syntax error';
     Exit;
    end;
   end;
  end;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>'(' Then
  Begin
   Error:='Syntax error in call user - defined function';
   Exit;
  end;
  Delete(Line,1,1);
  Line:=Trim(Line);
  Index:=1;
  If Line='' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  While Line<>'' Do
  Begin
   Result:=Calculate(Line);
   If Error<>'' Then Exit;
   If DefFnSArgs[CurrentDefFn,Index].ValueType<>NumStr Then
   Begin
    Error:='Argument type mismatch';
    Exit;
   end;
   If NumStr Then
   DefFnSArgs[CurrentDefFn,Index].StringValue:=Result
   Else
   DefFnSArgs[CurrentDefFn,Index].NumberValue:=StringToNumber(Result);
   Line:=Trim(Line);
   If Line='' Then
   Begin
    Error:='Syntax error';
    Exit;
   end;
   Case Line[1] Of
   ',':
    Begin
     Delete(Line,1,1);
     If Index=DefFnSArgsCount[CurrentDefFn] Then
     Begin
      Error:='Argument - count mismatch';
      Exit;
     end;
     Inc(Index);
    end;
   ')':
    Begin
     Delete(Line,1,1);
     If Index<>DefFnSArgsCount[CurrentDefFn] Then
     Begin
      Error:='Argument - count mismatch';
      Exit;
     end;
     Break;
    end;
   end;
  end;
 end;
 If Copy(WorkLine,1,1)<>'=' Then
 Begin
  Error:='Syntax error';
  Exit;
 end;
 Delete(WorkLine,1,1);
 OldDefFnMode:=DefFnMode;
 DefFnMode:=True;
 Result:=Calculate(WorkLine);
 If Error<>'' Then Exit;
 If NumStr<>FnType Then
 Begin
  Error:='Type mismatch';
  Exit;
 end;
 DefFnMode:=OldDefFnMode;
 For Index:=1 To MaxDefFnSArgs Do
 Begin
  DefFnSArgs[CurrentDefFn,Index].VarName:='';
  DefFnSArgs[CurrentDefFn,Index].StringValue:='';
  DefFnSArgs[CurrentDefFn,Index].NumberValue:=0.0;
  DefFnSArgs[CurrentDefFn,Index].ValueType:=False;
 end;
 DefFnSArgsCount[CurrentDefFn]:=0;
 Dec(CurrentDefFn);
 InDefFn:=Result;
end;
Procedure SetVar(VarName : String; VarType : Boolean; VarValue : String);
Var
  Index  : Word;
  WorkDT : DateTime;
Begin
 If (VarName='DATE') And VarType Then
 Begin
  If Length(VarValue)<>10 Then
  Begin
   Error:='Invalid date';
   Exit;
  end;
  WorkDT.Year:=Trunc(StringToNumber(Copy(VarValue,7,2)));
  If Error<>'' Then Exit;
  If (WorkDT.Year<1980) Or (WorkDT.Year>2099) Then
  Begin
   Error:='Invalid year number';
   Exit;
  end;
  WorkDT.Month:=Trunc(StringToNumber(Copy(VarValue,1,2)));
  If Error<>'' Then Exit;
  If (WorkDT.Month<1) Or (WorkDT.Month>12) Then
  Begin
   Error:='Invalid month number';
   Exit;
  end;
  WorkDT.Day:=Trunc(StringToNumber(Copy(VarValue,4,2)));
  If Error<>'' Then Exit;
  If (WorkDT.Day<1) Or (WorkDT.Day>MonthDay(WorkDT.Year,WorkDT.Month)) Then
  Begin
   Error:='Invalid day number';
   Exit;
  end;
  SetDate(WorkDT.Year,WorkDT.Month,WorkDT.Day);
 end Else If (VarName='TIME') And VarType Then
 Begin
  If Length(VarValue)<>8 Then
  Begin
   Error:='Invalid date';
   Exit;
  end;
  WorkDT.Hour:=Trunc(StringToNumber(Copy(VarValue,1,2)));
  If Error<>'' Then Exit;
  If (WorkDT.Hour<0) Or (WorkDT.Hour>23) Then
  Begin
   Error:='Invalid hour value';
   Exit;
  end;
  WorkDT.Min:=Trunc(StringToNumber(Copy(VarValue,4,2)));
  If Error<>'' Then Exit;
  If (WorkDT.Min<0) Or (WorkDT.Min>59) Then
  Begin
   Error:='Invalid minute value';
   Exit;
  end;
  WorkDT.Sec:=Trunc(StringToNumber(Copy(VarValue,7,2)));
  If Error<>'' Then Exit;
  If (WorkDT.Sec<0) Or (WorkDT.Sec>59) Then
  Begin
   Error:='Invalid second value';
   Exit;
  end;
  SetTime(WorkDT.Hour,WorkDT.Min,WorkDT.Sec,0);
 end Else If (VarName='PROMPT') And VarType Then Prompt:=VarValue Else
 Begin
  If VarsCount=0 Then
  Begin
   Inc(VarsCount);
   If VarType Then Vars[VarsCount].StringValue:=VarValue Else Vars[VarsCount].NumberValue:=StringToNumber(VarValue);
   Vars[VarsCount].ValueType:=VarType;
   Vars[VarsCount].VarName:=VarName;
  end Else
  Begin
   For Index:=1 To MaxVars+1 Do
   Begin
    If Index=MaxVars+1 Then
    Begin
     If VarsCount=MaxVars Then
     Begin
      Error:='Too many variables';
      Exit;
     end;
     Inc(VarsCount);
     If VarType Then Vars[VarsCount].StringValue:=VarValue Else Vars[VarsCount].NumberValue:=StringToNumber(VarValue);
     Vars[VarsCount].ValueType:=VarType;
     Vars[VarsCount].VarName:=VarName;
     Exit;
    end;
    If (Vars[Index].VarName=VarName) And (Vars[Index].ValueType=VarType) Then Break;
   end;
   If VarType Then Vars[Index].StringValue:=VarValue Else Vars[Index].NumberValue:=StringToNumber(VarValue);
  end;
 end;
end;
Function InVar(VarName : String; VarType : Boolean) : String;
Var
  Index : Word;
Begin
 If DefFnMode Then
 Begin
  If DefFnSArgsCount[CurrentDefFn]=0 Then
  Begin
   DefFnMode:=False;
   InVar:=InVar(VarName,VarType);
   DefFnMode:=True;
  end Else
  Begin
   For Index:=1 To DefFnSArgsCount[CurrentDefFn]+1 Do
   Begin
    If Index=DefFnSArgsCount[CurrentDefFn]+1 Then
    Begin
     DefFnMode:=False;
     InVar:=InVar(VarName,VarType);
     DefFnMode:=True;
     Exit;
    end;
    If (DefFnSArgs[CurrentDefFn,Index].VarName=VarName) And (DefFnSArgs[CurrentDefFn,Index].ValueType=VarType) Then Break;
   end;
   If VarType Then InVar:=DefFnSArgs[CurrentDefFn,Index].StringValue
   Else InVar:=NumberToString(DefFnSArgs[CurrentDefFn,Index].NumberValue);
  end;
 end Else
 Begin
  If VarsCount=0 Then
  Begin
   If VarType Then
   Begin
    SetVar(VarName,True,'');
    InVar:='';
   end Else
   Begin
    SetVar(VarName,False,'0.0');
    InVar:='0.0';
   end;
  end Else
  Begin
   For Index:=1 To MaxVars+1 Do
   Begin
    If Index=MaxVars+1 Then
    Begin
     If VarType Then
     Begin
      SetVar(VarName,True,'');
      InVar:='';
     end Else
     Begin
      SetVar(VarName,False,'0.0');
      InVar:='0.0';
     end;
     Exit;
    end;
    If (Vars[Index].VarName=VarName) And (Vars[Index].ValueType=VarType) Then Break;
   end;
   If VarType Then InVar:=Vars[Index].StringValue Else InVar:=NumberToString(Vars[Index].NumberValue);
  end;
 end;
end;
Function InMeaning(Var Line : String) : String;
Var
  Result : String;
  Value  : String;
  Name   : String;
  WorkDT : DateTime;
Begin
 Line:=Trim(Line);
 If Line='' Then
 Begin
  Error:='Syntax error';
  Exit;
 end;
 Case UpCase(Line[1]) Of
 '0'..'9':
  Begin
   InMeaning:=NumberToString(InNumber(Line));
   NumStr:=False;
  end;
 '-':
  Begin
   Delete(Line,1,1);
   Result:=Calculate(Line);
   If Error<>'' Then Exit;
   If NumStr Then
   Begin
    Error:='Type mismatch';
    Exit;
   end;
   InMeaning:=NumberToString(0.0-StringToNumber(Result));
  end;
 '+':
  Begin
   Delete(Line,1,1);
   Result:=Calculate(Line);
   If Error<>'' Then Exit;
   If NumStr Then
   Begin
    Error:='Type mismatch';
    Exit;
   end;
   InMeaning:=NumberToString(0.0+StringToNumber(Result));
  end;
 'A'..'Z':
  Begin
   Name:=InName(Line);
   If Error<>'' Then Exit;
   Line:=Trim(Line);
   NumStr:=False;
   If Line<>'' Then
   Case Line[1] Of
   '$':
    Begin
     Delete(Line,1,1);
     NumStr:=True;
    end;
   '!': Delete(Line,1,1);
   '@': Delete(Line,1,1);
   '#': Delete(Line,1,1);
   '%': Delete(Line,1,1);
   '&': Delete(Line,1,1);
   end;
   Line:=Trim(Line);
   If Name='NOT' Then
   Begin
    Result:=Calculate(Line);
    If Error<>'' Then Exit;
    If NumStr Then
    Begin
     Error:='Type mismatch';
     Exit;
    end;
    InMeaning:=NumberToString(Not Trunc(StringToNumber(Result)));
   end Else If NumStr Then
   Begin
    If Name='INKEY' Then
    Begin
     If KeyPressed Then
     Begin
      Result:=ReadKey;
      If Ord(Result[1])=0 Then InMeaning:=Chr(0)+ReadKey Else InMeaning:=Result;
     end Else InMeaning:='';
    end Else If Name='DATE' Then
    Begin
     GetDate(WorkDT.Year,WorkDT.Month,WorkDT.Day,WorkDT.Hour);
     Str(WorkDT.Month,Result);
     If Length(Result)<2 Then Result:='0'+Result;
     Str(WorkDT.Day,Value);
     If Length(Value)<2 Then Value:='0'+Value;
     Result:=Result+'-'+Value+'-';
     Str(WorkDT.Year,Value);
     InMeaning:=Result+Value;
    end Else If Name='TIME' Then
    Begin
     GetTime(WorkDT.Hour,WorkDT.Min,WorkDT.Sec,WorkDT.Year);
     Str(WorkDT.Hour,Result);
     If Length(Result)<2 Then Result:='0'+Result;
     Str(WorkDT.Min,Value);
     If Length(Value)<2 Then Value:='0'+Value;
     Result:=Result+':'+Value+':';
     Str(WorkDT.Sec,Value);
     If Length(Value)<2 Then Value:='0'+Value;
     InMeaning:=Result+Value;
    end Else If Name='PROMPT' Then InMeaning:=Prompt Else
    If Name='INPUT' Then
    Begin
     If Copy(Line,1,1)='(' Then
     Begin
      Delete(Line,1,1);
      Line:=Trim(Line);
      If Copy(Line,1,1)<>'#' Then
      Begin
       Error:='Syntax error';
       Exit;
      end;
      Delete(Line,1,1);
      Result:=Calculate(Line);
      If Error<>'' Then Exit;
      If NumStr Then
      Begin
       Error:='Type mismatch';
       Exit;
      end;
      Line:=Trim(Line);
      If Copy(Line,1,1)<>')' Then
      Begin
       Error:='Syntax error';
       Exit;
      end;
      Delete(Line,1,1);
      If (Trunc(StringToNumber(Result))<1) Or (Trunc(StringToNumber(Result))>MaxFiles) Then
      Begin
       Error:='Invalid file number';
       Exit;
      end;
      If Not Files[Trunc(StringToNumber(Result))].IsUse Then
      Begin
       Error:='Invalid file number';
       Exit;
      end;
      If Not Files[Trunc(StringToNumber(Result))].FileMode Then
      Begin
       Error:='Bad file mode';
       Exit;
      end;
      ReadLn(Files[Trunc(StringToNumber(Result))].WorkFile,Result);
      If IOResult<>0 Then
      Begin
       Error:='Cannot read from file';
       Exit;
      end;
      NumStr:=True;
      InMeaning:=Result;
     end Else
     Begin
      ReadLn(Result);
      InMeaning:=Result;
     end;
    end Else If Name='STR' Then
    Begin
     If Copy(Line,1,1)<>'(' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     Result:=Calculate(Line);
     If Error<>'' Then Exit;
     If NumStr Then
     Begin
      Error:='Type mismatch';
      Exit;
     end;
     Line:=Trim(Line);
     If Copy(Line,1,1)<>')' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     NumStr:=True;
     InMeaning:=NumberToString(StringToNumber(Result));
    end Else If Name='CHR' Then
    Begin
     If Copy(Line,1,1)<>'(' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     Result:=Calculate(Line);
     If Error<>'' Then Exit;
     If NumStr Then
     Begin
      Error:='Type mismatch';
      Exit;
     end;
     Line:=Trim(Line);
     If Copy(Line,1,1)<>')' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     NumStr:=True;
     InMeaning:=Chr(Trunc(StringToNumber(Result)));
    end Else If Name='TRIM' Then
    Begin
     If Copy(Line,1,1)<>'(' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     Result:=Calculate(Line);
     If Error<>'' Then Exit;
     If Not NumStr Then
     Begin
      Error:='Type mismatch';
      Exit;
     end;
     Line:=Trim(Line);
     If Copy(Line,1,1)<>')' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     InMeaning:=Trim(Result);
    end Else If Name='MID' Then
    Begin
     If Copy(Line,1,1)<>'(' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     Name:=Calculate(Line);
     If Error<>'' Then Exit;
     If Not NumStr Then
     Begin
      Error:='Type mismatch';
      Exit;
     end;
     Line:=Trim(Line);
     If Copy(Line,1,1)<>',' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     Result:=Calculate(Line);
     If Error<>'' Then Exit;
     If NumStr Then
     Begin
      Error:='Type mismatch';
      Exit;
     end;
     Line:=Trim(Line);
     If Copy(Line,1,1)<>',' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     Value:=Calculate(Line);
     If Error<>'' Then Exit;
     If NumStr Then
     Begin
      Error:='Type mismatch';
      Exit;
     end;
     Line:=Trim(Line);
     If Copy(Line,1,1)<>')' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     NumStr:=True;
     InMeaning:=Copy(Name,Trunc(StringToNumber(Result)),Trunc(StringToNumber(Value)));
    end Else If Name='DAYOFWEEK' Then
    Begin
     If Copy(Line,1,1)<>'(' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     Name:=Calculate(Line);
     If Error<>'' Then Exit;
     If NumStr Then
     Begin
      Error:='Type mismatch';
      Exit;
     end;
     Line:=Trim(Line);
     If Copy(Line,1,1)<>',' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     Result:=Calculate(Line);
     If Error<>'' Then Exit;
     If NumStr Then
     Begin
      Error:='Type mismatch';
      Exit;
     end;
     Line:=Trim(Line);
     If Copy(Line,1,1)<>',' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     Value:=Calculate(Line);
     If Error<>'' Then Exit;
     If NumStr Then
     Begin
      Error:='Type mismatch';
      Exit;
     end;
     Line:=Trim(Line);
     If Copy(Line,1,1)<>')' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     NumStr:=True;
     If (Trunc(StringToNumber(Name))<1980) Or (Trunc(StringToNumber(Name))>2099) Then
     Begin
      Error:='Invalid year';
      Exit;
     end;
     If (Trunc(StringToNumber(Result))<1) Or (Trunc(StringToNumber(Result))>12) Then
     Begin
      Error:='Invalid month';
      Exit;
     end;
     If (Trunc(StringToNumber(Value))<1)
     Or (Trunc(StringToNumber(Value))>MonthDay(Trunc(StringToNumber(Name)),Trunc(StringToNumber(Result)))) Then
     Begin
      Error:='Invalid day';
      Exit;
     end;
     Case DayOfWeek(Trunc(StringToNumber(Name)),Trunc(StringToNumber(Result)),Trunc(StringToNumber(Value))) Of
     1: InMeaning:='Monday';
     2: InMeaning:='Tuesday';
     3: InMeaning:='Wednesday';
     4: InMeaning:='Thursday';
     5: InMeaning:='Friday';
     6: InMeaning:='Saturday';
     7: InMeaning:='Sunday';
     end;
    end Else If Copy(Name,1,2)='FN' Then InMeaning:=InDefFn(Name,True,Line) Else InMeaning:=InVar(Name,True);
   end Else
   Begin
    If Name='PI' Then InMeaning:='3.1415926535897932385' Else
    If Name='BLACK' Then InMeaning:='0' Else
    If Name='BLUE' Then InMeaning:='1' Else
    If Name='GREEN' Then InMeaning:='2' Else
    If Name='CYAN' Then InMeaning:='3' Else
    If Name='RED' Then InMeaning:='4' Else
    If Name='MAGENTA' Then InMeaning:='5' Else
    If Name='BROWN' Then InMeaning:='6' Else
    If Name='LIGHTGRAY' Then InMeaning:='7' Else
    If Name='DARKGRAY' Then InMeaning:='8' Else
    If Name='LIGHTBLUE' Then InMeaning:='9' Else
    If Name='LIGHTGREEN' Then InMeaning:='10' Else
    If Name='LIGHTCYAN' Then InMeaning:='11' Else
    If Name='LIGHTRED' Then InMeaning:='12' Else
    If Name='LIGHTMAGENTA' Then InMeaning:='13' Else
    If Name='YELLOW' Then InMeaning:='14' Else
    If Name='WHITE' Then InMeaning:='15' Else
    If Name='FALSE' Then InMeaning:='0' Else
    If Name='TRUE' Then InMeaning:='-1' Else
    If Name='LEN' Then
    Begin
     If Copy(Line,1,1)<>'(' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     Result:=Calculate(Line);
     If Error<>'' Then Exit;
     If Not NumStr Then
     Begin
      Error:='Type mismatch';
      Exit;
     end;
     Line:=Trim(Line);
     If Copy(Line,1,1)<>')' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     NumStr:=False;
     InMeaning:=NumberToString(Length(Result));
    end Else If Name='INSTR' Then
    Begin
     If Copy(Line,1,1)<>'(' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     Result:=Calculate(Line);
     If Error<>'' Then Exit;
     If Not NumStr Then
     Begin
      Error:='Type mismatch';
      Exit;
     end;
     Line:=Trim(Line);
     If Copy(Line,1,1)<>',' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     Value:=Calculate(Line);
     If Error<>'' Then Exit;
     If Not NumStr Then
     Begin
      Error:='Type mismatch';
      Exit;
     end;
     Line:=Trim(Line);
     If Copy(Line,1,1)<>')' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     NumStr:=False;
     InMeaning:=NumberToString(Pos(Value,Result));
    end Else If Name='ASC' Then
    Begin
     If Copy(Line,1,1)<>'(' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     Result:=Calculate(Line);
     If Error<>'' Then Exit;
     If Not NumStr Then
     Begin
      Error:='Type mismatch';
      Exit;
     end;
     Line:=Trim(Line);
     If Copy(Line,1,1)<>')' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     NumStr:=False;
     If Result='' Then Error:='Illegal function call' Else InMeaning:=NumberToString(Ord(Result[1]));
    end Else If Name='CRC32' Then
    Begin
     If Copy(Line,1,1)<>'(' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     Result:=Calculate(Line);
     If Error<>'' Then Exit;
     If Not NumStr Then
     Begin
      Error:='Type mismatch';
      Exit;
     end;
     Line:=Trim(Line);
     If Copy(Line,1,1)<>')' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     NumStr:=False;
     InMeaning:=NumberToString(CRC32(Result));
    end Else If Name='VAL' Then
    Begin
     If Copy(Line,1,1)<>'(' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     Result:=Calculate(Line);
     If Error<>'' Then Exit;
     If Not NumStr Then
     Begin
      Error:='Type mismatch';
      Exit;
     end;
     Line:=Trim(Line);
     If Copy(Line,1,1)<>')' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     NumStr:=False;
     InMeaning:=NumberToString(StringToNumber(Result));
    end Else If Name='SQR' Then
    Begin
     If Copy(Line,1,1)<>'(' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     Result:=Calculate(Line);
     If Error<>'' Then Exit;
     If NumStr Then
     Begin
      Error:='Type mismatch';
      Exit;
     end;
     Line:=Trim(Line);
     If Copy(Line,1,1)<>')' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     InMeaning:=NumberToString(Sqrt(StringToNumber(Result)));
    end Else If Name='ABS' Then
    Begin
     If Copy(Line,1,1)<>'(' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     Result:=Calculate(Line);
     If Error<>'' Then Exit;
     If NumStr Then
     Begin
      Error:='Type mismatch';
      Exit;
     end;
     Line:=Trim(Line);
     If Copy(Line,1,1)<>')' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     InMeaning:=NumberToString(Abs(StringToNumber(Result)));
    end Else If Name='INT' Then
    Begin
     If Copy(Line,1,1)<>'(' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     Result:=Calculate(Line);
     If Error<>'' Then Exit;
     If NumStr Then
     Begin
      Error:='Type mismatch';
      Exit;
     end;
     Line:=Trim(Line);
     If Copy(Line,1,1)<>')' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     InMeaning:=NumberToString(Trunc(StringToNumber(Result)));
    end Else If Name='SIN' Then
    Begin
     If Copy(Line,1,1)<>'(' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     Result:=Calculate(Line);
     If Error<>'' Then Exit;
     If NumStr Then
     Begin
      Error:='Type mismatch';
      Exit;
     end;
     Line:=Trim(Line);
     If Copy(Line,1,1)<>')' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     InMeaning:=NumberToString(Sin(StringToNumber(Result)));
    end Else If Name='COS' Then
    Begin
     If Copy(Line,1,1)<>'(' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     Result:=Calculate(Line);
     If Error<>'' Then Exit;
     If NumStr Then
     Begin
      Error:='Type mismatch';
      Exit;
     end;
     Line:=Trim(Line);
     If Copy(Line,1,1)<>')' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     InMeaning:=NumberToString(Cos(StringToNumber(Result)));
    end Else If Name='ATN' Then
    Begin
     If Copy(Line,1,1)<>'(' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     Result:=Calculate(Line);
     If Error<>'' Then Exit;
     If NumStr Then
     Begin
      Error:='Type mismatch';
      Exit;
     end;
     Line:=Trim(Line);
     If Copy(Line,1,1)<>')' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     InMeaning:=NumberToString(ArcTan(StringToNumber(Result)));
    end Else If Name='EOF' Then
    Begin
     If Copy(Line,1,1)<>'(' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     Line:=Trim(Line);
     If Copy(Line,1,1)<>'#' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     Result:=Calculate(Line);
     If Error<>'' Then Exit;
     If NumStr Then
     Begin
      Error:='Type mismatch';
      Exit;
     end;
     Line:=Trim(Line);
     If Copy(Line,1,1)<>')' Then
     Begin
      Error:='Syntax error';
      Exit;
     end;
     Delete(Line,1,1);
     If (Trunc(StringToNumber(Result))<1) Or (Trunc(StringToNumber(Result))>MaxFiles) Then
     Begin
      Error:='Invalid file number';
      Exit;
     end;
     If Not Files[Trunc(StringToNumber(Result))].IsUse Then
     Begin
      Error:='Invalid file number';
      Exit;
     end;
     If EoF(Files[Trunc(StringToNumber(Result))].WorkFile) Then InMeaning:='-1' Else InMeaning:='0';
    end Else If Copy(Name,1,2)='FN' Then InMeaning:=InDefFn(Name,False,Line) Else InMeaning:=InVar(Name,False);
   end;
  end;
 '"':
  Begin
   Delete(Line,1,1);
   If Pos('"',Line)=0 Then
   Begin
    Error:='Syntax error';
    Exit;
   end;
   InMeaning:=Copy(Line,1,Pos('"',Line)-1);
   Line:=Copy(Line,Pos('"',Line)+1,255);
   NumStr:=True;
  end;
 '(':
  Begin
   Delete(Line,1,1);
   InMeaning:=Calculate(Line);
   If Error<>'' Then Exit;
   Line:=Trim(Line);
   If Copy(Line,1,1)<>')' Then Error:='Syntax error' Else Delete(Line,1,1);
  end;
 end;
end;
Function ParseCalculate(Var Line : String) : String;
Var
  Result     : String;
  Value      : String;
  Action     : String;
  TempLine   : String;
Begin
 Result:=ParseInMeaning(Line);
 If Error<>'' Then Exit;
 Line:=Trim(Line);
 While Line<>'' Do
 Case UpCase(Line[1]) Of
 '+':
  Begin
   Delete(Line,1,1);
   Value:=ParseInMeaning(Line);
   If Error<>'' Then Exit;
   Result:=Result+'+'+Value;
  end;
 '-':
  Begin
   Delete(Line,1,1);
   Value:=ParseInMeaning(Line);
   If Error<>'' Then Exit;
   Result:=Result+'-'+Value;
  end;
 '/','\':
  Begin
   Delete(Line,1,1);
   Value:=ParseInMeaning(Line);
   If Error<>'' Then Exit;
   Result:=Result+'/'+Value;
  end;
 '*':
  Begin
   Delete(Line,1,1);
   Value:=ParseInMeaning(Line);
   If Error<>'' Then Exit;
   Result:=Result+'*'+Value;
  end;
 '=':
  Begin
   Delete(Line,1,1);
   Line:=Trim(Line);
   If Line='' Then
   Begin
    Error:='Syntax error';
    Exit;
   end;
   Case Line[1] Of
   '<':
    Begin
     Delete(Line,1,1);
     Value:=ParseInMeaning(Line);
     If Error<>'' Then Exit;
     Result:=Result+'<='+Value;
    end;
   '>':
    Begin
     Delete(Line,1,1);
     Value:=ParseInMeaning(Line);
     If Error<>'' Then Exit;
     Result:=Result+'=>'+Value;
    end;
   Else
    Begin
     Value:=ParseInMeaning(Line);
     If Error<>'' Then Exit;
     Result:=Result+'='+Value;
    end;
   end;
  end;
 '<':
  Begin
   Delete(Line,1,1);
   Line:=Trim(Line);
   If Line='' Then
   Begin
    Error:='Syntax error';
    Exit;
   end;
   Case Line[1] Of
   '>':
    Begin
     Delete(Line,1,1);
     Value:=ParseInMeaning(Line);
     If Error<>'' Then Exit;
     Result:=Result+'<>'+Value;
    end;
   '=':
    Begin
     Delete(Line,1,1);
     Value:=ParseInMeaning(Line);
     If Error<>'' Then Exit;
     Result:=Result+'<='+Value;
    end;
   Else
    Begin
     Value:=ParseInMeaning(Line);
     If Error<>'' Then Exit;
     Result:=Result+'<'+Value;
    end;
   end;
  end;
 '>':
  Begin
   Delete(Line,1,1);
   Line:=Trim(Line);
   If Line='' Then
   Begin
    Error:='Syntax error';
    Exit;
   end;
   Case Line[1] Of
   '<':
    Begin
     Delete(Line,1,1);
     Value:=ParseInMeaning(Line);
     If Error<>'' Then Exit;
     Result:=Result+'<>'+Value;
    end;
   '=':
    Begin
     Delete(Line,1,1);
     Value:=ParseInMeaning(Line);
     If Error<>'' Then Exit;
     Result:=Result+'=>'+Value;
    end;
   Else
    Begin
     Value:=ParseInMeaning(Line);
     If Error<>'' Then Exit;
     Result:=Result+'>'+Value;
    end;
   end;
  end;
 'A'..'Z':
  Begin
   TempLine:=Line;
   Action:=InName(Line);
   If Error<>'' Then Exit;
   If Action='AND' Then
   Begin
    Value:=ParseInMeaning(Line);
    If Error<>'' Then Exit;
    Result:=Result+' And '+Value;
   end Else If Action='OR' Then
   Begin
    Value:=ParseInMeaning(Line);
    If Error<>'' Then Exit;
    Result:=Result+' Or '+Value;
   end Else If Action='XOR' Then
   Begin
    Value:=ParseInMeaning(Line);
    If Error<>'' Then Exit;
    Result:=Result+' XOr '+Value;
   end Else If Action='MOD' Then
   Begin
    Value:=ParseInMeaning(Line);
    If Error<>'' Then Exit;
    Result:=Result+' Mod '+Value;
   end Else
   Begin
    Line:=TempLine;
    Break;
   end;
  end;
 Else Break;
 end;
 ParseCalculate:=Result;
end;
Function ParseInMeaning(Var Line : String) : String;
Var
  Result : String;
  Value  : String;
  Name   : String;
Begin
 Line:=Trim(Line);
 If Line='' Then
 Begin
  Error:='Syntax error';
  Exit;
 end;
 Case UpCase(Line[1]) Of
 '0'..'9': ParseInMeaning:=NumberToString(InNumber(Line));
 '-':
  Begin
   Delete(Line,1,1);
   Result:=ParseCalculate(Line);
   If Error<>'' Then Exit;
   ParseInMeaning:='-'+Result;
  end;
 '+':
  Begin
   Delete(Line,1,1);
   Result:=ParseCalculate(Line);
   If Error<>'' Then Exit;
   ParseInMeaning:=Result;
  end;
 'A'..'Z':
  Begin
   Result:=InName(Line);
   If Error<>'' Then Exit;
   Line:=Trim(Line);
   If Result='NOT' Then
   Begin
    Result:=ParseCalculate(Line);
    If Error<>'' Then Exit;
    ParseInMeaning:='Not '+Result;
   end Else
   Begin
    If Line<>'' Then
    Case Line[1] Of
    '$':
     Begin
      Delete(Line,1,1);
      Result:=Result+'$';
     end;
    '!': Delete(Line,1,1);
    '@': Delete(Line,1,1);
    '#': Delete(Line,1,1);
    '%': Delete(Line,1,1);
    '&': Delete(Line,1,1);
    end;
    Line:=Trim(Line);
    If Copy(Line,1,1)='(' Then
    Begin
     Delete(Line,1,1);
     Result:=Result+'(';
     Line:=Trim(Line);
     While Line<>'' Do
     Begin
      If Copy(Line,1,1)='#' Then
      Begin
       Delete(Line,1,1);
       Result:=Result+'#';
      end;
      Value:=ParseCalculate(Line);
      If Error<>'' Then Exit;
      Result:=Result+Value;
      Line:=Trim(Line);
      If Line='' Then
      Begin
       Error:='Syntax error';
       Exit;
      end;
      Case Line[1] Of
      ')':
       Begin
        Delete(Line,1,1);
        Result:=Result+')';
        Break;
       end;
      ',':
       Begin
        Delete(Line,1,1);
        Result:=Result+',';
       end;
      Else
       Begin
        Error:='Syntax error';
        Exit;
       end;
      end;
     end;
    end;
    ParseInMeaning:=Result;
   end;
  end;
 '"':
  Begin
   Delete(Line,1,1);
   If Pos('"',Line)=0 Then
   Begin
    Error:='Syntax error';
    Exit;
   end;
   ParseInMeaning:='"'+Copy(Line,1,Pos('"',Line)-1)+'"';
   Line:=Copy(Line,Pos('"',Line)+1,255);
  end;
 '(':
  Begin
   Delete(Line,1,1);
   Result:=ParseCalculate(Line);
   If Error<>'' Then Exit;
   Line:=Trim(Line);
   If Copy(Line,1,1)<>')' Then Error:='Syntax error' Else
   Begin
    Delete(Line,1,1);
    ParseInMeaning:='('+Result+')';
   end;
  end;
 end;
end;
Procedure ClearAll;
Var
  Index    : Word;
  SubIndex : Word;
Begin
 For Index:=1 To MaxWhiles Do
 Begin
  Whiles[Index].StartLine:=0;
  Whiles[Index].EndLine:=0;
  Whiles[Index].Conditional:='';
  Whiles[Index].IsFree:=True;
 end;
 For Index:=1 To MaxFroms Do
 Begin
  Froms[Index].StartLine:=0;
  Froms[Index].EndLine:=0;
  Froms[Index].BeginValue:=0;
  Froms[Index].EndLine:=0;
  Froms[Index].IsFree:=True;
 end;
 For Index:=1 To MaxFiles Do
 Begin
  If Files[Index].IsUse Then Close(Files[Index].WorkFile);
  Files[Index].FileMode:=False;
  Files[Index].IsUse:=False;
 end;
 For Index:=1 To MaxGoSubS Do GoSubS[Index]:=0;
 GoSubSCount:=0;
 For Index:=1 To MaxVars Do
 Begin
  Vars[Index].VarName:='';
  Vars[Index].StringValue:='';
  Vars[Index].NumberValue:=0.0;
  Vars[Index].ValueType:=False;
 end;
 VarsCount:=0;
 For Index:=1 To MaxDefFnS Do
 Begin
  DefFnS[Index]:='';
  For SubIndex:=1 To MaxDefFnSArgs Do
  Begin
   DefFnSArgs[Index,SubIndex].VarName:='';
   DefFnSArgs[Index,SubIndex].StringValue:='';
   DefFnSArgs[Index,SubIndex].NumberValue:=0.0;
   DefFnSArgs[Index,SubIndex].ValueType:=False;
  end;
  DefFnSArgsCount[Index]:=0;
 end;
 DefFnSCount:=0;
 CurrentDefFn:=0;
 DefFnMode:=False;
 CurrentLine:=0;
 RunMode:=False;
 TraceMode:=False;
 NumStr:=False;
 Error:='';
 For Index:=1 To MaxANSIParameters Do Parameters[Index]:=0;
 ParametersCount:=0;
 ANSICursorColumn:=0;
 ANSICursorRow:=0;
 ANSICursorSaved:=False;
 Mode:=0;
 NumberLine:='';
 Number:=0;
end;
Function FindLine(LineNumber : Word; LabelName : String; NameNumber : Boolean) : Word;
Var
  Index    : Word;
  WorkLine : String;
  Work     : String;
  Wrk      : Real;
Begin
 If NameNumber Then
 Begin
  For Index:=1 To TextLinesCount+1 Do
  Begin
   If Index=TextLinesCount+1 Then
   Begin
    Error:='Line not found';
    Exit;
   end;
   If Trim(TextLines[Index])<>'' Then
   Begin
    WorkLine:=Trim(TextLines[Index]);
    Case UpCase(WorkLine[1]) Of
    '0'..'9':
     Begin
      Wrk:=InNumber(WorkLine);
      If Error<>'' Then Exit;
      WorkLine:=Trim(WorkLine);
      If WorkLine='' Then
      Begin
       Error:='Syntax error';
       Exit;
      end;
      Case UpCase(WorkLine[1]) Of
      'A'..'Z':
       Begin
        Work:=InName(WorkLine);
        If Error<>'' Then Exit;
        If Work='LABEL' Then
        Begin
         Work:=Calculate(WorkLine);
         If Error<>'' Then Exit;
         If Not NumStr Then
         Begin
          Error:='Type mismatch';
          Exit;
         end;
         If Work=LabelName Then Break;
        end;
       end;
      Else
       Begin
        Error:='Invalid line';
        Exit;
       end;
      end;
     end;
    'A'..'Z':
     Begin
      Work:=InName(WorkLine);
      If Error<>'' Then Exit;
      If Work='LABEL' Then
      Begin
       Work:=Calculate(WorkLine);
       If Error<>'' Then Exit;
       If Not NumStr Then
       Begin
        Error:='Type mismatch';
        Exit;
       end;
       If Work=LabelName Then Break;
      end;
     end;
    Else
     Begin
      Error:='Invalid line';
      Exit;
     end;
    end;
   end;
  end;
 end Else
 Begin
  For Index:=1 To TextLinesCount+1 Do
  Begin
   If Index=TextLinesCount+1 Then
   Begin
    Error:='Line not found';
    Exit;
   end;
   If Trim(TextLines[Index])<>'' Then
   Begin
    WorkLine:=Trim(TextLines[Index]);
    If ((Ord(WorkLine[1])>(Ord('0')-1)) And (Ord(WorkLine[1])<(Ord('9')+1))) Then
    Begin
     Wrk:=InNumber(WorkLine);
     If Error<>'' Then Exit;
     If Trunc(Wrk)=LineNumber Then Break;
    end;
   end;
  end;
 end;
 FindLine:=Index;
end;
Function ParseRunLine(Var Line : String) : String;
Var
  Name      : String;
  Result    : String;
  Value     : String;
  Meaning   : String;
Begin
 Name:=InName(Line);
 If Error<>'' Then Exit;
 Line:=Trim(Line);
 If Name='REM' Then
 Begin
  If Line<>'' Then ParseRunLine:='Rem '+Line Else ParseRunLine:='Rem';
 end Else If Name='LABEL' Then ParseRunLine:='Label '+ParseCalculate(Line) Else
 If Name='OPEN' Then
 Begin
  Name:=ParseCalculate(Line);
  If Error<>'' Then Exit;
  Result:=InName(Line);
  If Error<>'' Then Exit;
  If Result<>'FOR' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Result:=InName(Line);
  If Error<>'' Then Exit;
  If (Result<>'INPUT') And (Result<>'OUTPUT') And (Result<>'APPEND') Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Value:=InName(Line);
  If Error<>'' Then Exit;
  If Value<>'AS' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>'#' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  If Result='INPUT' Then Result:='InPut';
  If Result='OUTPUT' Then Result:='OutPut';
  If Result='APPEND' Then Result:='Append';
  ParseRunLine:='Open '+Name+' For '+Result+' As #'+ParseCalculate(Line);
 end Else If Name='CLOSE' Then
 Begin
  If Copy(Line,1,1)<>'#' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  ParseRunLine:='Close #'+ParseCalculate(Line);
 end Else If Name='PRINT' Then
 Begin
  If Copy(Line,1,1)='#' Then
  Begin
   Delete(Line,1,1);
   Value:=ParseCalculate(Line);
   If Error<>'' Then Exit;
   Line:=Trim(Line);
   If Copy(Line,1,1)<>',' Then
   Begin
    Error:='Syntax error';
    Exit;
   end;
   Delete(Line,1,1);
   ParseRunLine:='Print #'+Value+','+ParseCalculate(Line);
  end Else ParseRunLine:='Print '+ParseCalculate(Line);
 end Else If Name='CLS' Then ParseRunLine:='Cls' Else If Name='COLOR' Then
 Begin
  Result:=ParseCalculate(Line);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>',' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  ParseRunLine:='Color '+Result+','+ParseCalculate(Line);
 end Else If Name='LOCATE' Then
 Begin
  Result:=ParseCalculate(Line);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>',' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  ParseRunLine:='Locate '+Result+','+ParseCalculate(Line);
 end Else If Name='SOUND' Then
 Begin
  Result:=ParseCalculate(Line);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>',' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  ParseRunLine:='Sound '+Result+','+ParseCalculate(Line);
 end Else If Name='NAME' Then
 Begin
  Result:=ParseCalculate(Line);
  If Error<>'' Then Exit;
  Value:=InName(Line);
  If Error<>'' Then Exit;
  If Value<>'AS' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  ParseRunLine:='Name '+Result+' As '+ParseCalculate(Line);
 end Else If Name='MKDIR' Then ParseRunLine:='MkDir '+ParseCalculate(Line) Else
 If Name='CHDIR' Then ParseRunLine:='ChDir '+ParseCalculate(Line) Else
 If Name='RMDIR' Then ParseRunLine:='RmDir '+ParseCalculate(Line) Else
 If Name='KILL' Then ParseRunLine:='Kill '+ParseCalculate(Line) Else
 If Name='FILES' Then ParseRunLine:='Files '+ParseCalculate(Line) Else
 If Name='WINDOW' Then
 Begin
  If Copy(Line,1,1)<>'(' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Name:=ParseCalculate(Line);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>',' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Result:=ParseCalculate(Line);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>')' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Line:=Trim(Line);
  If Copy(Line,1,1)<>'-' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Line:=Trim(Line);
  If Copy(Line,1,1)<>'(' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Value:=ParseCalculate(Line);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>',' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Meaning:=ParseCalculate(Line);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>')' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  ParseRunLine:='Window ('+Name+','+Result+')-('+Value+','+Meaning+')';
 end Else If Name='GO' Then
 Begin
  Name:=InName(Line);
  If Error<>'' Then Exit;
  If Name='TO' Then ParseRunLine:='Go To '+ParseCalculate(Line) Else
  If Name='SUB' Then ParseRunLine:='Go Sub '+ParseCalculate(Line) Else Error:='Syntax error';
 end Else If Name='RETURN' Then ParseRunLine:='Return' Else
 If Name='TRON' Then ParseRunLine:='TrOn' Else
 If Name='TROFF' Then ParseRunLine:='TrOff' Else
 If Name='END' Then ParseRunLine:='End' Else
 If Name='LET' Then
 Begin
  Result:=InName(Line);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Line='' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Case Line[1] Of
  '$':
   Begin
    Delete(Line,1,1);
    Result:=Result+'$';
   end;
  '!': Delete(Line,1,1);
  '@': Delete(Line,1,1);
  '#': Delete(Line,1,1);
  '%': Delete(Line,1,1);
  '&': Delete(Line,1,1);
  end;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>'=' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  ParseRunLine:='Let '+Result+'='+ParseCalculate(Line);
 end Else
 If Name='WHILE' Then ParseRunLine:='While '+ParseCalculate(Line) Else
 If Name='WEND' Then ParseRunLine:='WEnd' Else If Name='FROM' Then
 Begin
  Name:=InName(Line);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Line='' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Case Line[1] Of
  '$':
   Begin
    Error:='Variable type mismatch';
    Exit;
   end;
  '!': Delete(Line,1,1);
  '@': Delete(Line,1,1);
  '#': Delete(Line,1,1);
  '%': Delete(Line,1,1);
  '&': Delete(Line,1,1);
  end;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>'=' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Result:=ParseCalculate(Line);
  If Error<>'' Then Exit;
  Value:=InName(Line);
  If Error<>'' Then Exit;
  If Value<>'TO' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  ParseRunLine:='From '+Name+'='+Result+' To '+ParseCalculate(Line);
 end Else If Name='NEXT' Then
 Begin
  Name:=InName(Line);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Line<>'' Then
  Case Line[1] Of
  '$':
   Begin
    Error:='Variable type mismatch';
    Exit;
   end;
  '!': Delete(Line,1,1);
  '@': Delete(Line,1,1);
  '#': Delete(Line,1,1);
  '%': Delete(Line,1,1);
  '&': Delete(Line,1,1);
  end;
  ParseRunLine:='Next '+Name;
 end Else If Name='EXIT' Then
 Begin
  Name:=InName(Line);
  If Error<>'' Then Exit;
  If Name='WHILE' Then ParseRunLine:='Exit While' Else
  If Name='FROM' Then ParseRunLine:='Exit From' Else
  Error:='Syntax error';
 end Else If Name='IF' Then
 Begin
  Result:='If '+ParseCalculate(Line);
  If Error<>'' Then Exit;
  Name:=InName(Line);
  If Error<>'' Then Exit;
  If Name<>'THEN' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Result:=Result+' Then '+ParseRunLine(Line);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Line<>'' Then
  Begin
   Name:=InName(Line);
   If Error<>'' Then Exit;
   If Name<>'ELSE' Then
   Begin
    Error:='Syntax error';
    Exit;
   end;
   ParseRunLine:=Result+' Else '+ParseRunLine(Line);
  end Else ParseRunLine:=Result;
 end Else If Name='DEF' Then
 Begin
  Result:=InName(Line);
  If Error<>'' Then Exit;
  If Copy(Result,1,2)<>'FN' Then
  Begin
   Error:='User - defined function name must be beginning on FN';
   Exit;
  end;
  Line:=Trim(Line);
  Case Line[1] Of
  '$':
   Begin
    Delete(Line,1,1);
    Result:=Result+'$';
   end;
  '!': Delete(Line,1,1);
  '@': Delete(Line,1,1);
  '#': Delete(Line,1,1);
  '%': Delete(Line,1,1);
  '&': Delete(Line,1,1);
  end;
  Line:=Trim(Line);
  If Copy(Line,1,1)='(' Then
  Begin
   Delete(Line,1,1);
   Result:=Result+'(';
   Line:=Trim(Line);
   If Line='' Then
   Begin
    Error:='Syntax error';
    Exit;
   end;
   While Line<>'' Do
   Begin
    Name:=InName(Line);
    If Error<>'' Then Exit;
    Result:=Result+Name;
    Line:=Trim(Line);
    If Line='' Then
    Begin
     Error:='Syntax error';
     Exit;
    end;
    Case Line[1] Of
    '$':
     Begin
      Delete(Line,1,1);
      Result:=Result+'$';
     end;
    '!': Delete(Line,1,1);
    '@': Delete(Line,1,1);
    '#': Delete(Line,1,1);
    '%': Delete(Line,1,1);
    '&': Delete(Line,1,1);
    end;
    Line:=Trim(Line);
    If Line='' Then
    Begin
     Error:='Syntax error';
     Exit;
    end;
    Case Line[1] Of
    ')':
     Begin
      Delete(Line,1,1);
      Result:=Result+')';
      Line:=Trim(Line);
      Break;
     end;
    ',':
     Begin
      Delete(Line,1,1);
      Result:=Result+',';
     end;
    end;
   end;
  end;
  If Copy(Line,1,1)<>'=' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  ParseRunLine:='Def '+Result+'='+ParseCalculate(Line);
 end Else Error:='Unknown statement';
end;
Procedure RunLine(Var Line : String);
Var
  Name        : String;
  Result      : String;
  Value       : String;
  Meaning     : String;
  FromVarName : String;
  Number      : Real;
  Num         : Real;
  Find        : SearchRec;
  WorkFile    : Text;
  WorkDT      : DateTime;
  Index       : Word;
  SubIndex    : Word;
  WorkIndex   : Word;
  WhilesCount : Word;
  FromsCount  : Word;
  VarType     : Boolean;
  IfElse      : Boolean;
Begin
 Name:=InName(Line);
 If Error<>'' Then Exit;
 Line:=Trim(Line);
 If Name='REM' Then Exit Else
 If Name='LABEL' Then Exit Else
 If Name='OPEN' Then
 Begin
  Name:=Calculate(Line);
  If Error<>'' Then Exit;
  If Not NumStr Then
  Begin
   Error:='Type mismatch';
   Exit;
  end;
  Result:=InName(Line);
  If Error<>'' Then Exit;
  If Result<>'FOR' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Result:=InName(Line);
  If Error<>'' Then Exit;
  If (Result<>'INPUT') And (Result<>'OUTPUT') And (Result<>'APPEND') Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Value:=InName(Line);
  If Error<>'' Then Exit;
  If Value<>'AS' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>'#' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Value:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismatch';
   Exit;
  end;
  Number:=StringToNumber(Value);
  If Error<>'' Then Exit;
  If (Trunc(Number)<1) Or (Trunc(Number)>MaxFiles) Then
  Begin
   Error:='Invalid file number';
   Exit;
  end;
  If Files[Trunc(Number)].IsUse Then
  Begin
   Error:='File already open';
   Exit;
  end;
  If Result='INPUT' Then Files[Trunc(Number)].FileMode:=True Else Files[Trunc(Number)].FileMode:=False;
  Files[Trunc(Number)].IsUse:=True;
  Assign(Files[Trunc(Number)].WorkFile,Name);
  If Result='INPUT' Then ReSet(Files[Trunc(Number)].WorkFile) Else
  If Result='OUTPUT' Then ReWrite(Files[Trunc(Number)].WorkFile) Else
  If Result='APPEND' Then Append(Files[Trunc(Number)].WorkFile);
  If IOResult<>0 Then Error:='Cannot open file';
 end Else If Name='CLOSE' Then
 Begin
  If Copy(Line,1,1)<>'#' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismatch';
   Exit;
  end;
  Number:=StringToNumber(Result);
  If Error<>'' Then Exit;
  If (Trunc(Number)<1) Or (Trunc(Number)>MaxFiles) Then
  Begin
   Error:='Invalid file number';
   Exit;
  end;
  If Not Files[Trunc(Number)].IsUse Then
  Begin
   Error:='File already closed';
   Exit;
  end;
  Files[Trunc(Number)].FileMode:=False;
  Files[Trunc(Number)].IsUse:=False;
  Close(Files[Trunc(Number)].WorkFile);
  If IOResult<>0 Then Error:='Cannot close file';
 end Else If Name='PRINT' Then
 Begin
  If Copy(Line,1,1)='#' Then
  Begin
   Delete(Line,1,1);
   Value:=Calculate(Line);
   If Error<>'' Then Exit;
   If NumStr Then
   Begin
    Error:='Type mismatch';
    Exit;
   end;
   Number:=StringToNumber(Value);
   If Error<>'' Then Exit;
   If (Trunc(Number)<1) Or (Trunc(Number)>MaxFiles) Then
   Begin
    Error:='Invalid file number';
    Exit;
   end;
   If Not Files[Trunc(Number)].IsUse Then
   Begin
    Error:='Invalid file number';
    Exit;
   end;
   If Files[Trunc(Number)].FileMode Then
   Begin
    Error:='Bad file mode';
    Exit;
   end;
   Line:=Trim(Line);
   If Copy(Line,1,1)<>',' Then
   Begin
    Error:='Syntax error';
    Exit;
   end;
   Delete(Line,1,1);
   Result:=Calculate(Line);
   If Error<>'' Then Exit;
   WriteLn(Files[Trunc(Number)].WorkFile,Result);
   If IOResult<>0 Then Error:='Cannot write to file';
  end Else
  Begin
   Result:=Calculate(Line);
   If Error<>'' Then Exit;
   WriteANSILine(Result+Chr(13)+Chr(10));
  end;
 end Else If Name='CLS' Then ClrScr Else If Name='COLOR' Then
 Begin
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismacth';
   Exit;
  end;
  Number:=StringToNumber(Result);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>',' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismacth';
   Exit;
  end;
  Num:=StringToNumber(Result);
  If Error<>'' Then Exit;
  TextBackGround(Trunc(Number));
  TextColor(Trunc(Num));
 end Else If Name='LOCATE' Then
 Begin
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismacth';
   Exit;
  end;
  Number:=StringToNumber(Result);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>',' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismacth';
   Exit;
  end;
  Num:=StringToNumber(Result);
  If Error<>'' Then Exit;
  GoToXY(Trunc(Number),Trunc(Num));
 end Else If Name='SOUND' Then
 Begin
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismacth';
   Exit;
  end;
  Number:=StringToNumber(Result);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>',' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismacth';
   Exit;
  end;
  Num:=StringToNumber(Result);
  If Error<>'' Then Exit;
  Sound(Trunc(Number));
  Delay(Trunc(Num));
  NoSound;
 end Else If Name='NAME' Then
 Begin
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If Not NumStr Then
  Begin
   Error:='Type mismatch';
   Exit;
  end;
  Value:=InName(Line);
  If Error<>'' Then Exit;
  If Value<>'AS' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Value:=Calculate(Line);
  If Error<>'' Then Exit;
  If Not NumStr Then
  Begin
   Error:='Type mismatch';
   Exit;
  end;
  Assign(WorkFile,Result);
  Rename(WorkFile,Value);
  If IOResult<>0 Then Error:='Cannot rename file';
 end Else If Name='MKDIR' Then
 Begin
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If Not NumStr Then
  Begin
   Error:='Type mismacth';
   Exit;
  end;
  MkDir(Result);
  If IOResult<>0 Then Error:='Cannot make directory';
 end Else If Name='CHDIR' Then
 Begin
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If Not NumStr Then
  Begin
   Error:='Type mismacth';
   Exit;
  end;
  ChDir(Result);
  If IOResult<>0 Then Error:='Cannot change directory';
 end Else If Name='RMDIR' Then
 Begin
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If Not NumStr Then
  Begin
   Error:='Type mismacth';
   Exit;
  end;
  RmDir(Result);
  If IOResult<>0 Then Error:='Cannot remove directory';
 end Else If Name='KILL' Then
 Begin
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If Not NumStr Then
  Begin
   Error:='Type mismacth';
   Exit;
  end;
  FindFirst(Result,AnyFile,Find);
  If DosError=18 Then
  Begin
   Error:='File not found';
   Exit;
  end;
  Repeat
   Assign(WorkFile,Find.Name);
   Erase(WorkFile);
   If IOResult<>0 Then
   Begin
    Error:='Cannot delete file';
    Exit;
   end;
   FindNext(Find);
  Until DosError=18;
 end Else If Name='FILES' Then
 Begin
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If Not NumStr Then
  Begin
   Error:='Type mismacth';
   Exit;
  end;
  FindFirst(Result,AnyFile,Find);
  If DosError=18 Then
  Begin
   Error:='File not found';
   Exit;
  end;
  WriteLn('Name.        Size.      Date.           Time.    Attribute.');
  Number:=0.0;
  Repeat
   Number:=Number+Find.Size;
   Result:=Find.Name;
   While Length(Result)<13 Do Result:=Result+' ';
   Value:=NumberToString(Find.Size);
   While Length(Value)<10 Do Value:=' '+Value;
   Result:=Result+Value+' ';
   UnPackTime(Find.Time,WorkDT);
   Case DayOfWeek(WorkDT.Year,WorkDT.Month,WorkDT.Day) Of
   1: Result:=Result+'Mon';
   2: Result:=Result+'Tue';
   3: Result:=Result+'Wed';
   4: Result:=Result+'Thu';
   5: Result:=Result+'Fri';
   6: Result:=Result+'Sat';
   7: Result:=Result+'Sun';
   end;
   Value:=NumberToString(WorkDT.Day);
   If Length(Value)<2 Then Value:=' '+Value;
   Result:=Result+' '+Value+' ';
   Case WorkDT.Month Of
    1: Result:=Result+'Jan';
    2: Result:=Result+'Feb';
    3: Result:=Result+'Mar';
    4: Result:=Result+'Apr';
    5: Result:=Result+'May';
    6: Result:=Result+'Jun';
    7: Result:=Result+'Jul';
    8: Result:=Result+'Aug';
    9: Result:=Result+'Sep';
   10: Result:=Result+'Oct';
   11: Result:=Result+'Nov';
   12: Result:=Result+'Dec';
   end;
   Result:=Result+' '+NumberToString(WorkDT.Year)+' ';
   Value:=NumberToString(WorkDT.Hour);
   If Length(Value)<2 Then Value:='0'+Value;
   Result:=Result+Value+':';
   Value:=NumberToString(WorkDT.Min);
   If Length(Value)<2 Then Value:='0'+Value;
   Result:=Result+Value+':';
   Value:=NumberToString(WorkDT.Sec);
   If Length(Value)<2 Then Value:='0'+Value;
   Result:=Result+Value+' ';
   If (Find.Attr And ReadOnly)<>0 Then Value:='R' Else Value:=' ';
   If (Find.Attr And Hidden)<>0 Then Value:=Value+'H' Else Value:=Value+' ';
   If (Find.Attr And SysFile)<>0 Then Value:=Value+'S' Else Value:=Value+' ';
   If (Find.Attr And VolumeID)<>0 Then Value:=Value+'V' Else Value:=Value+' ';
   If (Find.Attr And Directory)<>0 Then Value:=Value+'D' Else Value:=Value+' ';
   If (Find.Attr And Archive)<>0 Then Value:=Value+'A' Else Value:=Value+' ';
   WriteLn(Result+Value);
   FindNext(Find);
  Until DosError=18;
  WriteLn('    Total size of files: '+NumberToString(Number)+' bytes.');
  WriteLn('      Current disk size: '+NumberToString(DiskSize(0))+' bytes.');
  WriteLn('Current disk free space: '+NumberToString(DiskFree(0))+' bytes.');
 end Else If Name='WINDOW' Then
 Begin
  If Copy(Line,1,1)<>'(' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Name:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismacth';
   Exit;
  end;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>',' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismacth';
   Exit;
  end;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>')' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Line:=Trim(Line);
  If Copy(Line,1,1)<>'-' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Line:=Trim(Line);
  If Copy(Line,1,1)<>'(' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Value:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismacth';
   Exit;
  end;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>',' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Meaning:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismacth';
   Exit;
  end;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>')' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Window(Trunc(StringToNumber(Name)),Trunc(StringToNumber(Result)),Trunc(StringToNumber(Value)),
  Trunc(StringToNumber(Meaning)));
 end Else If Name='GO' Then
 Begin
  If Not RunMode Then
  Begin
   Error:='Cannot execute GO TO or GO SUB statement without program running';
   Exit;
  end;
  Name:=InName(Line);
  If Error<>'' Then Exit;
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr Then Index:=FindLine(0,Result,True) Else Index:=FindLine(Trunc(StringToNumber(Result)),'',False);
  If Error<>'' Then Exit;
  If Name='TO' Then CurrentLine:=Index-1 Else If Name='SUB' Then
  Begin
   If GoSubSCount=MaxGoSubS Then
   Begin
    Error:='Too many GO SUB''s';
    Exit;
   end;
   Inc(GoSubSCount);
   GoSubS[GoSubSCount]:=CurrentLine;
   CurrentLine:=Index-1;
  end Else Error:='Syntax error';
 end Else If Name='RETURN' Then
 Begin
  If Not RunMode Then
  Begin
   Error:='Cannot execute RETURN statement without program running';
   Exit;
  end;
  If GoSubSCount=0 Then
  Begin
   Error:='RETURN without GO SUB';
   Exit;
  end;
  CurrentLine:=GoSubS[GoSubSCount];
  GoSubS[GoSubSCount]:=0;
  Dec(GoSubSCount);
 end Else If Name='TRON' Then
 Begin
  TraceMode:=True;
  WriteLn('Trace mode is on.');
 end Else If Name='TROFF' Then
 Begin
  TraceMode:=False;
  WriteLn('Trace mode is off.');
 end Else If Name='END' Then
 Begin
  If Not RunMode Then
  Begin
   Error:='Cannot end not running program';
   Exit;
  end;
  RunMode:=False;
 end Else If Name='DEF' Then
 Begin
  If DefFnSCount=MaxDefFnS Then
  Begin
   Error:='Too many user - defined functions';
   Exit;
  end;
  Inc(DefFnSCount);
  Result:=InName(Line);
  If Error<>'' Then Exit;
  If Copy(Result,1,2)<>'FN' Then
  Begin
   Error:='User - defined function name must be beginning on FN';
   Exit;
  end;
  Line:=Trim(Line);
  Case Line[1] Of
  '$':
   Begin
    Delete(Line,1,1);
    Result:=Result+'$';
   end;
  '!': Delete(Line,1,1);
  '@': Delete(Line,1,1);
  '#': Delete(Line,1,1);
  '%': Delete(Line,1,1);
  '&': Delete(Line,1,1);
  end;
  Line:=Trim(Line);
  If Copy(Line,1,1)='(' Then
  Begin
   Delete(Line,1,1);
   Result:=Result+'(';
   Line:=Trim(Line);
   If Line='' Then
   Begin
    Error:='Syntax error';
    Exit;
   end;
   While Line<>'' Do
   Begin
    Name:=InName(Line);
    If Error<>'' Then Exit;
    Result:=Result+Name;
    Line:=Trim(Line);
    If Line='' Then
    Begin
     Error:='Syntax error';
     Exit;
    end;
    Case Line[1] Of
    '$':
     Begin
      Delete(Line,1,1);
      Result:=Result+'$';
     end;
    '!': Delete(Line,1,1);
    '@': Delete(Line,1,1);
    '#': Delete(Line,1,1);
    '%': Delete(Line,1,1);
    '&': Delete(Line,1,1);
    end;
    Line:=Trim(Line);
    If Line='' Then
    Begin
     Error:='Syntax error';
     Exit;
    end;
    Case Line[1] Of
    ')':
     Begin
      Delete(Line,1,1);
      Result:=Result+')';
      Line:=Trim(Line);
      Break;
     end;
    ',':
     Begin
      Delete(Line,1,1);
      Result:=Result+',';
     end;
    end;
   end;
  end;
  If Copy(Line,1,1)<>'=' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  DefFnS[DefFnSCount]:=Result+'='+ParseCalculate(Line);
 end Else If Name='LET' Then
 Begin
  Name:=InName(Line);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Line='' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  VarType:=False;
  Case Line[1] Of
  '$':
   Begin
    Delete(Line,1,1);
    VarType:=True;
   end;
  '!': Delete(Line,1,1);
  '@': Delete(Line,1,1);
  '#': Delete(Line,1,1);
  '%': Delete(Line,1,1);
  '&': Delete(Line,1,1);
  end;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>'=' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr<>VarType Then
  Begin
   Error:='Type mismatch';
   Exit;
  end;
  SetVar(Name,VarType,Result);
 end Else If Name='WHILE' Then
 Begin
  If Not RunMode Then
  Begin
   Error:='Cannot execute WHILE loop without program running';
   Exit;
  end;
  For Index:=1 To MaxWhiles+1 Do
  Begin
   If Index=MaxWhiles+1 Then
   Begin
    Error:='Too many WHILE''s';
    Exit;
   end;
   If Whiles[Index].IsFree Then Break;
  end;
  WhilesCount:=0;
  For SubIndex:=CurrentLine+1 To TextLinesCount+1 Do
  Begin
   If SubIndex=TextLinesCount+1 Then
   Begin
    Error:='WHILE without WEND';
    Exit;
   end;
   If Trim(TextLines[SubIndex])<>'' Then
   Begin
    Value:=Trim(TextLines[SubIndex]);
    Case UpCase(Value[1]) Of
    '0'..'9':
     Begin
      Number:=InNumber(Value);
      If Error<>'' Then Exit;
      Name:=InName(Value);
      If Error<>'' Then Exit;
      If Name='WHILE' Then Inc(WhilesCount) Else
      If Name='WEND' Then If WhilesCount=0 Then Break Else Dec(WhilesCount);
     end;
    'A'..'Z':
     Begin
      Name:=InName(Value);
      If Error<>'' Then Exit;
      If Name='WHILE' Then Inc(WhilesCount) Else
      If Name='WEND' Then If WhilesCount=0 Then Break Else Dec(WhilesCount);
     end;
    Else
     Begin
      Error:='Invalid line';
      Exit;
     end;
    end;
   end;
  end;
  If Line='' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Value:=Line;
  Value:=Calculate(Value);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismatch';
   Exit;
  end;
  If StringToNumber(Value)<>0.0 Then
  Begin
   Whiles[Index].StartLine:=CurrentLine;
   Whiles[Index].EndLine:=SubIndex;
   Whiles[Index].Conditional:=ParseCalculate(Line);
   If Error<>'' Then Exit;
   Whiles[Index].IsFree:=False;
  end Else CurrentLine:=SubIndex;
 end Else If Name='WEND' Then
 Begin
  If Not RunMode Then
  Begin
   Error:='Cannot execute WHILE loop without program running';
   Exit;
  end;
  For Index:=1 To MaxWhiles+1 Do
  Begin
   If Index=MaxWhiles+1 Then
   Begin
    Error:='WEND without WHILE';
    Exit;
   end;
   If Not Whiles[Index].IsFree Then If Whiles[Index].EndLine=CurrentLine Then Break;
  end;
  Value:=Whiles[Index].Conditional;
  Value:=Calculate(Value);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismatch';
   Exit;
  end;
  If StringToNumber(Value)<>0.0 Then CurrentLine:=Whiles[Index].StartLine Else
  Begin
   Whiles[Index].StartLine:=0;
   Whiles[Index].EndLine:=0;
   Whiles[Index].Conditional:='';
   Whiles[Index].IsFree:=True;
  end;
 end Else If Name='FROM' Then
 Begin
  If Not RunMode Then
  Begin
   Error:='Cannot execute the FROM loop without program running';
   Exit;
  end;
  FromVarName:=InName(Line);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Line='' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Case Line[1] Of
  '$':
   Begin
    Error:='Variable type mismatch';
    Exit;
   end;
  '!': Delete(Line,1,1);
  '@': Delete(Line,1,1);
  '#': Delete(Line,1,1);
  '%': Delete(Line,1,1);
  '&': Delete(Line,1,1);
  end;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>'=' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismatch';
   Exit;
  end;
  Value:=InName(Line);
  If Error<>'' Then Exit;
  If Value<>'TO' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Value:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismatch';
   Exit;
  end;
  For Index:=1 To MaxFroms+1 Do
  Begin
   If Index=MaxFroms+1 Then
   Begin
    Error:='Too many FROM''s';
    Exit;
   end;
   If Froms[Index].IsFree Then Break;
  end;
  FromsCount:=0;
  For SubIndex:=CurrentLine+1 To TextLinesCount+1 Do
  Begin
   If SubIndex=TextLinesCount+1 Then
   Begin
    Error:='FROM without NEXT';
    Exit;
   end;
   If Trim(TextLines[SubIndex])<>'' Then
   Begin
    Name:=Trim(TextLines[SubIndex]);
    Case UpCase(Name[1]) Of
    '0'..'9':
     Begin
      Number:=InNumber(Name);
      If Error<>'' Then Exit;
      Meaning:=InName(Name);
      If Error<>'' Then Exit;
      If Meaning='FROM' Then Inc(FromsCount) Else
      If Meaning='NEXT' Then
      Begin
       Meaning:=InName(Name);
       If Error<>'' Then Exit;
       If (FromsCount=0) And (Meaning=FromVarName) Then Break Else Dec(FromsCount);
      end;
     end;
    'A'..'Z':
     Begin
      Meaning:=InName(Name);
      If Error<>'' Then Exit;
      If Meaning='FROM' Then Inc(FromsCount) Else
      If Meaning='NEXT' Then
      Begin
       Meaning:=InName(Name);
       If Error<>'' Then Exit;
       If (FromsCount=0) And (Meaning=FromVarName) Then Break Else Dec(FromsCount);
      end;
     end;
    Else
     Begin
      Error:='Invalid line';
      Exit;
     end;
    end;
   end;
  end;
  If StringToNumber(Value)>=StringToNumber(Result) Then
  Begin
   Froms[Index].VarName:=FromVarName;
   Froms[Index].StartLine:=CurrentLine;
   Froms[Index].EndLine:=SubIndex;
   Froms[Index].BeginValue:=Trunc(StringToNumber(Result));
   Froms[Index].EndValue:=Trunc(StringToNumber(Value));
   Froms[Index].IsFree:=False;
   SetVar(FromVarName,False,Result);
  end Else CurrentLine:=SubIndex;
 end Else If Name='NEXT' Then
 Begin
  If Not RunMode Then
  Begin
   Error:='Cannot execute the FROM loop without program running';
   Exit;
  end;
  FromVarName:=InName(Line);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Line<>'' Then
  Case Line[1] Of
  '$':
   Begin
    Error:='Variable type mismatch';
    Exit;
   end;
  '!': Delete(Line,1,1);
  '@': Delete(Line,1,1);
  '#': Delete(Line,1,1);
  '%': Delete(Line,1,1);
  '&': Delete(Line,1,1);
  end;
  For Index:=1 To MaxFroms+1 Do
  Begin
   If Index=MaxFroms+1 Then
   Begin
    Error:='NEXT without FROM';
    Exit;
   end;
   If Not Froms[Index].IsFree Then If (Froms[Index].EndLine=CurrentLine) And (Froms[Index].VarName=FromVarName) Then Break;
  end;
  Result:=InVar(FromVarName,False);
  If StringToNumber(Result)=Froms[Index].EndValue Then
  Begin
   Froms[Index].VarName:='';
   Froms[Index].StartLine:=0;
   Froms[Index].EndLine:=0;
   Froms[Index].BeginValue:=0;
   Froms[Index].EndValue:=0;
   Froms[Index].IsFree:=True;
  end Else
  Begin
   SetVar(FromVarName,False,NumberToString(StringToNumber(Result)+1));
   CurrentLine:=Froms[Index].StartLine;
  end;
 end Else If Name='EXIT' Then
 Begin
  If Not RunMode Then
  Begin
   Error:='Cannot EXIT from loop without program is running';
   Exit;
  end;
  Name:=InName(Line);
  If Error<>'' Then Exit;
  If Name='WHILE' Then
  Begin
   For Index:=1 To MaxWhiles+1 Do
   Begin
    If Index=MaxWhiles+1 Then
    Begin
     Error:='EXIT WHILE without WHILE';
     Exit;
    end;
    If Not Whiles[Index].IsFree Then
    If (CurrentLine>=Whiles[Index].StartLine) And (CurrentLine<=Whiles[Index].EndLine) Then Break;
   end;
   CurrentLine:=Whiles[Index].EndLine;
   Whiles[Index].StartLine:=0;
   Whiles[Index].EndLine:=0;
   Whiles[Index].Conditional:='';
   Whiles[Index].IsFree:=True;
  end Else If Name='FROM' Then
  Begin
   For Index:=1 To MaxFroms+1 Do
   Begin
    If Index=MaxFroms+1 Then
    Begin
     Error:='EXIT FROM without FROM';
     Exit;
    end;
    If Not Froms[Index].IsFree Then
    If (CurrentLine<=Froms[Index].StartLine) And (CurrentLine>=Froms[Index].EndLine)
    And (Froms[Index].VarName=FromVarName) Then Break;
   end;
   CurrentLine:=Froms[Index].EndLine;
   Froms[Index].VarName:='';
   Froms[Index].StartLine:=0;
   Froms[Index].EndLine:=0;
   Froms[Index].BeginValue:=0;
   Froms[Index].EndValue:=0;
   Froms[Index].IsFree:=True;
  end Else Error:='Syntax error';
 end Else If Name='IF' Then
 Begin
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismatch';
   Exit;
  end;
  Value:=InName(Line);
  If Error<>'' Then Exit;
  If Value<>'THEN' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Name:=ParseRunLine(Line);
  If Error<>'' Then Exit;
  IfElse:=False;
  Line:=Trim(Line);
  If Line<>'' Then
  Begin
   IfElse:=True;
   Value:=InName(Line);
   If Error<>'' Then Exit;
   If Value<>'ELSE' Then
   Begin
    Error:='Syntax error';
    Exit;
   end;
   Meaning:=ParseRunLine(Line);
   If Error<>'' Then Exit;
  end;
  If StringToNumber(Result)<>0.0 Then RunLine(Name) Else If IfElse Then RunLine(Meaning);
 end Else Error:='Unknown statement';
end;
Procedure MakeBox(Column,Row,Width,Height : Byte; Title,Status : String);
Var
  Index : Byte;
Begin
 Window(Column,Row,(Column-1)+Width,(Row-1)+Height);
 TextBackGround(LightGray);
 TextColor(Black);
 ClrScr;
 Window(Column,Row,(Column-1)+Width,Row+Height);
 Write('É');
 For Index:=1 To Width-2 Do Write('Í');
 Write('»');
 For Index:=2 To Height-1 Do
 Begin
  GoToXY(1,Index);
  Write('º');
  GoToXY(Width,Index);
  Write('º');
 end;
 Write('È');
 For Index:=1 To Width-2 Do Write('Í');
 Write('¼');
 Window(Column+1,Row+1,(Column-1)+(Width-1),(Row-1)+(Height-2));
 TextColor(Red);
 Write(Copy(Title,1,Width-2));
 Window(Column+1,(Row-1)+(Height-1),(Column-1)+(Width-1),(Row-1)+(Height-1));
 TextColor(Yellow);
 Window(Column+1,(Row-1)+(Height-1),(Column-1)+(Width-1),(Row-1)+Height);
 GoToXY((((Width-2)-Length(Copy(Status,1,Width-2))) Div 2)+1,1);
 Write(Copy(Status,1,Width-2));
 Window(Column+1,Row+2,(Column-1)+(Width-1),(Row-1)+(Height-2));
 TextColor(Blue);
end;
Function MessageBox(Title,Message : String) : Boolean;
Var
  Msg : String;
Begin
 MakeBox(14,8,53,10,Title,'ENTER=Yes,ESC=No.');
 Msg:=Message;
 While Length(Msg)<250 Do Msg:=Msg+' ';
 Write(Msg);
 GoToXY(1,1);
 Repeat
  Case ReadKey Of
  #13:
   Begin
    MessageBox:=True;
    Break;
   end;
  #27:
   Begin
    MessageBox:=False;
    Break;
   end;
  end;
 Until False;
end;
Procedure OutBox(Title,Message : String);
Var
  Msg : String;
Begin
 MakeBox(14,8,53,10,Title,'ENTER=Quit.');
 Msg:=Message;
 While Length(Msg)<255 Do Msg:=Msg+' ';
 Write(Msg);
 GoToXY(1,1);
 Repeat
 Until ReadKey=#13;
end;
Function InputBox(Title,Message : String; Var InputLine : String) : Boolean;
Var
  Msg              : String;
  WorkLine         : String;
  WorkCursorColumn : Integer;
  WorkLinePosition : Integer;
  WorkKey          : Char;
 Procedure WriteLine;
 Begin
  ClrScr;
  Window(15,15,65,16);
  Write(Copy(WorkLine,(WorkCursorColumn-WorkLinePosition)+1,51));
  Window(15,15,65,15);
  GoToXY(WorkLinePosition,1);
 end;
 Procedure WorkControl;
 Begin
  If WorkCursorColumn<1 Then WorkCursorColumn:=1;
  If WorkLinePosition<1 Then WorkLinePosition:=1;
  If WorkCursorColumn>Length(WorkLine)+1 Then WorkCursorColumn:=Length(WorkLine)+1;
  If Length(WorkLine)<52 Then If WorkLinePosition>Length(WorkLine)+1 Then WorkLinePosition:=Length(WorkLine)+1;
  If Length(WorkLine)>50 Then If WorkLinePosition>51 Then WorkLinePosition:=51;
  WriteLine;
 end;
 Procedure WorkCursorLeft;
 Begin
  Dec(WorkCursorColumn);
  Dec(WorkLinePosition);
  WorkControl;
 end;
 Procedure WorkCursorRight;
 Begin
  Inc(WorkCursorColumn);
  Inc(WorkLinePosition);
  WorkControl;
 end;
Begin
 MakeBox(14,8,53,10,Title,'ENTER=Yes,ESC=No.');
 Msg:=Message;
 While Length(Msg)<255 Do Msg:=Msg+' ';
 Write(Msg);
 Window(15,15,65,15);
 TextColor(Green);
 WorkLine:=InputLine;
 WorkCursorColumn:=1;
 WorkLinePosition:=1;
 WriteLine;
 Repeat
  WorkKey:=ReadKey;
  Case WorkKey Of
  #0:
   Case ReadKey Of
   #75: WorkCursorLeft;
   #77: WorkCursorRight;
   #71:
    Begin
     WorkCursorColumn:=1;
     WorkLinePosition:=1;
     WriteLine;
    end;
   #79:
    Begin
     WorkCursorColumn:=Length(WorkLine)+1;
     WorkLinePosition:=WorkCursorColumn;
     WorkControl;
    end;
   #83:
    Begin
     Delete(WorkLine,WorkCursorColumn,1);
     WorkControl;
    end;
   end;
  #8:
   If WorkCursorColumn>1 Then
   Begin
    WorkCursorLeft;
    Delete(WorkLine,WorkCursorColumn,1);
    WriteLine;
   end;
  #13:
   Begin
    InputBox:=True;
    InputLine:=WorkLine;
    Break;
   end;
  #27:
   Begin
    InputBox:=False;
    Break;
   end;
  Else If (Length(WorkLine)<255) And (Ord(WorkKey)>31) Then
   Begin
    Insert(WorkKey,WorkLine,WorkCursorColumn);
    WorkCursorRight;
   end;
  end;
 Until False;
end;
Procedure GNUBasicHelp;
 Function Pause : Boolean;
 Begin
  Write('Please press the ENTER key to continue or ESC to cancel.');
  Pause:=ReadKey=Chr(13);
  WriteLn;
 end;
Begin
 WriteLn;
 WriteLn('The personal interpretter of the BASIC programming language.');
 WriteLn('GNUBasic, Copyright (C) 2003 Sandul Yura Valentinovich.');
 WriteLn('(C) Monday, 3 March 2003 year.');
 WriteLn('All rights reserved.');
 WriteLn('GNUBasic comes with ABSOLUTELY NO WARRANTY; for details, see the GNU General');
 WriteLn('Public License, version 2.');
 WriteLn('    This is free software, and you are welcome to redistribute it under certain');
 WriteLn('conditions from the GNU General Public License.');
 WriteLn('***************************************************************');
 WriteLn;
 WriteLn('Statements:');
 WriteLn('        REM [Any symbols combination.]');
 WriteLn('        Insert comment to program.');
 WriteLn('        OPEN FileName$ FOR INPUT|OUTPUT|APPEND AS #FileNumber%');
 WriteLn('        Open file for work with it.');
 WriteLn('        CLOSE #FileNumber%');
 WriteLn('        Close file.');
 WriteLn('        PRINT [#FileNumber%,]Expression');
 WriteLn('        Output to file or screen.');
 WriteLn('        CLS');
 WriteLn('        Clear the screen.');
 WriteLn('        COLOR BackGroundColor%,ForeGroundColor%');
 WriteLn('        Set screen color.');
 If Not Pause Then Exit;
 WriteLn('        LOCATE Column%,Row%');
 WriteLn('        Move screen cursor.');
 WriteLn('        SOUND Frequency%,Duration%');
 WriteLn('        Play sound (duration set in miliseconds (1/1000 of second)).');
 WriteLn('        NAME FileName$ AS NewFileName$');
 WriteLn('        Rename file.');
 WriteLn('        MKDIR DirectoryName$');
 WriteLn('        Create directory.');
 WriteLn('        CHDIR DirectoryName$');
 WriteLn('        Change current directory.');
 WriteLn('        RMDIR DirectoryName$');
 WriteLn('        Remove directory.');
 WriteLn('        KILL FileMask$');
 WriteLn('        Delete files.');
 WriteLn('        FILES FileMask$');
 WriteLn('        Out files.');
 WriteLn('        SYSTEM');
 WriteLn('        Quit from interpretter.');
 WriteLn('        WINDOW (UpperColumn%,UpperRow%)-(LowerColumn%,LowerRow%)');
 WriteLn('        Redirect scree to window.');
 WriteLn('        LIST [LineNumber%[,EndLineNumber%]]');
 WriteLn('        Output program lines.');
 WriteLn('        DELETE LineNumber%[,EndLineNumber%]');
 WriteLn('        Delete program lines.');
 If Not Pause Then Exit;
 WriteLn('        SAVE FileName$');
 WriteLn('        Save current program into file.');
 WriteLn('        LOAD FileName$');
 WriteLn('        Load program from file.');
 WriteLn('        NEW');
 WriteLn('        Clear current program and reset interpretter.');
 WriteLn('        GO TO|SUB LineNumber%');
 WriteLn('        Run GO TO or GO SUB statement.');
 WriteLn('        RETURN');
 WriteLn('        Return from GO SUB subroutine.');
 WriteLn('        TRON');
 WriteLn('        Set trace mode to on.');
 WriteLn('        TROFF');
 WriteLn('        Set trace mode to off.');
 WriteLn('        RUN');
 WriteLn('        Run current program.');
 WriteLn('        END');
 WriteLn('        End current running program.');
 WriteLn('        LET VarName=Expression');
 WriteLn('        Set value for variable.');
 WriteLn('        WHILE Conditional');
 WriteLn('        WEND');
 WriteLn('        The WHILE loop.');
 WriteLn('        FROM VarName%=StartValue% TO EndValue%');
 If Not Pause Then Exit;
 WriteLn('        NEXT VarName%');
 WriteLn('        The FROM (like FOR) loop.');
 WriteLn('        EXIT WHILE|FROM');
 WriteLn('        Exit from current WHILE or FROM loop.');
 WriteLn('        IF Conditional THEN Statement[ ELSE Statement]');
 WriteLn('        The IF conditional operator.');
 WriteLn('        DEF FNName[(Arg[,Arg...])]=Expression');
 WriteLn('        Declare the user - defined function.');
 WriteLn('        HELP');
 WriteLn('        Output this help screen.');
 WriteLn('        SCREEN BW40|CO40|BW80|CO80|MONO');
 WriteLn('        Change screen mode.');
 WriteLn('System variables:');
 WriteLn('        DATE$');
 WriteLn('        Contain current date in format: MM-DD-YYYY.');
 WriteLn('        TIME$');
 WriteLn('        Contain current time in format: HH:MM:SS.');
 WriteLn('String functions:');
 WriteLn('        INKEY$');
 WriteLn('        If pressed any alphabetic or numeric key, then return it (one symbol');
 WriteLn('        length string). If pressed special keys (like F1 - F10), then return');
 WriteLn('        two - symbols string: CHR$(0)+CHR$(CodeOfKey%). If keys is not');
 WriteLn('        pressed, then return empty string.');
 WriteLn('        INPUT$[(#FileNumber%)]');
 If Not Pause Then Exit;
 WriteLn('        Perform input from keyboard or file.');
 WriteLn('        STR$(Value%)');
 WriteLn('        Number, converted to string.');
 WriteLn('        CHR$(Code%)');
 WriteLn('        Symbol on code.');
 WriteLn('        MID$(Line$,Start%,Count%)');
 WriteLn('        Part of Line$, startted on Start% symbol, length Count% symbols.');
 WriteLn('        DAYOFWEEK(Year%,Month%,Day%)');
 WriteLn('        Return name of day.');
 WriteLn('Numeric functions:');
 WriteLn('        LEN(Line$)');
 WriteLn('        Return length of line.');
 WriteLn('        INSTR(Line$,SubLine$)');
 WriteLn('        Return number of first occurence of SubLine$ in Line$.');
 WriteLn('        ASC(Line$)');
 WriteLn('        Return code of first symbol in line.');
 WriteLn('        CRC32(Line$)');
 WriteLn('        Return CRC-32 code of line.');
 WriteLn('        VAL(Value$)');
 WriteLn('        Convert string number to number.');
 WriteLn('        SQR(Value#)');
 WriteLn('        Return the square root of value.');
 WriteLn('        ABS(Value#)');
 WriteLn('        Return absolute value of Value#.');
 If Not Pause Then Exit;
 WriteLn('        INT(Value#)');
 WriteLn('        Return integer part of Value#.');
 WriteLn('        SIN(Value#)');
 WriteLn('        Return sine of Value#.');
 WriteLn('        COS(Value#)');
 WriteLn('        Return co - sine of Value#.');
 WriteLn('        EOF(#FileNumber%)');
 WriteLn('        If EOF, then return 1 (true), else return 0 (false).');
 WriteLn('Constans:');
 WriteLn('        PI=3.1415926535897932385,BLACK=0,BLUE=1,GREEN=2,CYAN=3,RED=4,MAGENTA=5');
 WriteLn('        BROWN=6,LIGHTGRAY=7,DARKGRAY=8,LIGHTBLUE=9,LIGHTGREEN=10,LIGHTCYAN=11');
 WriteLn('        LIGHTRED=12,LIGHTMAGENTA=13,YELLOW=14,WHITE=15,FALSE=0,TRUE=1');
 WriteLn('Operators:');
 WriteLn('        Value[!|@|#|$|%|&]      +       Value[!|@|#|$|%|&]');
 WriteLn('        Value[!|@|#|%|&]        -       Value[!|@|#|%|&]');
 WriteLn('        Value[!|@|#|%|&]        /       Value[!|@|#|%|&]');
 WriteLn('        Value[!|@|#|%|&]        \       Value[!|@|#|%|&]');
 WriteLn('        Value[!|@|#|%|&]        *       Value[!|@|#|%|&]');
 WriteLn('        Value[!|@|#|$|%|&]      =       Value[!|@|#|$|%|&]');
 WriteLn('        Value[!|@|#|$|%|&]      <       Value[!|@|#|$|%|&]');
 WriteLn('        Value[!|@|#|$|%|&]      >       Value[!|@|#|$|%|&]');
 WriteLn('        Value[!|@|#|$|%|&]      <=      Value[!|@|#|$|%|&]');
 WriteLn('        Value[!|@|#|$|%|&]      =<      Value[!|@|#|$|%|&]');
 WriteLn('        Value[!|@|#|$|%|&]      =>      Value[!|@|#|$|%|&]');
 If Not Pause Then Exit;
 WriteLn('        Value[!|@|#|$|%|&]      >=      Value[!|@|#|$|%|&]');
 WriteLn('        Value[!|@|#|$|%|&]      <>      Value[!|@|#|$|%|&]');
 WriteLn('        Value[!|@|#|$|%|&]      ><      Value[!|@|#|$|%|&]');
 WriteLn('        Value[!|@|#|%|&]        AND     Value[!|@|#|%|&]');
 WriteLn('        Value[!|@|#|%|&]        OR      Value[!|@|#|%|&]');
 WriteLn('        Value[!|@|#|%|&]        XOR     Value[!|@|#|%|&]');
 WriteLn('        Value[!|@|#|%|&]        MOD     Value[!|@|#|%|&]');
 WriteLn('                                NOT     Value[!|@|#|%|&]');
end;
Function GNUBasicCRC32(Line : String) : LongInt;
Var
  Crc32Table : Array[0..255] Of LongInt;
  CrcValue   : LongInt;
  Count      : Byte;
  Index      : Byte;
Begin
 For Index:=0 To 255 Do
 Begin
  CRCValue:=Index;
  For Count:=1 To 8 Do If Odd(CRCValue) Then CRCValue:=(CRCValue Div 2) XOr LongInt($EDB88320) Else CRCValue:=CRCValue Div 2;
  Crc32Table[Index]:=CRCValue;
 end;
 CRCValue:=LongInt($FFFFFFFF);
 For Index:=1 To Length(Line) Do CRCValue:=Crc32Table[Byte(CRCValue) XOr Ord(Line[Index])] XOr (CRCValue Div $100);
 GNUBasicCRC32:=CRCValue;
end;
Procedure GNUBasicSortLines;
Var
  Index      : Word;
  LineIndex  : Word;
  LineNumber : Word;
  LineData   : String;
Begin
 For Index:=1 To BASICLinesCount Do For LineIndex:=Index To BASICLinesCount Do If Lines[Index].LineNumber>Lines[LineIndex].LineNumber Then
 Begin
  LineData:=Lines[Index].Line;
  LineNumber:=Lines[Index].LineNumber;
  Lines[Index].Line:=Lines[LineIndex].Line;
  Lines[Index].LineNumber:=Lines[LineIndex].LineNumber;
  Lines[LineIndex].LineNumber:=LineNumber;
  Lines[LineIndex].Line:=LineData;
 end;
end;
Procedure GNUBasicClearAll(ClearLines : Boolean);
Var
  Index    : Word;
  SubIndex : Word;
Begin
 If ClearLines Then
 Begin
  For Index:=1 To MaxLines Do
  Begin
   Lines[Index].Line:='';
   Lines[Index].LineNumber:=0;
  end;
  BASICLinesCount:=0;
 end;
 For Index:=1 To MaxWhiles Do
 Begin
  Whiles[Index].StartLine:=0;
  Whiles[Index].EndLine:=0;
  Whiles[Index].Conditional:='';
  Whiles[Index].IsFree:=True;
 end;
 For Index:=1 To MaxFroms Do
 Begin
  Froms[Index].StartLine:=0;
  Froms[Index].EndLine:=0;
  Froms[Index].BeginValue:=0;
  Froms[Index].EndLine:=0;
  Froms[Index].IsFree:=True;
 end;
 For Index:=1 To MaxFiles Do
 Begin
  If Files[Index].IsUse Then Close(Files[Index].WorkFile);
  Files[Index].FileMode:=False;
  Files[Index].IsUse:=False;
 end;
 For Index:=1 To MaxGoSubS Do GoSubS[Index]:=0;
 GoSubSCount:=0;
 For Index:=1 To MaxVars Do
 Begin
  Vars[Index].VarName:='';
  Vars[Index].StringValue:='';
  Vars[Index].NumberValue:=0.0;
  Vars[Index].ValueType:=False;
 end;
 VarsCount:=0;
 For Index:=1 To MaxDefFnS Do
 Begin
  DefFnS[Index]:='';
  For SubIndex:=1 To MaxDefFnSArgs Do
  Begin
   DefFnSArgs[Index,SubIndex].VarName:='';
   DefFnSArgs[Index,SubIndex].StringValue:='';
   DefFnSArgs[Index,SubIndex].NumberValue:=0.0;
   DefFnSArgs[Index,SubIndex].ValueType:=False;
  end;
  DefFnSArgsCount[Index]:=0;
 end;
 DefFnSCount:=0;
 CurrentDefFn:=0;
 DefFnMode:=False;
 CurrentLine:=0;
 RunMode:=False;
 TraceMode:=False;
 NumStr:=False;
 IsSystem:=False;
 Error:='';
 For Index:=1 To MaxANSIParameters Do Parameters[Index]:=0;
 ParametersCount:=0;
 ANSICursorColumn:=0;
 ANSICursorRow:=0;
 ANSICursorSaved:=False;
 Mode:=0;
 NumberLine:='';
 Number:=0;
end;
Function GNUBasicFindLine(LineNumber : Word) : Word;
Var
  Index : Word;
Begin
 If BASICLinesCount=0 Then Error:='Line not found' Else
 Begin
  For Index:=1 To BASICLinesCount+1 Do
  Begin
   If Index=BASICLinesCount+1 Then
   Begin
    Error:='Line not found';
    Exit;
   end;
   If Lines[Index].LineNumber=LineNumber Then Break;
  end;
  GNUBasicFindLine:=Index;
 end;
end;
Function GNUBasicParseRunLine(Var Line : String) : String;
Var
  Name      : String;
  Result    : String;
  Value     : String;
  Meaning   : String;
Begin
 Name:=InName(Line);
 If Error<>'' Then Exit;
 Line:=Trim(Line);
 If Name='REM' Then
 Begin
  If Line<>'' Then GNUBasicParseRunLine:='Rem '+Line Else GNUBasicParseRunLine:='Rem';
 end Else If Name='OPEN' Then
 Begin
  Name:=ParseCalculate(Line);
  If Error<>'' Then Exit;
  Result:=InName(Line);
  If Error<>'' Then Exit;
  If Result<>'FOR' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Result:=InName(Line);
  If Error<>'' Then Exit;
  If (Result<>'INPUT') And (Result<>'OUTPUT') And (Result<>'APPEND') Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Value:=InName(Line);
  If Error<>'' Then Exit;
  If Value<>'AS' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>'#' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  If Result='INPUT' Then Result:='InPut';
  If Result='OUTPUT' Then Result:='OutPut';
  If Result='APPEND' Then Result:='Append';
  GNUBasicParseRunLine:='Open '+Name+' For '+Result+' As #'+ParseCalculate(Line);
 end Else If Name='CLOSE' Then
 Begin
  If Copy(Line,1,1)<>'#' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  GNUBasicParseRunLine:='Close #'+ParseCalculate(Line);
 end Else If Name='PRINT' Then
 Begin
  If Copy(Line,1,1)='#' Then
  Begin
   Delete(Line,1,1);
   Value:=ParseCalculate(Line);
   If Error<>'' Then Exit;
   Line:=Trim(Line);
   If Copy(Line,1,1)<>',' Then
   Begin
    Error:='Syntax error';
    Exit;
   end;
   Delete(Line,1,1);
   GNUBasicParseRunLine:='Print #'+Value+','+ParseCalculate(Line);
  end Else GNUBasicParseRunLine:='Print '+ParseCalculate(Line);
 end Else If Name='CLS' Then GNUBasicParseRunLine:='Cls' Else If Name='COLOR' Then
 Begin
  Result:=ParseCalculate(Line);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>',' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  GNUBasicParseRunLine:='Color '+Result+','+ParseCalculate(Line);
 end Else If Name='LOCATE' Then
 Begin
  Result:=ParseCalculate(Line);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>',' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  GNUBasicParseRunLine:='Locate '+Result+','+ParseCalculate(Line);
 end Else If Name='SOUND' Then
 Begin
  Result:=ParseCalculate(Line);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>',' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  GNUBasicParseRunLine:='Sound '+Result+','+ParseCalculate(Line);
 end Else If Name='NAME' Then
 Begin
  Result:=ParseCalculate(Line);
  If Error<>'' Then Exit;
  Value:=InName(Line);
  If Error<>'' Then Exit;
  If Value<>'AS' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  GNUBasicParseRunLine:='Name '+Result+' As '+ParseCalculate(Line);
 end Else If Name='MKDIR' Then GNUBasicParseRunLine:='MkDir '+ParseCalculate(Line) Else
 If Name='CHDIR' Then GNUBasicParseRunLine:='ChDir '+ParseCalculate(Line) Else
 If Name='RMDIR' Then GNUBasicParseRunLine:='RmDir '+ParseCalculate(Line) Else
 If Name='KILL' Then GNUBasicParseRunLine:='Kill '+ParseCalculate(Line) Else
 If Name='FILES' Then GNUBasicParseRunLine:='Files '+ParseCalculate(Line) Else
 If Name='SYSTEM' Then GNUBasicParseRunLine:='System' Else If Name='WINDOW' Then
 Begin
  If Copy(Line,1,1)<>'(' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Name:=ParseCalculate(Line);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>',' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Result:=ParseCalculate(Line);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>')' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Line:=Trim(Line);
  If Copy(Line,1,1)<>'-' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Line:=Trim(Line);
  If Copy(Line,1,1)<>'(' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Value:=ParseCalculate(Line);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>',' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Meaning:=ParseCalculate(Line);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>')' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  GNUBasicParseRunLine:='Window ('+Name+','+Result+')-('+Value+','+Meaning+')';
 end Else If Name='LIST' Then
 Begin
  If Line='' Then GNUBasicParseRunLine:='List' Else
  Begin
   Result:=ParseCalculate(Line);
   If Error<>'' Then Exit;
   Line:=Trim(Line);
   If Copy(Line,1,1)=',' Then
   Begin
    Delete(Line,1,1);
    GNUBasicParseRunLine:='List '+Result+','+ParseCalculate(Line);
   end Else GNUBasicParseRunLine:='List '+Result;
  end;
 end Else If Name='DELETE' Then
 Begin
  Result:=ParseCalculate(Line);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Copy(Line,1,1)=',' Then
  Begin
   Delete(Line,1,1);
   GNUBasicParseRunLine:='Delete '+Result+','+ParseCalculate(Line);
  end Else GNUBasicParseRunLine:='Delete '+Result;
 end Else If Name='SAVE' Then GNUBasicParseRunLine:='Save '+ParseCalculate(Line) Else
 If Name='LOAD' Then GNUBasicParseRunLine:='Load '+ParseCalculate(Line) Else
 If Name='NEW' Then GNUBasicParseRunLine:='New' Else If Name='GO' Then
 Begin
  Name:=InName(Line);
  If Error<>'' Then Exit;
  If Name='TO' Then GNUBasicParseRunLine:='Go To '+ParseCalculate(Line) Else
  If Name='SUB' Then GNUBasicParseRunLine:='Go Sub '+ParseCalculate(Line) Else Error:='Syntax error';
 end Else If Name='RETURN' Then GNUBasicParseRunLine:='Return' Else
 If Name='TRON' Then GNUBasicParseRunLine:='TrOn' Else
 If Name='TROFF' Then GNUBasicParseRunLine:='TrOff' Else
 If Name='RUN' Then GNUBasicParseRunLine:='Run' Else
 If Name='END' Then GNUBasicParseRunLine:='End' Else
 If Name='LET' Then
 Begin
  Result:=InName(Line);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Line='' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Case Line[1] Of
  '$':
   Begin
    Delete(Line,1,1);
    Result:=Result+'$';
   end;
  '!': Delete(Line,1,1);
  '@': Delete(Line,1,1);
  '#': Delete(Line,1,1);
  '%': Delete(Line,1,1);
  '&': Delete(Line,1,1);
  end;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>'=' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  GNUBasicParseRunLine:='Let '+Result+'='+ParseCalculate(Line);
 end Else
 If Name='WHILE' Then GNUBasicParseRunLine:='While '+ParseCalculate(Line) Else
 If Name='WEND' Then GNUBasicParseRunLine:='WEnd' Else If Name='FROM' Then
 Begin
  Name:=InName(Line);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Line='' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Case Line[1] Of
  '$':
   Begin
    Error:='Variable type mismatch';
    Exit;
   end;
  '!': Delete(Line,1,1);
  '@': Delete(Line,1,1);
  '#': Delete(Line,1,1);
  '%': Delete(Line,1,1);
  '&': Delete(Line,1,1);
  end;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>'=' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Result:=ParseCalculate(Line);
  If Error<>'' Then Exit;
  Value:=InName(Line);
  If Error<>'' Then Exit;
  If Value<>'TO' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  GNUBasicParseRunLine:='From '+Name+'='+Result+' To '+ParseCalculate(Line);
 end Else If Name='NEXT' Then
 Begin
  Name:=InName(Line);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Line<>'' Then
  Case Line[1] Of
  '$':
   Begin
    Error:='Variable type mismatch';
    Exit;
   end;
  '!': Delete(Line,1,1);
  '@': Delete(Line,1,1);
  '#': Delete(Line,1,1);
  '%': Delete(Line,1,1);
  '&': Delete(Line,1,1);
  end;
  GNUBasicParseRunLine:='Next '+Name;
 end Else If Name='EXIT' Then
 Begin
  Name:=InName(Line);
  If Error<>'' Then Exit;
  If Name='WHILE' Then GNUBasicParseRunLine:='Exit While' Else
  If Name='FROM' Then GNUBasicParseRunLine:='Exit From' Else
  Error:='Syntax error';
 end Else If Name='IF' Then
 Begin
  Result:='If '+ParseCalculate(Line);
  If Error<>'' Then Exit;
  Name:=InName(Line);
  If Error<>'' Then Exit;
  If Name<>'THEN' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Result:=Result+' Then '+GNUBasicParseRunLine(Line);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Line<>'' Then
  Begin
   Name:=InName(Line);
   If Error<>'' Then Exit;
   If Name<>'ELSE' Then
   Begin
    Error:='Syntax error';
    Exit;
   end;
   GNUBasicParseRunLine:=Result+' Else '+GNUBasicParseRunLine(Line);
  end Else GNUBasicParseRunLine:=Result;
 end Else If Name='DEF' Then
 Begin
  Result:=InName(Line);
  If Error<>'' Then Exit;
  If Copy(Result,1,2)<>'FN' Then
  Begin
   Error:='User - defined function name must be beginning on FN';
   Exit;
  end;
  Line:=Trim(Line);
  Case Line[1] Of
  '$':
   Begin
    Delete(Line,1,1);
    Result:=Result+'$';
   end;
  '!': Delete(Line,1,1);
  '@': Delete(Line,1,1);
  '#': Delete(Line,1,1);
  '%': Delete(Line,1,1);
  '&': Delete(Line,1,1);
  end;
  Line:=Trim(Line);
  If Copy(Line,1,1)='(' Then
  Begin
   Delete(Line,1,1);
   Result:=Result+'(';
   Line:=Trim(Line);
   If Line='' Then
   Begin
    Error:='Syntax error';
    Exit;
   end;
   While Line<>'' Do
   Begin
    Name:=InName(Line);
    If Error<>'' Then Exit;
    Result:=Result+Name;
    Line:=Trim(Line);
    If Line='' Then
    Begin
     Error:='Syntax error';
     Exit;
    end;
    Case Line[1] Of
    '$':
     Begin
      Delete(Line,1,1);
      Result:=Result+'$';
     end;
    '!': Delete(Line,1,1);
    '@': Delete(Line,1,1);
    '#': Delete(Line,1,1);
    '%': Delete(Line,1,1);
    '&': Delete(Line,1,1);
    end;
    Line:=Trim(Line);
    If Line='' Then
    Begin
     Error:='Syntax error';
     Exit;
    end;
    Case Line[1] Of
    ')':
     Begin
      Delete(Line,1,1);
      Result:=Result+')';
      Line:=Trim(Line);
      Break;
     end;
    ',':
     Begin
      Delete(Line,1,1);
      Result:=Result+',';
     end;
    end;
   end;
  end;
  If Copy(Line,1,1)<>'=' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  GNUBasicParseRunLine:='Def '+Result+'='+ParseCalculate(Line);
 end Else If Name='HELP' Then GNUBasicParseRunLine:='Help' Else Error:='Unknown statement';
end;
Procedure GNUBasicDeleteLine(LineNumber : Word);
Var
  Index  : Word;
  Number : Word;
Begin
 Number:=GNUBasicFindLine(LineNumber);
 If Error<>'' Then Exit;
 Lines[Number].Line:='';
 Lines[Number].LineNumber:=0;
 If Number<BASICLinesCount Then
 For Index:=Number To BASICLinesCount-1 Do
 Begin
  Lines[Index].Line:=Lines[Index+1].Line;
  Lines[Index].LineNumber:=Lines[Index+1].LineNumber;
  Lines[Index+1].Line:='';
  Lines[Index+1].LineNumber:=0;
 end;
 Dec(BASICLinesCount);
end;
Procedure GNUBasicRunLine(Var Line : String);
Var
  Name        : String;
  Result      : String;
  Value       : String;
  Meaning     : String;
  FromVarName : String;
  Number      : Real;
  Num         : Real;
  Find        : SearchRec;
  WorkFile    : Text;
  WorkDT      : DateTime;
  Index       : Word;
  SubIndex    : Word;
  WorkIndex   : Word;
  WhilesCount : Word;
  FromsCount  : Word;
  VarType     : Boolean;
  IfElse      : Boolean;
Begin
 Name:=InName(Line);
 If Error<>'' Then Exit;
 Line:=Trim(Line);
 If Name='REM' Then Exit Else If Name='OPEN' Then
 Begin
  Name:=Calculate(Line);
  If Error<>'' Then Exit;
  If Not NumStr Then
  Begin
   Error:='Type mismatch';
   Exit;
  end;
  Result:=InName(Line);
  If Error<>'' Then Exit;
  If Result<>'FOR' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Result:=InName(Line);
  If Error<>'' Then Exit;
  If (Result<>'INPUT') And (Result<>'OUTPUT') And (Result<>'APPEND') Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Value:=InName(Line);
  If Error<>'' Then Exit;
  If Value<>'AS' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>'#' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Value:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismatch';
   Exit;
  end;
  Number:=StringToNumber(Value);
  If Error<>'' Then Exit;
  If (Trunc(Number)<1) Or (Trunc(Number)>MaxFiles) Then
  Begin
   Error:='Invalid file number';
   Exit;
  end;
  If Files[Trunc(Number)].IsUse Then
  Begin
   Error:='File already open';
   Exit;
  end;
  If Result='INPUT' Then Files[Trunc(Number)].FileMode:=True Else Files[Trunc(Number)].FileMode:=False;
  Files[Trunc(Number)].IsUse:=True;
  Assign(Files[Trunc(Number)].WorkFile,Name);
  If Result='INPUT' Then ReSet(Files[Trunc(Number)].WorkFile) Else
  If Result='OUTPUT' Then ReWrite(Files[Trunc(Number)].WorkFile) Else
  If Result='APPEND' Then Append(Files[Trunc(Number)].WorkFile);
  If IOResult<>0 Then Error:='Cannot open file';
 end Else If Name='CLOSE' Then
 Begin
  If Copy(Line,1,1)<>'#' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismatch';
   Exit;
  end;
  Number:=StringToNumber(Result);
  If Error<>'' Then Exit;
  If (Trunc(Number)<1) Or (Trunc(Number)>MaxFiles) Then
  Begin
   Error:='Invalid file number';
   Exit;
  end;
  If Not Files[Trunc(Number)].IsUse Then
  Begin
   Error:='File already closed';
   Exit;
  end;
  Files[Trunc(Number)].FileMode:=False;
  Files[Trunc(Number)].IsUse:=False;
  Close(Files[Trunc(Number)].WorkFile);
  If IOResult<>0 Then Error:='Cannot close file';
 end Else If Name='PRINT' Then
 Begin
  If Copy(Line,1,1)='#' Then
  Begin
   Delete(Line,1,1);
   Value:=Calculate(Line);
   If Error<>'' Then Exit;
   If NumStr Then
   Begin
    Error:='Type mismatch';
    Exit;
   end;
   Number:=StringToNumber(Value);
   If Error<>'' Then Exit;
   If (Trunc(Number)<1) Or (Trunc(Number)>MaxFiles) Then
   Begin
    Error:='Invalid file number';
    Exit;
   end;
   If Not Files[Trunc(Number)].IsUse Then
   Begin
    Error:='Invalid file number';
    Exit;
   end;
   If Files[Trunc(Number)].FileMode Then
   Begin
    Error:='Bad file mode';
    Exit;
   end;
   Line:=Trim(Line);
   If Copy(Line,1,1)<>',' Then
   Begin
    Error:='Syntax error';
    Exit;
   end;
   Delete(Line,1,1);
   Result:=Calculate(Line);
   If Error<>'' Then Exit;
   WriteLn(Files[Trunc(Number)].WorkFile,Result);
   If IOResult<>0 Then Error:='Cannot write to file';
  end Else
  Begin
   Result:=Calculate(Line);
   If Error<>'' Then Exit;
   WriteANSILine(Result);
  end;
 end Else If Name='CLS' Then ClrScr Else If Name='COLOR' Then
 Begin
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismacth';
   Exit;
  end;
  Number:=StringToNumber(Result);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>',' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismacth';
   Exit;
  end;
  Num:=StringToNumber(Result);
  If Error<>'' Then Exit;
  TextBackGround(Trunc(Number));
  TextColor(Trunc(Num));
 end Else If Name='LOCATE' Then
 Begin
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismacth';
   Exit;
  end;
  Number:=StringToNumber(Result);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>',' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismacth';
   Exit;
  end;
  Num:=StringToNumber(Result);
  If Error<>'' Then Exit;
  GoToXY(Trunc(Number),Trunc(Num));
 end Else If Name='SOUND' Then
 Begin
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismacth';
   Exit;
  end;
  Number:=StringToNumber(Result);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>',' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismacth';
   Exit;
  end;
  Num:=StringToNumber(Result);
  If Error<>'' Then Exit;
  Sound(Trunc(Number));
  Delay(Trunc(Num));
  NoSound;
 end Else If Name='NAME' Then
 Begin
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If Not NumStr Then
  Begin
   Error:='Type mismatch';
   Exit;
  end;
  Value:=InName(Line);
  If Error<>'' Then Exit;
  If Value<>'AS' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Value:=Calculate(Line);
  If Error<>'' Then Exit;
  If Not NumStr Then
  Begin
   Error:='Type mismatch';
   Exit;
  end;
  Assign(WorkFile,Result);
  Rename(WorkFile,Value);
  If IOResult<>0 Then Error:='Cannot rename file';
 end Else If Name='MKDIR' Then
 Begin
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If Not NumStr Then
  Begin
   Error:='Type mismacth';
   Exit;
  end;
  MkDir(Result);
  If IOResult<>0 Then Error:='Cannot make directory';
 end Else If Name='CHDIR' Then
 Begin
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If Not NumStr Then
  Begin
   Error:='Type mismacth';
   Exit;
  end;
  ChDir(Result);
  If IOResult<>0 Then Error:='Cannot change directory';
 end Else If Name='RMDIR' Then
 Begin
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If Not NumStr Then
  Begin
   Error:='Type mismacth';
   Exit;
  end;
  RmDir(Result);
  If IOResult<>0 Then Error:='Cannot remove directory';
 end Else If Name='KILL' Then
 Begin
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If Not NumStr Then
  Begin
   Error:='Type mismacth';
   Exit;
  end;
  FindFirst(Result,AnyFile,Find);
  If DosError=18 Then
  Begin
   Error:='File not found';
   Exit;
  end;
  Repeat
   Assign(WorkFile,Find.Name);
   Erase(WorkFile);
   If IOResult<>0 Then
   Begin
    Error:='Cannot delete file';
    Exit;
   end;
   FindNext(Find);
  Until DosError=18;
 end Else If Name='FILES' Then
 Begin
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If Not NumStr Then
  Begin
   Error:='Type mismacth';
   Exit;
  end;
  FindFirst(Result,AnyFile,Find);
  If DosError=18 Then
  Begin
   Error:='File not found';
   Exit;
  end;
  WriteLn('Name.        Size.      Date.           Time.    Attribute.');
  Number:=0.0;
  Repeat
   Number:=Number+Find.Size;
   Result:=Find.Name;
   While Length(Result)<13 Do Result:=Result+' ';
   Value:=NumberToString(Find.Size);
   While Length(Value)<10 Do Value:=' '+Value;
   Result:=Result+Value+' ';
   UnPackTime(Find.Time,WorkDT);
   Case DayOfWeek(WorkDT.Year,WorkDT.Month,WorkDT.Day) Of
   1: Result:=Result+'Mon';
   2: Result:=Result+'Tue';
   3: Result:=Result+'Wed';
   4: Result:=Result+'Thu';
   5: Result:=Result+'Fri';
   6: Result:=Result+'Sat';
   7: Result:=Result+'Sun';
   end;
   Value:=NumberToString(WorkDT.Day);
   If Length(Value)<2 Then Value:=' '+Value;
   Result:=Result+' '+Value+' ';
   Case WorkDT.Month Of
    1: Result:=Result+'Jan';
    2: Result:=Result+'Feb';
    3: Result:=Result+'Mar';
    4: Result:=Result+'Apr';
    5: Result:=Result+'May';
    6: Result:=Result+'Jun';
    7: Result:=Result+'Jul';
    8: Result:=Result+'Aug';
    9: Result:=Result+'Sep';
   10: Result:=Result+'Oct';
   11: Result:=Result+'Nov';
   12: Result:=Result+'Dec';
   end;
   Result:=Result+' '+NumberToString(WorkDT.Year)+' ';
   Value:=NumberToString(WorkDT.Hour);
   If Length(Value)<2 Then Value:='0'+Value;
   Result:=Result+Value+':';
   Value:=NumberToString(WorkDT.Min);
   If Length(Value)<2 Then Value:='0'+Value;
   Result:=Result+Value+':';
   Value:=NumberToString(WorkDT.Sec);
   If Length(Value)<2 Then Value:='0'+Value;
   Result:=Result+Value+' ';
   If (Find.Attr And ReadOnly)<>0 Then Value:='R' Else Value:=' ';
   If (Find.Attr And Hidden)<>0 Then Value:=Value+'H' Else Value:=Value+' ';
   If (Find.Attr And SysFile)<>0 Then Value:=Value+'S' Else Value:=Value+' ';
   If (Find.Attr And VolumeID)<>0 Then Value:=Value+'V' Else Value:=Value+' ';
   If (Find.Attr And Directory)<>0 Then Value:=Value+'D' Else Value:=Value+' ';
   If (Find.Attr And Archive)<>0 Then Value:=Value+'A' Else Value:=Value+' ';
   WriteLn(Result+Value);
   FindNext(Find);
  Until DosError=18;
  WriteLn('    Total size of files: '+NumberToString(Number)+' bytes.');
  WriteLn('      Current disk size: '+NumberToString(DiskSize(0))+' bytes.');
  WriteLn('Current disk free space: '+NumberToString(DiskFree(0))+' bytes.');
 end Else If Name='SYSTEM' Then
 Begin
  RunMode:=False;
  IsSystem:=True;
 end Else If Name='WINDOW' Then
 Begin
  If Copy(Line,1,1)<>'(' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Name:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismacth';
   Exit;
  end;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>',' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismacth';
   Exit;
  end;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>')' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Line:=Trim(Line);
  If Copy(Line,1,1)<>'-' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Line:=Trim(Line);
  If Copy(Line,1,1)<>'(' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Value:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismacth';
   Exit;
  end;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>',' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Meaning:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismacth';
   Exit;
  end;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>')' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Window(Trunc(StringToNumber(Name)),Trunc(StringToNumber(Result)),Trunc(StringToNumber(Value)),Trunc(StringToNumber(Meaning)));
 end Else If Name='LIST' Then
 Begin
  If Line='' Then
  Begin
   For Index:=1 To BASICLinesCount Do
   Begin
    Result:=NumberToString(Lines[Index].LineNumber);
    While Length(Result)<Length(NumberToString(MaxLines)) Do Result:=' '+Result;
    WriteLn(Result+' '+Lines[Index].Line);
   end;
  end Else
  Begin
   Result:=Calculate(Line);
   If Error<>'' Then Exit;
   If NumStr Then
   Begin
    Error:='Type mismatch';
    Exit;
   end;
   Number:=GNUBasicFindLine(Trunc(StringToNumber(Result)));
   If Error<>'' Then Exit;
   Line:=Trim(Line);
   If Copy(Line,1,1)=',' Then
   Begin
    Delete(Line,1,1);
    Result:=Calculate(Line);
    If Error<>'' Then Exit;
    If NumStr Then
    Begin
     Error:='Type mismatch';
     Exit;
    end;
    Num:=GNUBasicFindLine(Trunc(StringToNumber(Result)));
    If Error<>'' Then Exit;
    If Num<Number Then
    Begin
     Error:='Invalid line number range';
     Exit;
    end;
    For Index:=Trunc(Number) To Trunc(Num) Do
    Begin
     Result:=NumberToString(Lines[Index].LineNumber);
     While Length(Result)<Length(NumberToString(MaxLines)) Do Result:=' '+Result;
     WriteLn(Result+' '+Lines[Index].Line);
    end;
   end Else
   Begin
    Result:=NumberToString(Lines[Trunc(Number)].LineNumber);
    While Length(Result)<Length(NumberToString(MaxLines)) Do Result:=' '+Result;
    WriteLn(Result+' '+Lines[Trunc(Number)].Line);
   end;
  end;
 end Else If Name='DELETE' Then
 Begin
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismatch';
   Exit;
  end;
  Line:=Trim(Line);
  If Copy(Line,1,1)=',' Then
  Begin
   Delete(Line,1,1);
   Value:=Calculate(Line);
   If Error<>'' Then Exit;
   If NumStr Then
   Begin
    Error:='Type mismatch';
    Exit;
   end;
   If StringToNumber(Value)<StringToNumber(Result) Then
   Begin
    Error:='Invalid line number range';
    Exit;
   end;
   For Index:=Trunc(StringToNumber(Result)) To Trunc(StringToNumber(Value)) Do
   Begin
    GNUBasicDeleteLine(Index);
    If Error<>'' Then Exit;
   end;
  end Else GNUBasicDeleteLine(Trunc(StringToNumber(Result)));
 end Else If Name='SAVE' Then
 Begin
  If BASICLinesCount=0 Then
  Begin
   Error:='Nothing to save';
   Exit;
  end;
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If Not NumStr Then
  Begin
   Error:='Type mismacth';
   Exit;
  end;
  Assign(WorkFile,Result);
  ReWrite(WorkFile);
  If IOResult<>0 Then
  Begin
   Error:='Cannot open file';
   Exit;
  end;
  For Index:=1 To BASICLinesCount Do
  Begin
   Result:=NumberToString(Lines[Index].LineNumber);
   While Length(Result)<Length(NumberToString(MaxLines)) Do Result:=' '+Result;
   WriteLn(WorkFile,Result+' '+Lines[Index].Line);
   If IOResult<>0 Then
   Begin
    Close(WorkFile);
    Erase(WorkFile);
    Error:='Cannot write to file';
    Exit;
   end;
  end;
  Close(WorkFile);
 end Else If Name='LOAD' Then
 Begin
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If Not NumStr Then
  Begin
   Error:='Type mismacth';
   Exit;
  end;
  Assign(WorkFile,Result);
  ReSet(WorkFile);
  If IOResult<>0 Then
  Begin
   Error:='Cannot open file';
   Exit;
  end;
  GNUBasicClearAll(True);
  SubIndex:=0;
  While Not EoF(WorkFile) Do
  Begin
   ReadLn(WorkFile,Result);
   If IOResult<>0 Then
   Begin
    Close(WorkFile);
    GNUBasicClearAll(True);
    Error:='Cannot read from file';
    Exit;
   end;
   If SubIndex=MaxLines Then
   Begin
    Close(WorkFile);
    GNUBasicClearAll(True);
    Error:='Too many BASIC lines in file at line: '+NumberToString(SubIndex);
    Exit;
   end;
   Inc(SubIndex);
   Result:=Trim(Result);
   Index:=Trunc(InNumber(Result));
   If Error<>'' Then
   Begin
    Close(WorkFile);
    GNUBasicClearAll(True);
    Exit;
   end;
   If (Index<1) Or (Index>MaxLines) Then
   Begin
    Close(WorkFile);
    GNUBasicClearAll(True);
    Error:='Invalid line number in file at line: '+NumberToString(SubIndex);
    Exit;
   end;
   Result:=Trim(Result);
   If Result='' Then
   Begin
    Close(WorkFile);
    GNUBasicClearAll(True);
    Error:='Invalid line in file at line: '+NumberToString(SubIndex);
    Exit;
   end;
   If Not ((Ord(UpCase(Result[1]))>(Ord('A')-1)) And (Ord(UpCase(Result[1]))<(Ord('Z')+1))) Then
   Begin
    Close(WorkFile);
    GNUBasicClearAll(True);
    Error:='Invalid line in file at line: '+NumberToString(SubIndex);
    Exit;
   end;
   Result:=GNUBasicParseRunLine(Result);
   If Error<>'' Then
   Begin
    Close(WorkFile);
    GNUBasicClearAll(True);
    Error:=Error+' in file at line: '+NumberToString(SubIndex);
    Exit;
   end;
   If BASICLinesCount=0 Then
   Begin
    Inc(BASICLinesCount);
    Lines[BASICLinesCount].Line:=Result;
    Lines[BASICLinesCount].LineNumber:=Index;
   end Else
   Begin
    For WorkIndex:=1 To BASICLinesCount+1 Do
    Begin
     If WorkIndex=BASICLinesCount+1 Then
     Begin
      If BASICLinesCount=MaxLines Then
      Begin
       Close(WorkFile);
       GNUBasicClearAll(True);
       Error:='Too many BASIC lines in file at line: '+NumberToString(SubIndex);
       Exit;
      end;
      Inc(BASICLinesCount);
      Lines[BASICLinesCount].Line:=Result;
      Lines[BASICLinesCount].LineNumber:=Index;
      GNUBasicSortLines;
      Break;
     end;
     If Lines[WorkIndex].LineNumber=Index Then
     Begin
      Lines[WorkIndex].Line:=Result;
      Break;
     end;
    end;
   end;
  end;
  Close(WorkFile);
 end Else If Name='NEW' Then GNUBasicClearAll(True) Else If Name='GO' Then
 Begin
  If Not RunMode Then
  Begin
   Error:='Cannot execute GO TO or GO SUB statement without program running';
   Exit;
  end;
  Name:=InName(Line);
  If Error<>'' Then Exit;
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismatch';
   Exit;
  end;
  Index:=GNUBasicFindLine(Trunc(StringToNumber(Result)));
  If Error<>'' Then Exit;
  If Name='TO' Then CurrentLine:=Index-1 Else If Name='SUB' Then
  Begin
   If GoSubSCount=MaxGoSubS Then
   Begin
    Error:='Too many GO SUB''s';
    Exit;
   end;
   Inc(GoSubSCount);
   GoSubS[GoSubSCount]:=CurrentLine;
   CurrentLine:=Index-1;
  end Else Error:='Syntax error';
 end Else If Name='RETURN' Then
 Begin
  If Not RunMode Then
  Begin
   Error:='Cannot execute RETURN statement without program running';
   Exit;
  end;
  If GoSubSCount=0 Then
  Begin
   Error:='RETURN without GO SUB';
   Exit;
  end;
  CurrentLine:=GoSubS[GoSubSCount];
  GoSubS[GoSubSCount]:=0;
  Dec(GoSubSCount);
 end Else If Name='TRON' Then
 Begin
  TraceMode:=True;
  WriteLn('Trace mode is on.');
 end Else If Name='TROFF' Then
 Begin
  TraceMode:=False;
  WriteLn('Trace mode is off.');
 end Else If Name='RUN' Then
 Begin
  If RunMode Then
  Begin
   Error:='Program already running';
   Exit;
  end;
  If BASICLinesCount=0 Then
  Begin
   Error:='Nothing to run';
   Exit;
  end;
  RunMode:=True;
  CurrentLine:=1;
  Repeat
   If TraceMode Then Write('['+NumberToString(Lines[CurrentLine].LineNumber)+']');
   Result:=Lines[CurrentLine].Line;
   GNUBasicRunLine(Result);
   If Error<>'' Then Exit;
   Inc(CurrentLine);
  Until (CurrentLine>BASICLinesCount) Or (Not RunMode);
  RunMode:=False;
  CurrentLine:=0;
 end Else If Name='END' Then
 Begin
  If Not RunMode Then
  Begin
   Error:='Cannot end not running program';
   Exit;
  end;
  RunMode:=False;
 end Else If Name='DEF' Then
 Begin
  If DefFnSCount=MaxDefFnS Then
  Begin
   Error:='Too many user - defined functions';
   Exit;
  end;
  Inc(DefFnSCount);
  Result:=InName(Line);
  If Error<>'' Then Exit;
  If Copy(Result,1,2)<>'FN' Then
  Begin
   Error:='User - defined function name must be beginning on FN';
   Exit;
  end;
  Line:=Trim(Line);
  Case Line[1] Of
  '$':
   Begin
    Delete(Line,1,1);
    Result:=Result+'$';
   end;
  '!': Delete(Line,1,1);
  '@': Delete(Line,1,1);
  '#': Delete(Line,1,1);
  '%': Delete(Line,1,1);
  '&': Delete(Line,1,1);
  end;
  Line:=Trim(Line);
  If Copy(Line,1,1)='(' Then
  Begin
   Delete(Line,1,1);
   Result:=Result+'(';
   Line:=Trim(Line);
   If Line='' Then
   Begin
    Error:='Syntax error';
    Exit;
   end;
   While Line<>'' Do
   Begin
    Name:=InName(Line);
    If Error<>'' Then Exit;
    Result:=Result+Name;
    Line:=Trim(Line);
    If Line='' Then
    Begin
     Error:='Syntax error';
     Exit;
    end;
    Case Line[1] Of
    '$':
     Begin
      Delete(Line,1,1);
      Result:=Result+'$';
     end;
    '!': Delete(Line,1,1);
    '@': Delete(Line,1,1);
    '#': Delete(Line,1,1);
    '%': Delete(Line,1,1);
    '&': Delete(Line,1,1);
    end;
    Line:=Trim(Line);
    If Line='' Then
    Begin
     Error:='Syntax error';
     Exit;
    end;
    Case Line[1] Of
    ')':
     Begin
      Delete(Line,1,1);
      Result:=Result+')';
      Line:=Trim(Line);
      Break;
     end;
    ',':
     Begin
      Delete(Line,1,1);
      Result:=Result+',';
     end;
    end;
   end;
  end;
  If Copy(Line,1,1)<>'=' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  DefFnS[DefFnSCount]:=Result+'='+ParseCalculate(Line);
 end Else If Name='LET' Then
 Begin
  Name:=InName(Line);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Line='' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  VarType:=False;
  Case Line[1] Of
  '$':
   Begin
    Delete(Line,1,1);
    VarType:=True;
   end;
  '!': Delete(Line,1,1);
  '@': Delete(Line,1,1);
  '#': Delete(Line,1,1);
  '%': Delete(Line,1,1);
  '&': Delete(Line,1,1);
  end;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>'=' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr<>VarType Then
  Begin
   Error:='Type mismatch';
   Exit;
  end;
  SetVar(Name,VarType,Result);
 end Else If Name='WHILE' Then
 Begin
  If Not RunMode Then
  Begin
   Error:='Cannot execute WHILE loop without program running';
   Exit;
  end;
  For Index:=1 To MaxWhiles+1 Do
  Begin
   If Index=MaxWhiles+1 Then
   Begin
    Error:='Too many WHILE''s';
    Exit;
   end;
   If Whiles[Index].IsFree Then Break;
  end;
  WhilesCount:=0;
  For SubIndex:=CurrentLine+1 To BASICLinesCount+1 Do
  Begin
   If SubIndex=BASICLinesCount+1 Then
   Begin
    Error:='WHILE without WEND';
    Exit;
   end;
   Value:=Lines[SubIndex].Line;
   Value:=InName(Value);
   If Error<>'' Then Exit;
   If Value='WHILE' Then Inc(WhilesCount) Else
   If Value='WEND' Then If WhilesCount=0 Then Break Else Dec(WhilesCount);
  end;
  If Line='' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Value:=Line;
  Value:=Calculate(Value);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismatch';
   Exit;
  end;
  If StringToNumber(Value)<>0.0 Then
  Begin
   Whiles[Index].StartLine:=CurrentLine;
   Whiles[Index].EndLine:=SubIndex;
   Whiles[Index].Conditional:=ParseCalculate(Line);
   If Error<>'' Then Exit;
   Whiles[Index].IsFree:=False;
  end Else CurrentLine:=SubIndex;
 end Else If Name='WEND' Then
 Begin
  If Not RunMode Then
  Begin
   Error:='Cannot execute WHILE loop without program running';
   Exit;
  end;
  For Index:=1 To MaxWhiles+1 Do
  Begin
   If Index=MaxWhiles+1 Then
   Begin
    Error:='WEND without WHILE';
    Exit;
   end;
   If Not Whiles[Index].IsFree Then If Whiles[Index].EndLine=CurrentLine Then Break;
  end;
  Value:=Whiles[Index].Conditional;
  Value:=Calculate(Value);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismatch';
   Exit;
  end;
  If StringToNumber(Value)<>0.0 Then CurrentLine:=Whiles[Index].StartLine Else
  Begin
   Whiles[Index].StartLine:=0;
   Whiles[Index].EndLine:=0;
   Whiles[Index].Conditional:='';
   Whiles[Index].IsFree:=True;
  end;
 end Else If Name='FROM' Then
 Begin
  If Not RunMode Then
  Begin
   Error:='Cannot execute the FROM loop without program running';
   Exit;
  end;
  FromVarName:=InName(Line);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Line='' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Case Line[1] Of
  '$':
   Begin
    Error:='Variable type mismatch';
    Exit;
   end;
  '!': Delete(Line,1,1);
  '@': Delete(Line,1,1);
  '#': Delete(Line,1,1);
  '%': Delete(Line,1,1);
  '&': Delete(Line,1,1);
  end;
  Line:=Trim(Line);
  If Copy(Line,1,1)<>'=' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Delete(Line,1,1);
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismatch';
   Exit;
  end;
  Value:=InName(Line);
  If Error<>'' Then Exit;
  If Value<>'TO' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Value:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismatch';
   Exit;
  end;
  For Index:=1 To MaxFroms+1 Do
  Begin
   If Index=MaxFroms+1 Then
   Begin
    Error:='Too many FROM''s';
    Exit;
   end;
   If Froms[Index].IsFree Then Break;
  end;
  FromsCount:=0;
  For SubIndex:=CurrentLine+1 To BASICLinesCount+1 Do
  Begin
   If SubIndex=BASICLinesCount+1 Then
   Begin
    Error:='FROM without NEXT';
    Exit;
   end;
   Name:=Lines[SubIndex].Line;
   Name:=InName(Name);
   If Error<>'' Then Exit;
   If Name='FROM' Then Inc(WhilesCount) Else
   If Name='NEXT' Then
   Begin
    Name:=Lines[SubIndex].Line;
    Meaning:=InName(Name);
    If Error<>'' Then Exit;
    Meaning:=InName(Name);
    If Error<>'' Then Exit;
    If (FromsCount=0) And (Meaning=FromVarName) Then Break Else Dec(FromsCount);
   end;
  end;
  If StringToNumber(Value)>=StringToNumber(Result) Then
  Begin
   Froms[Index].VarName:=FromVarName;
   Froms[Index].StartLine:=CurrentLine;
   Froms[Index].EndLine:=SubIndex;
   Froms[Index].BeginValue:=Trunc(StringToNumber(Result));
   Froms[Index].EndValue:=Trunc(StringToNumber(Value));
   Froms[Index].IsFree:=False;
   SetVar(FromVarName,False,Result);
  end Else CurrentLine:=SubIndex;
 end Else If Name='NEXT' Then
 Begin
  If Not RunMode Then
  Begin
   Error:='Cannot execute the FROM loop without program running';
   Exit;
  end;
  FromVarName:=InName(Line);
  If Error<>'' Then Exit;
  Line:=Trim(Line);
  If Line<>'' Then
  Case Line[1] Of
  '$':
   Begin
    Error:='Variable type mismatch';
    Exit;
   end;
  '!': Delete(Line,1,1);
  '@': Delete(Line,1,1);
  '#': Delete(Line,1,1);
  '%': Delete(Line,1,1);
  '&': Delete(Line,1,1);
  end;
  For Index:=1 To MaxFroms+1 Do
  Begin
   If Index=MaxFroms+1 Then
   Begin
    Error:='NEXT without FROM';
    Exit;
   end;
   If Not Froms[Index].IsFree Then If (Froms[Index].EndLine=CurrentLine) And (Froms[Index].VarName=FromVarName) Then Break;
  end;
  Result:=InVar(FromVarName,False);
  If StringToNumber(Result)=Froms[Index].EndValue Then
  Begin
   Froms[Index].VarName:='';
   Froms[Index].StartLine:=0;
   Froms[Index].EndLine:=0;
   Froms[Index].BeginValue:=0;
   Froms[Index].EndValue:=0;
   Froms[Index].IsFree:=True;
  end Else
  Begin
   SetVar(FromVarName,False,NumberToString(StringToNumber(Result)+1));
   CurrentLine:=Froms[Index].StartLine;
  end;
 end Else If Name='EXIT' Then
 Begin
  If Not RunMode Then
  Begin
   Error:='Cannot EXIT from loop without program is running';
   Exit;
  end;
  Name:=InName(Line);
  If Error<>'' Then Exit;
  If Name='WHILE' Then
  Begin
   For Index:=1 To MaxWhiles+1 Do
   Begin
    If Index=MaxWhiles+1 Then
    Begin
     Error:='EXIT WHILE without WHILE';
     Exit;
    end;
    If Not Whiles[Index].IsFree Then
    If (CurrentLine>=Whiles[Index].StartLine) And (CurrentLine<=Whiles[Index].EndLine) Then Break;
   end;
   CurrentLine:=Whiles[Index].EndLine;
   Whiles[Index].StartLine:=0;
   Whiles[Index].EndLine:=0;
   Whiles[Index].Conditional:='';
   Whiles[Index].IsFree:=True;
  end Else If Name='FROM' Then
  Begin
   For Index:=1 To MaxFroms+1 Do
   Begin
    If Index=MaxFroms+1 Then
    Begin
     Error:='EXIT FROM without FROM';
     Exit;
    end;
    If Not Froms[Index].IsFree Then
    If (CurrentLine<=Froms[Index].StartLine) And (CurrentLine>=Froms[Index].EndLine) And (Froms[Index].VarName=FromVarName) Then Break;
   end;
   CurrentLine:=Froms[Index].EndLine;
   Froms[Index].VarName:='';
   Froms[Index].StartLine:=0;
   Froms[Index].EndLine:=0;
   Froms[Index].BeginValue:=0;
   Froms[Index].EndValue:=0;
   Froms[Index].IsFree:=True;
  end Else Error:='Syntax error';
 end Else If Name='IF' Then
 Begin
  Result:=Calculate(Line);
  If Error<>'' Then Exit;
  If NumStr Then
  Begin
   Error:='Type mismatch';
   Exit;
  end;
  Value:=InName(Line);
  If Error<>'' Then Exit;
  If Value<>'THEN' Then
  Begin
   Error:='Syntax error';
   Exit;
  end;
  Name:=GNUBasicParseRunLine(Line);
  If Error<>'' Then Exit;
  IfElse:=False;
  Line:=Trim(Line);
  If Line<>'' Then
  Begin
   IfElse:=True;
   Value:=InName(Line);
   If Error<>'' Then Exit;
   If Value<>'ELSE' Then
   Begin
    Error:='Syntax error';
    Exit;
   end;
   Meaning:=GNUBasicParseRunLine(Line);
   If Error<>'' Then Exit;
  end;
  If StringToNumber(Result)<>0.0 Then GNUBasicRunLine(Name) Else If IfElse Then GNUBasicRunLine(Meaning);
 end Else If Name='HELP' Then GNUBasicHelp Else Error:='Unknown statement';
end;
Function StandartStatus : String;
Var
  OutLine  : String;
  WorkLine : String;
Begin
 Str(LinePosition,OutLine);
 Str(CursorRow,WorkLine);
 StandartStatus:='ESC=Menu. Column='+OutLine+'. Row='+WorkLine+'. File='+GNUTextFileName+'.';
end;
Procedure DrawScreen;
Var
  Index : Byte;
Begin
 Window(1,1,80,25);
 TextBackGround(Blue);
 TextColor(Yellow);
 ClrScr;
 Write('É');
 For Index:=1 To 78 Do Write('Í');
 Write('»');
 For Index:=2 To 23 Do
 Begin
  GoToXY(1,Index);
  Write('º');
  GoToXY(80,Index);
  Write('º');
 end;
 Write('È');
 For Index:=1 To 78 Do Write('Í');
 Write('¼');
end;
Procedure Draw;
Var
  Index : Byte;
Begin
 Window(1,25,80,25);
 TextBackGround(LightGray);
 TextColor(Red);
 ClrScr;
 Write(' '+Copy(StatusLine,1,78));
 Window(2,2,79,23);
 TextBackGround(Blue);
 TextColor(White);
 ClrScr;
 Window(2,2,79,24);
 For Index:=1 To 22 Do
 Begin
  GoToXY(1,Index);
  Write(Copy(TextLines[(CursorRow-TextPosition)+Index],(CursorColumn-LinePosition)+1,78));
 end;
 Window(2,2,79,23);
 GoToXY(LinePosition,TextPosition);
end;
Procedure Control;
Begin
 If CursorRow<1 Then CursorRow:=1;
 If CursorColumn<1 Then CursorColumn:=1;
 If TextPosition<1 Then TextPosition:=1;
 If LinePosition<1 Then LinePosition:=1;
 If CursorRow>TextLinesCount Then CursorRow:=TextLinesCount;
 If TextPosition>22 Then TextPosition:=22;
 If CursorColumn>Length(TextLines[CursorRow])+1 Then CursorColumn:=Length(TextLines[CursorRow])+1;
 If Length(TextLines[CursorRow])+1<79 Then
 If LinePosition>Length(TextLines[CursorRow])+1 Then LinePosition:=Length(TextLines[CursorRow])+1;
 If Length(TextLines[CursorRow])+1>77 Then
 If LinePosition>78 Then LinePosition:=78;
 StatusLine:=StandartStatus;
 Draw;
end;
Procedure CursorUp;
Begin
 Dec(CursorRow);
 Dec(TextPosition);
 Control;
end;
Procedure CursorDown;
Begin
 Inc(CursorRow);
 Inc(TextPosition);
 Control;
end;
Procedure CursorLeft;
Begin
 If CursorColumn=1 Then
 Begin
  If CursorRow>1 Then
  Begin
   CursorColumn:=Length(TextLines[CursorRow-1])+1;
   LinePosition:=CursorColumn;
   Dec(CursorRow);
   Dec(TextPosition);
  end;
 end Else
 Begin
  Dec(CursorColumn);
  Dec(LinePosition);
 end;
 Control;
end;
Procedure CursorRight;
Begin
 If CursorColumn=Length(TextLines[CursorRow])+1 Then
 Begin
  If CursorRow<TextLinesCount Then
  Begin
   CursorColumn:=1;
   LinePosition:=1;
   CursorDown;
  end;
 end Else
 Begin
  Inc(CursorColumn);
  Inc(LinePosition);
  Control;
 end;
end;
Procedure DeleteText;
Var
  Index : Word;
  Tmp   : Byte;
Begin
 If CursorColumn=Length(TextLines[CursorRow])+1 Then
 Begin
  If (CursorRow<TextLinesCount) And (Length(TextLines[CursorRow])<255) Then
  Begin
   Tmp:=Length(TextLines[CursorRow]);
   TextLines[CursorRow]:=TextLines[CursorRow]+Copy(TextLines[CursorRow+1],1,255-Tmp);
   TextLines[CursorRow+1]:=Copy(TextLines[CursorRow+1],255-Tmp,255);
   If TextLines[CursorRow+1]='' Then For Index:=CursorRow+1 To TextLinesCount-1 Do
   Begin
    TextLines[Index]:=TextLines[Index+1];
    TextLines[Index+1]:='';
   end;
  end;
 end Else Delete(TextLines[CursorRow],CursorColumn,1);
 Draw;
end;
Procedure BackDelete;
Var
  Index : Word;
  Tmp   : Byte;
Begin
 If CursorColumn=1 Then
 Begin
  If CursorRow>1 Then
  Begin
   If Length(TextLines[CursorRow-1])<255 Then
   Begin
    Tmp:=Length(TextLines[CursorRow-1]);
    TextLines[CursorRow-1]:=TextLines[CursorRow-1]+Copy(TextLines[CursorRow],1,255-Tmp);
    TextLines[CursorRow]:=Copy(TextLines[CursorRow],255-Tmp,255);
    If TextLines[CursorRow]='' Then For Index:=CursorRow To TextLinesCount-1 Do
    Begin
     TextLines[Index]:=TextLines[Index+1];
     TextLines[Index+1]:='';
    end;
    CursorColumn:=Tmp+1;
    LinePosition:=CursorColumn;
    CursorUp;
   end;
  end;
 end Else
 Begin
  CursorLeft;
  Delete(TextLines[CursorRow],CursorColumn,1);
  Draw;
 end;
end;
Procedure EnterLine;
Var
  Index : Word;
Begin
 If TextLines[TextLinesCount]<>'' Then Exit;
 For Index:=TextLinesCount DownTo CursorRow+2 Do
 Begin
  TextLines[Index]:=TextLines[Index-1];
  TextLines[Index-1]:='';
 end;
 TextLines[CursorRow+1]:=Copy(TextLines[CursorRow],CursorColumn,255);
 TextLines[CursorRow]:=Copy(TextLines[CursorRow],1,CursorColumn-1);
 CursorColumn:=1;
 LinePosition:=1;
 CursorDown;
end;
Procedure InsertChar(Symbol : Char);
Begin
 If CursorColumn=Length(TextLines[CursorRow]) Then CursorRight;
 If Length(TextLines[CursorRow])=255 Then Exit;
 Insert(Symbol,TextLines[CursorRow],CursorColumn);
 CursorRight;
end;
Procedure Menu;
Var
  WorkFile    : Text;
  WorkLine    : String;
  WrkLine     : String;
  Index       : Word;
  ErrorStatus : Boolean;
  WorkKey     : Char;
 Procedure SaveFile;
 Var
   Index : Word;
 Begin
  ErrorStatus:=False;
  StatusLine:='Saving. Please waith...';
  Draw;
  Assign(WorkFile,GNUTextFileName);
  SetFAttr(WorkFile,0);
  Repeat
   ReWrite(WorkFile);
   If IOResult<>0 Then
   Begin
    If MessageBox('Save file.','Cannot open file: '+GNUTextFileName+' for save. Retry opening?') Then
    Begin
     Draw;
     Continue;
    end Else
    Begin
     ErrorStatus:=True;
     Exit;
    end;
   end Else Break;
  Until False;
  For Index:=TextLinesCount DownTo 1 Do If TextLines[Index]<>'' Then Break;
  For Index:=1 To Index Do
  Begin
   Repeat
    WriteLn(WorkFile,TextLines[Index]);
    If IOResult<>0 Then
    Begin
     If MessageBox('Save file.','Cannot write to file for save. Retry writing?') Then
     Begin
      Draw;
      Continue;
     end Else
     Begin
      ErrorStatus:=True;
      Close(WorkFile);
      SetFAttr(WorkFile,0);
      Erase(WorkFile);
      Exit;
     end;
    end Else Break;
   Until False;
  end;
  Close(WorkFile);
  SetFAttr(WorkFile,0);
 end;
 Procedure LoadFile;
 Var
   Index : Word;
 Begin
  StatusLine:='Load file.';
  Draw;
  If MessageBox('Load file.','Save current file before load new?') Then
  Begin
   SaveFile;
   If ErrorStatus Then Exit;
  end Else Draw;
  StatusLine:='Load file.';
  Draw;
  WorkLine:='';
  If InputBox('Load file.','Please enter file name to load it.',WorkLine) Then
  Begin
   If Length(WorkLine)>12 Then
   Begin
    OutBox('Load file.','File name is too long.');
    Exit;
   end;
   If Length(WorkLine)<1 Then
   Begin
    OutBox('Load file.','File name is too short.');
    Exit;
   end;
  end Else Exit;
  Draw;
  Assign(WorkFile,WorkLine);
  SetFAttr(WorkFile,0);
  Repeat
   ReSet(WorkFile);
   If IOResult<>0 Then
   Begin
    If MessageBox('Load file.','Cannot open file: '+GNUTextFileName+' for load. Retry opening?') Then
    Begin
     Draw;
     Continue;
    end Else Exit;
   end Else Break;
  Until False;
  For Index:=1 To TextLinesCount Do TextLines[Index]:='';
  CursorRow:=1;
  CursorColumn:=1;
  TextPosition:=1;
  LinePosition:=1;
  StatusLine:='Loading. Please waith...';
  Draw;
  Index:=1;
  While Not EoF(WorkFile) Do
  Begin
   Repeat
    ReadLn(WorkFile,TextLines[Index]);
    If IOResult<>0 Then
    Begin
     If MessageBox('load file.','Cannot read from file: '+WorkLine+' for load. Retry reading?') Then
     Begin
      Draw;
      Continue;
     end Else
     Begin
      For Index:=1 To TextLinesCount Do TextLines[Index]:='';
      Close(WorkFile);
      SetFAttr(WorkFile,0);
      Exit;
     end;
    end Else Break;
   Until False;
   Inc(Index);
   If Index=TextLinesCount+1 Then
   Begin
    StatusLine:='Loaded is stopped.';
    Draw;
    OutBox('Load file.','File is too big. Loaded first lines.');
    Break;
   end;
  end;
  GNUTextFileName:=WorkLine;
  Close(WorkFile);
  SetFAttr(WorkFile,0);
  For Index:=1 To TextLinesCount Do
  Begin
   WorkLine:=TextLines[Index];
   TextLines[Index]:='';
   While WorkLine<>'' Do
   Begin
    If Ord(WorkLine[1])<33 Then
    TextLines[Index]:=TextLines[Index]+' ' Else
    TextLines[Index]:=TextLines[Index]+Copy(WorkLine,1,1);
    Delete(WorkLine,1,1);
   end;
  end;
 end;
 Procedure ChangeFile;
 Begin
  StatusLine:='Change current file name.';
  Draw;
  WorkLine:=GNUTextFileName;
  If Not InputBox('Change file name.','Please change file name.',WorkLine) Then Exit;
  Draw;
  If Length(WorkLine)>12 Then
  Begin
   OutBox('Load file.','File name is too long.');
   Exit;
  end;
  If Length(WorkLine)<1 Then
  Begin
   OutBox('Load file.','File name is too short.');
   Exit;
  end;
  GNUTextFileName:=WorkLine;
 end;
 Procedure FindLine;
 Var
   Index : Word;
 Begin
  StatusLine:='Find line.';
  Draw;
  WorkLine:='';
  If Not InputBox('Find line.','Please enter line to find. Warning! Search is case sensitive.',WorkLine) Then Exit;
  Draw;
  For Index:=1 To TextLinesCount+1 Do
  Begin
   If Index=TextLinesCount+1 Then
   Begin
    OutBox('Find line.','Line is not found.');
    Exit;
   end;
   If Pos(WorkLine,TextLines[Index])>0 Then Break;
  end;
  CursorRow:=Index;
  CursorColumn:=Pos(WorkLine,TextLines[Index]);
  TextPosition:=CursorRow;
  LinePosition:=CursorColumn;
  Control;
 end;
 Procedure ReplaceLine;
 Var
   Index : Word;
 Begin
  StatusLine:='Replace line.';
  Draw;
  WorkLine:='';
  If Not InputBox('Replace line.','Please enter line to find. Warning! Search is case sensitive.',WorkLine) Then Exit;
  Draw;
  WrkLine:='';
  If Not InputBox('Replace line.','Please enter line to replace it.',WrkLine) Then Exit;
  Draw;
  For Index:=1 To TextLinesCount+1 Do
  Begin
   If Index=TextLinesCount+1 Then
   Begin
    OutBox('Replace line.','Search for replacement is end.');
    Exit;
   end;
   If Pos(WorkLine,TextLines[Index])>0 Then
   Begin
    CursorRow:=Index;
    CursorColumn:=Pos(WorkLine,TextLines[Index]);
    TextPosition:=CursorRow;
    LinePosition:=CursorColumn;
    Control;
    StatusLine:='Replace this occurence (ENTER=Yes,ESC=Cancel)?';
    Draw;
    Repeat
     WorkKey:=ReadKey;
    Until (WorkKey=Chr(13)) Or (WorkKey=Chr(27));
    If WorkKey=Chr(27) Then Exit;
    TextLines[Index]:=Copy(TextLines[Index],1,Pos(WorkLine,TextLines[Index])-1)+
    WrkLine+Copy(TextLines[Index],Pos(WorkLine,TextLines[Index])+Length(WorkLine),255);
   end;
  end;
 end;
 Procedure ReplaceAllLines;
 Var
   Index : Word;
 Begin
  StatusLine:='Replace line.';
  Draw;
  WorkLine:='';
  If Not InputBox('Replace line.','Please enter line to find. Warning! Search is case sensitive.',WorkLine) Then Exit;
  Draw;
  WrkLine:='';
  If Not InputBox('Replace line.','Please enter line to replace it.',WrkLine) Then Exit;
  Draw;
  For Index:=1 To TextLinesCount+1 Do
  Begin
   If Index=TextLinesCount+1 Then
   Begin
    OutBox('Replace line.','Replacement is end.');
    Exit;
   end;
   If Pos(WorkLine,TextLines[Index])>0 Then
   TextLines[Index]:=Copy(TextLines[Index],1,Pos(WorkLine,TextLines[Index])-1)+
   WrkLine+Copy(TextLines[Index],Pos(WorkLine,TextLines[Index])+Length(WorkLine),255);
  end;
 end;
 Procedure ParseProgramText;
 Var
   Index      : Word;
   WorkLine   : String;
   Work       : String;
   LineNumber : Word;
 Begin
  StatusLine:='Parsing program text. Please waith...';
  Draw;
  For Index:=1 To TextLinesCount Do
  Begin
   If Trim(TextLines[Index])<>'' Then
   Begin
    WorkLine:=Trim(TextLines[Index]);
    Case UpCase(WorkLine[1]) Of
    '0'..'9':
     Begin
      LineNumber:=Trunc(InNumber(WorkLine));
      If Error<>'' Then
      Begin
       CursorRow:=Index;
       TextPosition:=CursorRow;
       Control;
       StatusLine:='Parsing program text. Please waith...';
       Draw;
       OutBox('Parse text.','Error in line: '+NumberToString(Index)+': '+Error+'.');
       ClearAll;
       Exit;
      end;
      If (LineNumber<1) Or (LineNumber>TextLinesCount) Then
      Begin
       CursorRow:=Index;
       TextPosition:=CursorRow;
       Control;
       StatusLine:='Parsing program text. Please waith...';
       Draw;
       OutBox('Parse text.','Error in line: '+NumberToString(Index)+': Invalid line number.');
       Exit;
      end;
      WorkLine:=Trim(WorkLine);
      If WorkLine='' Then
      Begin
       CursorRow:=Index;
       TextPosition:=CursorRow;
       Control;
       StatusLine:='Parsing program text. Please waith...';
       Draw;
       OutBox('Parse text.','Error in line: '+NumberToString(Index)+': Invalid line.');
       Exit;
      end;
      Case UpCase(WorkLine[1]) Of
      'A'..'Z':
       Begin
        WorkLine:=ParseRunLine(WorkLine);
        If Error<>'' Then
        Begin
         CursorRow:=Index;
         TextPosition:=CursorRow;
         Control;
         StatusLine:='Parsing program text. Please waith...';
         Draw;
         OutBox('Parse text.','Error in line: '+NumberToString(Index)+': '+Error+'.');
         ClearAll;
         Exit;
        end;
        Work:=NumberToString(LineNumber);
        While Length(Work)<Length(NumberToString(TextLinesCount)) Do Work:='0'+Work;
        TextLines[Index]:=Work+' '+WorkLine;
       end;
      Else
       Begin
        CursorRow:=Index;
        TextPosition:=CursorRow;
        Control;
        StatusLine:='Parsing program text. Please waith...';
        Draw;
        OutBox('Parse text.','Error in line: '+NumberToString(Index)+': Invalid line.');
        Exit;
       end;
      end;
     end;
    'A'..'Z':
     Begin
      WorkLine:=ParseRunLine(WorkLine);
      If Error<>'' Then
      Begin
       CursorRow:=Index;
       TextPosition:=CursorRow;
       Control;
       StatusLine:='Parsing program text. Please waith...';
       Draw;
       OutBox('Parse text.','Error in line: '+NumberToString(Index)+': '+Error+'.');
       ClearAll;
       Exit;
      end;
      TextLines[Index]:=WorkLine;
     end;
    Else
     Begin
      CursorRow:=Index;
      TextPosition:=CursorRow;
      Control;
      StatusLine:='Parsing program text. Please waith...';
      Draw;
      OutBox('Parse text.','Error in line: '+NumberToString(Index)+': Invalid line.');
      Exit;
     end;
    end;
   end;
  end;
 end;
 Procedure RunProgram;
 Var
   LineNumber : Word;
 Begin
  StatusLine:='Running program. Please press ENTER to continue...';
  Window(1,1,80,25);
  TextBackGround(Black);
  TextColor(Green);
  ClrScr;
  ClearAll;
  RunMode:=True;
  CurrentLine:=1;
  Repeat
   If Trim(TextLines[CurrentLine])<>'' Then
   Begin
    WorkLine:=Trim(TextLines[CurrentLine]);
    Case UpCase(WorkLine[1]) Of
    '0'..'9':
     Begin
      LineNumber:=Trunc(InNumber(WorkLine));
      If Error<>'' Then
      Begin
       DrawScreen;
       Draw;
       OutBox('Running program.','Error in line: '+NumberToString(CurrentLine)+': '+Error+'.');
       ClearAll;
       Exit;
      end;
      If (LineNumber<1) Or (LineNumber>TextLinesCount) Then
      Begin
       DrawScreen;
       Draw;
       OutBox('Running program.','Error in line: '+NumberToString(CurrentLine)+': Invalid line number.');
       ClearAll;
       Exit;
      end;
      If TraceMode Then Write('['+NumberToString(LineNumber)+']');
      WorkLine:=Trim(WorkLine);
      If WorkLine='' Then
      Begin
       DrawScreen;
       Draw;
       OutBox('Running program.','Error in line: '+NumberToString(CurrentLine)+': Invalid line.');
       ClearAll;
       Exit;
      end;
      Case UpCase(WorkLine[1]) Of
      'A'..'Z':
       Begin
        WorkLine:=ParseRunLine(WorkLine);
        If Error<>'' Then
        Begin
         DrawScreen;
         Draw;
         OutBox('Running program.','Error in line: '+NumberToString(CurrentLine)+': '+Error+'.');
         ClearAll;
         Exit;
        end;
        RunLine(WorkLine);
        If Error<>'' Then
        Begin
         DrawScreen;
         Draw;
         OutBox('Running program.','Error in line: '+NumberToString(CurrentLine)+': '+Error+'.');
         ClearAll;
         Exit;
        end;
       end;
      Else
       Begin
        DrawScreen;
        Draw;
        OutBox('Running program.','Error in line: '+NumberToString(CurrentLine)+': Invalid line.');
        ClearAll;
        Exit;
       end;
      end;
     end;
    'A'..'Z':
     Begin
      WorkLine:=ParseRunLine(WorkLine);
      If Error<>'' Then
      Begin
       DrawScreen;
       Draw;
       OutBox('Running program.','Error in line: '+NumberToString(CurrentLine)+': '+Error+'.');
       ClearAll;
       Exit;
      end;
      RunLine(WorkLine);
      If Error<>'' Then
      Begin
       DrawScreen;
       Draw;
       OutBox('Running program.','Error in line: '+NumberToString(CurrentLine)+': '+Error+'.');
       ClearAll;
       Exit;
      end;
     end;
    Else
     Begin
      DrawScreen;
      Draw;
      OutBox('Running program.','Error in line: '+NumberToString(CurrentLine)+': Invalid line.');
      ClearAll;
      Exit;
     end;
    end;
   end;
   Inc(CurrentLine);
  Until (CurrentLine>TextLinesCount) Or (Not RunMode);
  Window(1,25,80,25);
  TextBackGround(Black);
  TextColor(Green);
  ClrScr;
  Write('Please press the ENTER key to continue...');
  GoToXY(1,1);
  Repeat Until ReadKey=Chr(13);
  ClearAll;
  DrawScreen;
 end;
 Procedure RunCurrentLine;
 Var
   LineNumber : Word;
 Begin
  StatusLine:='Running current line. Please press ENTER to continue...';
  Draw;
  If TextLines[CursorRow]<>'' Then
  Begin
   WorkLine:=Trim(TextLines[CursorRow]);
   Case UpCase(WorkLine[1]) Of
   '0'..'9':
    Begin
     LineNumber:=Trunc(InNumber(WorkLine));
     If Error<>'' Then
     Begin
      OutBox('Running current line.','Error in line: '+NumberToString(CursorRow)+': '+Error+'.');
      ClearAll;
      Exit;
     end;
     If (LineNumber<1) Or (LineNumber>TextLinesCount) Then
     Begin
      OutBox('Running current line.','Error in line: '+NumberToString(CursorRow)+': Invalid line number.');
      Exit;
     end;
     WorkLine:=Trim(WorkLine);
     If WorkLine='' Then
     Begin
      OutBox('Running current line.','Error in line: '+NumberToString(CursorRow)+': Invalid line.');
      Exit;
     end;
     Case UpCase(WorkLine[1]) Of
     'A'..'Z':
      Begin
       WorkLine:=ParseRunLine(WorkLine);
       If Error<>'' Then
       Begin
        OutBox('Running current line.','Error in line: '+NumberToString(CursorRow)+': '+Error+'.');
        ClearAll;
        Exit;
       end;
       Window(1,1,80,25);
       TextBackGround(Black);
       TextColor(Green);
       ClrScr;
       RunLine(WorkLine);
       If Error<>'' Then
       Begin
        DrawScreen;
        Draw;
        OutBox('Running current line.','Error in line: '+NumberToString(CursorRow)+': '+Error+'.');
        ClearAll;
        Exit;
       end Else
       Begin
        Window(1,25,80,25);
        TextBackGround(Black);
        TextColor(Green);
        ClrScr;
        Write('Please press the ENTER key to continue...');
        GoToXY(1,1);
        Repeat Until ReadKey=Chr(13);
       end;
       DrawScreen;
      end;
     Else
      Begin
       OutBox('Running current line.','Error in line: '+NumberToString(CursorRow)+': Invalid line.');
       Exit;
      end;
     end;
    end;
   'A'..'Z':
    Begin
     WorkLine:=ParseRunLine(WorkLine);
     If Error<>'' Then
     Begin
      OutBox('Running current line.','Error in line: '+NumberToString(CursorRow)+': '+Error+'.');
      ClearAll;
      Exit;
     end;
     Window(1,1,80,25);
     TextBackGround(Black);
     TextColor(Green);
     ClrScr;
     RunLine(WorkLine);
     If Error<>'' Then
     Begin
      DrawScreen;
      Draw;
      OutBox('Running current line.','Error in line: '+NumberToString(CursorRow)+': '+Error+'.');
      ClearAll;
      Exit;
     end Else
     Begin
      Window(1,25,80,25);
      TextBackGround(Black);
      TextColor(Green);
      ClrScr;
      Write('Please press the ENTER key to continue...');
      GoToXY(1,1);
      Repeat Until ReadKey=Chr(13);
     end;
     DrawScreen;
    end;
   Else
    Begin
     OutBox('Running current line.','Error in line: '+NumberToString(CursorRow)+': Invalid line.');
     Exit;
    end;
   end;
  end Else OutBox('Running current line.','Nothing to run.');
 end;
 Procedure GNUBasicInterpretter;
 Var
   BASICLine  : String;
   LineNumber : Word;
   Index      : Word;
   WorkDT     : DateTime;
 Begin
  Window(1,1,80,25);
  TextBackGround(Black);
  TextColor(LightGray);
  ClrScr;
  WriteLn;
  WriteLn('The personal interpretter of the BASIC programming language.');
  WriteLn('GNUBasic, Copyright (C) 2003 Sandul Yura Valentinovich.');
  WriteLn('(C) Monday, 3 March 2003 year.');
  WriteLn('All rights reserved.');
  WriteLn('GNUBasic comes with ABSOLUTELY NO WARRANTY; for details, see the GNU General');
  WriteLn('Public License, version 2. This is free software, and you are welcome to');
  WriteLn('redistribute it under certain conditions from the GNU General Public License.');
  WriteLn('***************************************************************');
  WriteLn('Type: "System" and press the [ENTER] key to quit.');
  WriteLn('Type: "Help" and press the [ENTER] key to get help.');
  WriteLn;
  GNUBasicClearAll(True);
  Repeat
   BASICLine:='Today: ';
   GetDate(WorkDT.Year,WorkDT.Month,WorkDT.Day,WorkDT.Hour);
   Case WorkDT.Hour Of
   0: BASICLine:=BASICLine+'Sun';
   1: BASICLine:=BASICLine+'Mon';
   2: BASICLine:=BASICLine+'Tues';
   3: BASICLine:=BASICLine+'Wednes';
   4: BASICLine:=BASICLine+'Thurs';
   5: BASICLine:=BASICLine+'Fri';
   6: BASICLine:=BASICLine+'Satur';
   end;
   BASICLine:=BASICLine+'day, '+NumberToString(WorkDT.Day)+' ';
   Case WorkDT.Month Of
    1: BASICLine:=BASICLine+'January';
    2: BASICLine:=BASICLine+'February';
    3: BASICLine:=BASICLine+'March';
    4: BASICLine:=BASICLine+'April';
    5: BASICLine:=BASICLine+'May';
    6: BASICLine:=BASICLine+'June';
    7: BASICLine:=BASICLine+'July';
    8: BASICLine:=BASICLine+'August';
    9: BASICLine:=BASICLine+'September';
   10: BASICLine:=BASICLine+'October';
   11: BASICLine:=BASICLine+'November';
   12: BASICLine:=BASICLine+'December';
   end;
   BASICLine:=BASICLine+' '+NumberToString(WorkDT.Year)+' year. Time: ';
   GetTime(WorkDT.Hour,WorkDT.Min,WorkDT.Sec,WorkDT.Year);
   If Length(NumberToString(WorkDT.Hour))<2 Then BASICLine:=BASICLine+'0';
   BASICLine:=BASICLine+NumberToString(WorkDT.Hour)+':';
   If Length(NumberToString(WorkDT.Min))<2 Then BASICLine:=BASICLine+'0';
   BASICLine:=BASICLine+NumberToString(WorkDT.Min)+':';
   If Length(NumberToString(WorkDT.Sec))<2 Then BASICLine:=BASICLine+'0';
   WriteLn(BASICLine+NumberToString(WorkDT.Sec)+'.');
   WriteLn('Free stack space: '+NumberToString(SPtr)+' bytes.');
   Write('GNU*BASIC=>');
   ReadLn(BASICLine);
   BASICLine:=Trim(BASICLine);
   If BASICLine<>'' Then
   Case UpCase(BASICLine[1]) Of
   '0'..'9':
    Begin
     LineNumber:=Trunc(InNumber(BASICLine));
     If Error='' Then
     Begin
      If (LineNumber<1) Or (LineNumber>MaxLines) Then Error:='Invalid line number' Else
      Begin
       BASICLine:=Trim(BASICLine);
       If BASICLine='' Then Error:='Invalid line' Else
       Begin
        If Not ((Ord(UpCase(BASICLine[1]))>(Ord('A')-1)) And (Ord(UpCase(BASICLine[1]))<(Ord('Z')+1))) Then
        Error:='Invalid line' Else
        Begin
         BASICLine:=GNUBasicParseRunLine(BASICLine);
         If Error='' Then
         Begin
          If BASICLinesCount=0 Then
          Begin
           Inc(BASICLinesCount);
           Lines[BASICLinesCount].Line:=BASICLine;
           Lines[BASICLinesCount].LineNumber:=LineNumber;
          end Else
          Begin
           For Index:=1 To BASICLinesCount+1 Do
           Begin
            If Index=BASICLinesCount+1 Then
            Begin
             If BASICLinesCount=MaxLines Then
             Begin
              Error:='Too many lines';
              Break;
             end Else
             Begin
              Inc(BASICLinesCount);
              Lines[BASICLinesCount].Line:=BASICLine;
              Lines[BASICLinesCount].LineNumber:=LineNumber;
              GNUBasicSortLines;
              Break;
             end;
            end;
            If Lines[Index].LineNumber=LineNumber Then
            Begin
             Lines[Index].Line:=BASICLine;
             Break;
            end;
           end;
          end;
         end;
        end;
       end;
      end;
     end;
    end;
   'A'..'Z':
    Begin
     BASICLine:=GNUBasicParseRunLine(BASICLine);
     If Error='' Then
     GNUBasicRunLine(BASICLine);
    end;
   Else Error:='Invalid input';
   end;
   If IsSystem Then Break;
   If Error<>'' Then
   Begin
    WriteLn('FATAL! Error: '+Error+'.');
    GNUBasicClearAll(False);
   end;
  Until False;
  GNUBasicClearAll(True);
  DrawScreen;
 end;
 Procedure OutHelp;
 Begin
  StatusLine:='Help';
  Draw;
  MakeBox(1,1,80,24,'Help.','ENTER=Continue, ESC=Quit.');
  WriteLn('The personal GNU - based text editor with integrated interpretter of');
  WriteLn('the BASIC programming language.');
  WriteLn('GNUBasic, Copyright (C) 2003 Sandul Yura Valentinovich.');
  WriteLn('(C) Monday, 3 March 2003 year..');
  WriteLn('All rights reserved.');
  WriteLn('GNUBasic comes with ABSOLUTELY NO WARRANTY; for details, see the GNU');
  WriteLn('General Public License, version 2.');
  WriteLn('    This is free software, and you are welcome to redistribute it');
  WriteLn('under certain conditions from the GNU General Public License.');
  WriteLn('*********************************************************************');
  WriteLn('        BASIC line in main text can be:');
  WriteLn('        1. Empty line (or with many spaces). This line skipped with');
  WriteLn('           interpret.');
  WriteLn('        2. LineNumber Statement. Line number can contain only decimal');
  WriteLn('           digits, and must me in range: 0 - 32767. Warning! If');
  WriteLn('           LineNumber go to out of this range, GNUText can be crash');
  WriteLn('           and all your data will be lost!');
  WriteLn('Statements:');
  WriteLn('        REM [Any symbols combination.]');
  Write('        Insert comment to program.');
  GoToXY(1,1);
  Repeat
   Case ReadKey Of
   #13:
    Begin
     ClrScr;
     Break;
    end;
   #27:
    Begin
     DrawScreen;
     Exit;
    end;
   end;
  Until False;
  WriteLn('        LABEL LabelName$');
  WriteLn('        Define label.');
  WriteLn('        OPEN FileName$ FOR INPUT|OUTPUT|APPEND AS #FileNumber%');
  WriteLn('        Open file for work with it.');
  WriteLn('        CLOSE #FileNumber%');
  WriteLn('        Close file.');
  WriteLn('        PRINT [#FileNumber%,]Expression');
  WriteLn('        Output to file or screen.');
  WriteLn('        CLS');
  WriteLn('        Clear the screen.');
  WriteLn('        COLOR BackGroundColor%,ForeGroundColor%');
  WriteLn('        Set screen color.');
  WriteLn('        LOCATE Column%,Row%');
  WriteLn('        Move screen cursor.');
  WriteLn('        SOUND Frequency%,Duration%');
  WriteLn('        Play sound (duration set in miliseconds (1/1000 of second)).');
  WriteLn('        NAME FileName$ AS NewFileName$');
  WriteLn('        Rename file.');
  WriteLn('        MKDIR DirectoryName$');
  Write('        Create directory.');
  GoToXY(1,1);
  Repeat
   Case ReadKey Of
   #13:
    Begin
     ClrScr;
     Break;
    end;
   #27:
    Begin
     DrawScreen;
     Exit;
    end;
   end;
  Until False;
  WriteLn('        CHDIR DirectoryName$');
  WriteLn('        Change current directory.');
  WriteLn('        RMDIR DirectoryName$');
  WriteLn('        Remove directory.');
  WriteLn('        KILL FileMask$');
  WriteLn('        Delete files.');
  WriteLn('        FILES FileMask$');
  WriteLn('        Out files.');
  WriteLn('        WINDOW (UpperColumn%,UpperRow%)-(LowerColumn%,LowerRow%)');
  WriteLn('        Redirect scree to window.');
  WriteLn('        GO TO|SUB Expression');
  WriteLn('        Run GO TO or GO SUB statement. If expression result is');
  WriteLn('        numeric, then GO TO or GO SUB to line, started with line');
  WriteLn('        number in this meaning. If expression result is string, then');
  WriteLn('        GO TO or GO SUB to line, contain statement: LABEL LabelName$.');
  WriteLn('        Warning! Label name is case sensitive!');
  WriteLn('        RETURN');
  WriteLn('        Return from GO SUB subroutine.');
  WriteLn('        TRON');
  Write('        Set trace mode to on.');
  GoToXY(1,1);
  Repeat
   Case ReadKey Of
   #13:
    Begin
     ClrScr;
     Break;
    end;
   #27:
    Begin
     DrawScreen;
     Exit;
    end;
   end;
  Until False;
  WriteLn('        TROFF');
  WriteLn('        Set trace mode to off.');
  WriteLn('        END');
  WriteLn('        End current running program.');
  WriteLn('        DEF FNName[(Arg[,Arg...])]=Expression');
  WriteLn('        Declare the user - defined function.');
  WriteLn('        LET VarName=Expression');
  WriteLn('        Set value for variable.');
  WriteLn('        WHILE Conditional');
  WriteLn('        WEND');
  WriteLn('        The WHILE loop.');
  WriteLn('        FROM VarName%=StartValue% TO EndValue%');
  WriteLn('        NEXT VarName%');
  WriteLn('        The FROM (like FOR) loop.');
  WriteLn('        EXIT WHILE|FROM');
  WriteLn('        Exit from current WHILE or FROM loop.');
  WriteLn('        IF Conditional THEN Statement[ ELSE Statement]');
  WriteLn('        The IF conditional operator.');
  WriteLn('System variables:');
  Write('        DATE$');
  GoToXY(1,1);
  Repeat
   Case ReadKey Of
   #13:
    Begin
     ClrScr;
     Break;
    end;
   #27:
    Begin
     DrawScreen;
     Exit;
    end;
   end;
  Until False;
  WriteLn('        Contain current date in format: MM-DD-YYYY.');
  WriteLn('        TIME$');
  WriteLn('        Contain current time in format: HH:MM:SS.');
  WriteLn('String functions:');
  WriteLn('        INKEY$');
  WriteLn('        If pressed any alphabetic or numeric key, then return it (one');
  WriteLn('        symbol length string). If pressed special keys (like F1 -');
  WriteLn('        F10), then return two - symbols string: CHR$(0)+');
  WriteLn('        CHR$(CodeOfKey%). If keys is not pressed, then return empty');
  WriteLn('        string.');
  WriteLn('        INPUT$[(#FileNumber%)]');
  WriteLn('        Perform input from keyboard or file.');
  WriteLn('        STR$(Value%)');
  WriteLn('        Number, converted to string.');
  WriteLn('        CHR$(Code%)');
  WriteLn('        Symbol on code.');
  WriteLn('        TRIM$(Line$)');
  WriteLn('        Line$ without leading and trailing spaces.');
  WriteLn('        MID$(Line$,Start%,Count%)');
  Write('        Part of Line$, startted on Start% symbol, length Count%');
  GoToXY(1,1);
  Repeat
   Case ReadKey Of
   #13:
    Begin
     ClrScr;
     Break;
    end;
   #27:
    Begin
     DrawScreen;
     Exit;
    end;
   end;
  Until False;
  WriteLn('        symbols.');
  WriteLn('        DAYOFWEEK(Year%,Month%,Day%)');
  WriteLn('        Return name of day.');
  WriteLn('Numeric functions:');
  WriteLn('        LEN(Line$)');
  WriteLn('        Return length of line.');
  WriteLn('        INSTR(Line$,SubLine$)');
  WriteLn('        Return number of first occurence of SubLine$ in Line$.');
  WriteLn('        ASC(Line$)');
  WriteLn('        Return code of first symbol in line.');
  WriteLn('        CRC32(Line$)');
  WriteLn('        Return CRC-32 code of line.');
  WriteLn('        VAL(Value$)');
  WriteLn('        Convert string number to number.');
  WriteLn('        SQR(Value#)');
  WriteLn('        Return the square root of value.');
  WriteLn('        ABS(Value#)');
  WriteLn('        Return absolute value of Value#.');
  WriteLn('        INT(Value#)');
  Write('        Return integer part of Value#.');
  GoToXY(1,1);
  Repeat
   Case ReadKey Of
   #13:
    Begin
     ClrScr;
     Break;
    end;
   #27:
    Begin
     DrawScreen;
     Exit;
    end;
   end;
  Until False;
  WriteLn('        SIN(Value#)');
  WriteLn('        Return sine of Value#.');
  WriteLn('        COS(Value#)');
  WriteLn('        Return co - sine of Value#.');
  WriteLn('        ATN(Value#)');
  WriteLn('        Return arc tangent of Value#.');
  WriteLn('        EOF(#FileNumber%)');
  WriteLn('        If EOF, then return 1 (true), else return 0 (false).');
  WriteLn('Constans:');
  WriteLn('        PI=3.1415926535897932385,BLACK=0,BLUE=1,GREEN=2,CYAN=3,RED=4,');
  WriteLn('        MAGENTA=5,BROWN=6,LIGHTGRAY=7,DARKGRAY=8,LIGHTBLUE=9,');
  WriteLn('        LIGHTGREEN=10,LIGHTCYAN=11,LIGHTRED=12,LIGHTMAGENTA=13,');
  WriteLn('        YELLOW=14,WHITE=15,FALSE=0,TRUE=-1');
  WriteLn('Operators:');
  WriteLn('        Value[!|@|#|$|%|&]      +       Value[!|@|#|$|%|&]');
  WriteLn('        Value[!|@|#|%|&]        -       Value[!|@|#|%|&]');
  WriteLn('        Value[!|@|#|%|&]        /       Value[!|@|#|%|&]');
  WriteLn('        Value[!|@|#|%|&]        \       Value[!|@|#|%|&]');
  WriteLn('        Value[!|@|#|%|&]        *       Value[!|@|#|%|&]');
  Write('        Value[!|@|#|$|%|&]      =       Value[!|@|#|$|%|&]');
  GoToXY(1,1);
  Repeat
   Case ReadKey Of
   #13:
    Begin
     ClrScr;
     Break;
    end;
   #27:
    Begin
     DrawScreen;
     Exit;
    end;
   end;
  Until False;
  WriteLn('        Value[!|@|#|$|%|&]      <       Value[!|@|#|$|%|&]');
  WriteLn('        Value[!|@|#|$|%|&]      >       Value[!|@|#|$|%|&]');
  WriteLn('        Value[!|@|#|$|%|&]      <=      Value[!|@|#|$|%|&]');
  WriteLn('        Value[!|@|#|$|%|&]      =<      Value[!|@|#|$|%|&]');
  WriteLn('        Value[!|@|#|$|%|&]      =>      Value[!|@|#|$|%|&]');
  WriteLn('        Value[!|@|#|$|%|&]      >=      Value[!|@|#|$|%|&]');
  WriteLn('        Value[!|@|#|$|%|&]      <>      Value[!|@|#|$|%|&]');
  WriteLn('        Value[!|@|#|$|%|&]      ><      Value[!|@|#|$|%|&]');
  WriteLn('        Value[!|@|#|%|&]        AND     Value[!|@|#|%|&]');
  WriteLn('        Value[!|@|#|%|&]        OR      Value[!|@|#|%|&]');
  WriteLn('        Value[!|@|#|%|&]        XOR     Value[!|@|#|%|&]');
  WriteLn('        Value[!|@|#|%|&]        MOD     Value[!|@|#|%|&]');
  WriteLn('                                NOT     Value[!|@|#|%|&]');
  WriteLn('Note:');
  WriteLn('     "Print" statement output must be one expression any type.');
  WriteLn('     String expression for "Print" statement can be contain ANSI');
  WriteLn('     escape sequences: in GNUText integrated ANSI terminal emulator.');
  WriteLn('     Resource of GNUText:');
  WriteLn('     Maximal count of text lines = 32768, whiles = 256, froms = 256,');
  Write('     files = 256, deffns = 256, maximal arguments count for deffn =');
  GoToXY(1,1);
  Repeat
   Case ReadKey Of
   #13:
    Begin
     ClrScr;
     Break;
    end;
   #27:
    Begin
     DrawScreen;
     Exit;
    end;
   end;
  Until False;
  WriteLn('     64, variables = 768, gosubs = 256, maximal arguments count for');
  Write('     ANSI sequence = 4.');
  GoToXY(1,1);
  Repeat
   Case ReadKey Of
   #13:
    Begin
     ClrScr;
     Break;
    end;
   #27:
    Begin
     DrawScreen;
     Exit;
    end;
   end;
  Until False;
  DrawScreen;
 end;
 Procedure Quit;
 Begin
  StatusLine:='Quit.';
  Draw;
  If MessageBox('Quit.','Save file before quit?') Then
  Begin
   SaveFile;
   If ErrorStatus Then Exit;
  end;
  Window(1,1,80,25);
  TextBackGround(Black);
  TextColor(LightGray);
  ClrScr;
  Halt;
 end;
Begin
 StatusLine:='Menu.';
 Draw;
 MakeBox(19,5,43,17,'GNUText Menu.','Please select menu item or ESC to cancel.');
 WriteLn('A=Save file.');
 WriteLn('B=Load file.');
 WriteLn('C=Change name of current file');
 WriteLn('('+GNUTextFileName+').');
 WriteLn('D=Find line.');
 WriteLn('E=Replace line.');
 WriteLn('F=Replace all lines.');
 WriteLn('G=Parse program text.');
 WriteLn('H=Run program.');
 WriteLn('I=Run current line.');
 WriteLn('J=Run GNUBasic linear interpretter.');
 WriteLn('K=Help.');
 Write('L=Quit from editor.');
 GoToXY(1,1);
 Repeat
  Key:=UpCase(ReadKey);
  Case Key Of
  'A'..'L':
   Begin
    Case Key Of
    'A': SaveFile;
    'B': LoadFile;
    'C': ChangeFile;
    'D': FindLine;
    'E': ReplaceLine;
    'F': ReplaceAllLines;
    'G': ParseProgramText;
    'H': RunProgram;
    'I': RunCurrentLine;
    'J': GNUBasicInterpretter;
    'K': OutHelp;
    'L': Quit;
    end;
    Break;
   end;
  #27: Break;
  end;
 Until False;
 StatusLine:=StandartStatus;
 Draw;
end;
Begin
 If (Lo(DOSVersion)<3) And (Hi(DOSVersion)<30) Then
 Begin
  WriteLn('This program required DOS version 3.30 or above.');
  Exit;
 end;
 TextMode(Co80);
 CheckBreak:=False;
 CheckEOF:=False;
 DirectVideo:=False;
 CheckSnow:=True;
 DrawScreen;
 CursorRow:=1;
 CursorColumn:=1;
 TextPosition:=1;
 LinePosition:=1;
 StatusLine:='Welkome to GNUText!';
 Draw;
 MakeBox(9,7,64,13,'The Personal GNU Text editor.','ENTER=Continue.');
 WriteLn('The personal GNU - based text editor.');
 WriteLn('This editor contain integrated BASIC language interpretter');
 WriteLn('(like Microsoft(R) GW-BASIC).');
 WriteLn('GNUText, Copyright (C) 2003 Sandul Yura Valentinovich.');
 WriteLn('(C) Monday, 3 March 2003 year.');
 WriteLn('All rights reserved.');
 WriteLn('GNUText comes with ABSOLUTELY NO WARRANTY; for details, see');
 WriteLn('the GNU General Public License, version 2. This is free');
 WriteLn('software, and you are welcome to redistribute it under');
 Write('certain conditions from the GNU General Public License.');
 GoToXY(1,1);
 Repeat
 Until ReadKey=#13;
 GNUTextFileName:='GNUText.txt';
 StatusLine:=StandartStatus;
 Draw;
 Repeat
  Key:=ReadKey;
  Case Key Of
  #0:
   Case ReadKey Of
   #75: CursorLeft;
   #77: CursorRight;
   #72: CursorUp;
   #80: CursorDown;
   #71:
    Begin
     CursorColumn:=1;
     LinePosition:=1;
     StatusLine:=StandartStatus;
     Draw;
    end;
   #79:
    Begin
     CursorColumn:=Length(TextLines[CursorRow])+1;
     LinePosition:=CursorColumn;
     Control;
    end;
   #73:
    Begin
     Dec(CursorRow,22);
     Dec(TextPosition,22);
     Control;
    end;
   #81:
    Begin
     Inc(CursorRow,22);
     Inc(TextPosition,22);
     Control;
    end;
   #83: DeleteText;
   end;
  #8: BackDelete;
  #13: EnterLine;
  #27: Menu;
  Else InsertChar(Key);
  end;
 Until False;
 Window(1,1,80,25);
 TextBackGround(Black);
 TextColor(LightGray);
 ClrScr;
end.