OComp.pas
上传用户:yj_qiu
上传日期:2022-08-08
资源大小:23636k
文件大小:69k
源码类别:

游戏引擎

开发平台:

Delphi

  1. (*
  2.  Oberon compiler unit
  3.  (C) 2004-2007 George "Mirage" Bakhtadze. <a href="http://www.casteng.com">www.casteng.com</a> <br>
  4.  The source code may be used under either MPL 1.1 or LGPL 2.1 license. See included license.txt file <br>
  5.  The unit contains compiler main class
  6. *)
  7. {$DEFINE DEBUG}
  8. unit OComp;
  9. interface
  10. uses SysUtils,
  11. {$IFDEF DEBUG} Classes, {$ENDIF}
  12.   OTypes, OScan, ORun, Dialogs;
  13. const
  14.   ConstMask  = 0 shl 24; VarMask = 1 shl 24; ProcMask = 2 shl 24;
  15.   ArrayMask = 4 shl 24; COArrayMask = 8 shl 24; ResWordMask = 16 shl 24; 
  16.   AllMask = 127 shl 24;
  17. type
  18.   TCompiledModule = record
  19.   end;
  20.   TTokenSet = set of TToken;
  21.   TCompiler = class
  22.     Scaner: TScaner;
  23.     Error: Boolean;
  24.     CError: TCompilationError;
  25.     CurNamespace, Namespace: PNamespace;       // Current and global namespaces
  26.     LastExpConstant: Boolean;
  27.     LoopCount: Integer;
  28. // Run-time data
  29.     Data: TRTData;
  30.     ExternalVars: array of record
  31.       VarAddress: Pointer;
  32.       VarName, VarType: string;
  33.     end;
  34.     constructor Create(AScaner: TScaner);
  35.     destructor Destroy; override;
  36.     procedure Reset;
  37.     function Compile: Integer;
  38.     function ImportExternalVar(AName, AType: string; Address: Pointer): Boolean;
  39.     function GetExternalVarIndex(AName: string): Integer;
  40.     function AddType(AName: TName): PType;
  41.     procedure ClearType(AType: PType); virtual;
  42.     function NewNamespace(AName: TName): PNamespace;
  43.     procedure AddNamespace(AName: TName); virtual;
  44.     procedure ClearNamespace(NS: PNamespace); virtual;
  45.     function AllocateData(const DataSize, Value: Integer): Integer;
  46.     function AllocateStack(const DataSize: Integer): Integer;
  47.     function AddIdent(AKind: Int32; AName: TName; AType, AValue: Integer): Integer; overload;
  48.     function AddIdentS(AKind: Int32; AName: TName; AType: Integer; AValue: Single): Integer; overload;
  49.     function CheckIdent(AName: TName; NS: PNamespace; SearchToRoot: Boolean; var IdentKind: Integer): Int32;
  50.     function SpecifyArray(TypeID: Integer; var Offset: Integer; var RuntimeOffs: Boolean): Integer;
  51.     function SpecifyRecord(TypeID: Integer; var Offset: Integer; var RuntimeOffs: Boolean): Integer;
  52.     function SpecifyVariable(AName: TName; TypeID: Integer; var Offset: Integer; var RuntimeOffs: Boolean): Integer;
  53.     function CompileBlock(ReturnType: Integer): Integer;
  54.     function ComputeExpression(StartPIN: Integer): Integer;
  55.     function SetNValue(PINIndex: Integer; Buffer: string; SetType: Boolean): Integer;
  56.     function SetSValue(PINIndex: Integer; Buffer: string): Integer;
  57.     function isNumeric(AType: Integer): Boolean;
  58.     function isInteger(AType: Integer): Boolean;
  59.     function isReal(AType: Integer): Boolean;
  60.   private
  61.     LocalVM: TOberonVM;
  62.     TotalNamesSpaces: Integer;
  63.     procedure AddOperation(LastOp, OldType: Integer; var Res: Integer);
  64.     function ControlTypes(var Operation: Integer; Type1, Type2: Integer): Integer;
  65.     procedure SynError(ASource: string; AErrorNum: Integer; AErrorData: Integer);
  66.     function CheckEnd(Buf: string): Integer;
  67.     function CheckOperator(Buf: string): Integer;
  68.     function GetOp1: Integer;
  69.     function Exp1: Integer;
  70.     function Exp2: Integer;
  71.     function SimplifyExpression(Loc: Integer): Integer;
  72.     function Expression: Integer;
  73.     function ConstantExpression(var ExpResult: Integer): Integer;
  74.     function GetOperator(Buf: string): Integer;
  75.     procedure ParseAssign(IdentID, IdentOffset: Integer);
  76.     procedure ParseLoop(ReturnType: Integer);
  77.     procedure ParseWhile(ReturnType: Integer);
  78.     procedure ParseRepeat(ReturnType: Integer);
  79.     procedure ParseFor(ReturnType: Integer);
  80.     procedure ParseIf(ReturnType: Integer);
  81.     procedure ParseCall(const ProcID: Integer);
  82.     procedure SetVarLocation(var AVar: TIdent; ALocation: Integer);
  83.     function ParseVarSection: Integer;
  84.     function ParseVar: Integer;
  85.     procedure ParseConst;
  86.     procedure ParseProc;
  87.     function ParseTypeDef(TypeName: TName; AlwaysNew: Boolean): Integer;
  88.     procedure ParseType;
  89.     function GetDeclaration(Buf: string): Integer;
  90. //    function GetTypeKind(TID: Integer): Integer;
  91.     function GetType(Buf: string): Integer;
  92.     function GetTypeSize(const TID: Integer): Integer;
  93.     function GetConst(const Index: Integer): Integer;
  94.     function Operators(ReturnType: Integer): Integer;
  95.     function Declarations: Integer;
  96.   end;
  97. implementation
  98. function TCompiler.SetNValue(PINIndex: Integer; Buffer: string; SetType: Boolean): Integer;            // ToFix: Check values range
  99. var i: Integer; Temp: Extended; DecPos: Int32;
  100. function HexStrToInt: Integer;
  101. var i: Integer;
  102. begin
  103.   Result := 0;
  104.   for i := 1 to Length(Buffer)-1 do begin
  105.     if Buffer[i] in ['0'..'9'] then
  106.      Result := (Result shl 4) or (Ord(Buffer[i]) - Ord('0')) else
  107.       if UpCase(Buffer[i]) in ['A'..'F'] then begin
  108.         if i = 1 then SynError('HexStrToStr', eInvalidNumber, 0) else
  109.         Result := (Result shl 4) or (Ord(UpCase(Buffer[i])) - Ord('A') + 10)
  110.       end else SynError('HexStrToStr', eInvalidNumber, 0);
  111.   end;
  112.   if UpCase(Buffer[Length(Buffer)]) <> 'H' then SynError('HexStrToStr', eInvalidNumber, 0);
  113. end;
  114. begin
  115.   Result := -1;
  116.   DecPos := Pos('.', Buffer);
  117.   if DecPos = 0 then begin
  118.     Data.PIN[PINIndex+1] := StrToIntDef(Buffer, 0);
  119.     for i := 1 to Length(Buffer) do if not (UpCase(Buffer[i]) in ['0'..'9']) then begin
  120.       Data.PIN[PINIndex+1] := HexStrToInt;                     // Number in hex format
  121.       Break;
  122.     end;
  123.     if Error then Exit;
  124.     if SetType then Data.PIN[PINIndex] := GetVTypeInt(Data.PIN[PINIndex+1]);
  125.   end else begin
  126.     if Pos('.', Copy(Buffer, DecPos+1, Length(Buffer))) > 0 then begin
  127.       SynError('SetNValue', eInvalidNumber, 0);
  128.       Exit;
  129.     end;
  130.     for i := 1 to Length(Buffer) do if not (UpCase(Buffer[i]) in ['0'..'9', 'D', 'E', '.', '-', '+']) then begin
  131.       SynError('SetNValue', eInvalidNumber, 0);
  132.       Exit;
  133.     end;
  134.     Buffer[DecPos] := ',';
  135.     DecPos := Length(Buffer)-DecPos;
  136.     case DecPos of
  137.       1..7: Data.PIN[PINIndex] := dtSingle;                         // ToFix: Wrong type checking
  138.       8..15: Data.PIN[PINIndex] := dtDouble;
  139.       else Data.PIN[PINIndex] := dtReal;
  140.     end;
  141.     Temp := StrToFloat(Buffer);
  142.     Single((@Data.PIN[PINIndex+1])^) := Temp;
  143.   end;
  144.   Result := Data.PIN[PINIndex];
  145. end;
  146. function TCompiler.SetSValue(PINIndex: Integer; Buffer: string): Integer;
  147. var Len: Nat16;
  148. begin
  149.   Result := -1;
  150.   Data.PIN[PINIndex+1] := Data.DataLength;
  151.   Data.PIN[PINIndex] := dtString;
  152.   Len := Length(Buffer);
  153.   Move(Len, Pointer(Int32(Data.Data)+Data.DataLength)^, 2);
  154.   if Len > 0 then Move(Buffer[1], Pointer(Int32(Data.Data)+Data.DataLength+2)^, Len);
  155.   Inc(Data.DataLength, Len+2);
  156.   Result := Data.PIN[PINIndex];
  157. end;
  158. function TCompiler.AddType(AName: TName): PType;
  159. begin
  160.   Assert(CurNamespace <> nil, 'AddType: Current namespace is nil');
  161.   New(Result);
  162.   Inc(Data.TotalTypes); SetLength(Data.Types, Data.TotalTypes);
  163.   Data.Types[Data.TotalTypes-1] := Result;
  164.   Inc(CurNamespace.TotalTypes); SetLength(CurNamespace.Types, CurNamespace.TotalTypes);
  165.   CurNamespace.Types[CurNamespace.TotalTypes-1] := Data.TotalTypes-1;
  166.   Result.Name := AName;
  167.   Result.ID := Data.TotalTypes-1;
  168.   Result.Kind := 0;
  169.   Result.Namespace := nil;
  170.   Result.Size := SizeOf(TStackItem);
  171. end;
  172. function TCompiler.NewNamespace(AName: TName): PNamespace;
  173. begin
  174.   New(Result);
  175.   Result.Name := AName;
  176.   Result.TotalConstants := 0; SetLength(Result.Constants, 0);
  177.   Result.TotalVariables := 0; SetLength(Result.Variables, 0);
  178.   Result.TotalProcedures := 0; SetLength(Result.Procedures, 0);
  179.   Result.TotalTypes := 0; SetLength(Result.Types, 0);
  180.   Result.Parent := nil;
  181.   Result.Kind := nskModule;
  182.   Result.StackLength := 0;
  183.   Result.ParamCount := 0; Result.ID := 0;
  184.   Result.UID := TotalNamesSpaces;
  185.   Inc(TotalNamesSpaces);
  186. end;
  187. procedure TCompiler.AddNamespace(AName: TName);
  188. var NewNS: PNamespace;
  189. begin
  190.   NewNS := NewNamespace(AName);
  191.   if CurNamespace = nil then Namespace := NewNS else begin
  192.     Inc(CurNamespace.TotalProcedures); SetLength(CurNamespace.Procedures, CurNamespace.TotalProcedures);
  193.     CurNamespace.Procedures[CurNamespace.TotalProcedures-1] := NewNS;
  194.   end;
  195.   NewNS.Parent := CurNamespace;
  196.   CurNamespace := NewNS;
  197. end;
  198. procedure TCompiler.ClearType(AType: PType);
  199. begin
  200.   if AType.Namespace <> nil then ClearNamespace(AType.Namespace);
  201. end;
  202. procedure TCompiler.ClearNamespace(NS: PNamespace);
  203. var i: Integer;
  204. begin
  205.   NS.TotalConstants := 0; SetLength(NS.Constants, 0);
  206.   NS.TotalVariables := 0; SetLength(NS.Variables, 0);
  207.   NS.TotalTypes := 0; SetLength(NS.Types, 0);
  208.   for i := 0 to NS.TotalProcedures-1 do begin
  209.     ClearNamespace(NS.Procedures[i]);
  210.     Dispose(NS.Procedures[i]);
  211.   end;
  212.   NS.TotalProcedures := 0; SetLength(NS.Procedures, 0);
  213. end;
  214. function TCompiler.AddIdent(AKind: Int32; AName: TName; AType, AValue: Integer): Integer;
  215. // Adds constant, variable or procedure identifier
  216. // In case of variable doesn't allocate data
  217. // Returns index of the new identifier
  218. var Offset, IdentKind: Integer;
  219. begin
  220.   Result := -1;
  221.   case AKind of
  222.     ikConstant: begin
  223.       Inc(Data.TotalConstants); SetLength(Data.Constants, Data.TotalConstants);
  224.       with Data.Constants[Data.TotalConstants-1] do begin
  225.         Name := AName; TypeID := AType; Namespace := CurNamespace;
  226.         Index := AllocateData(GetTypeSize(AType), AValue);
  227.         Location := ilGlobal;
  228.       end;
  229.       Inc(CurNamespace.TotalConstants); SetLength(CurNamespace.Constants, CurNamespace.TotalConstants);
  230.       CurNamespace.Constants[CurNamespace.TotalConstants-1] := Data.TotalConstants-1;
  231.       Result := Data.TotalConstants-1;
  232.     end;
  233.     ikVariable: begin
  234.       Offset := CheckIdent(AName, Namespace, False, IdentKind);
  235.       if (CurNamespace <> NameSpace) or (Offset = -1) then begin
  236.         Inc(Data.TotalVariables); SetLength(Data.Variables, Data.TotalVariables);
  237.         with Data.Variables[Data.TotalVariables-1] do begin
  238.           Name := AName; TypeID := AType; Namespace := CurNamespace;
  239. //          if Data.Types[AType].Kind <> tkRecord then begin
  240. //          end;
  241.         end;
  242.         Inc(CurNamespace.TotalVariables); SetLength(CurNamespace.Variables, CurNamespace.TotalVariables);
  243.         CurNamespace.Variables[CurNamespace.TotalVariables-1] := Data.TotalVariables-1;
  244.         Result := Data.TotalVariables-1;
  245.       end else Result := Offset and not AllMask;
  246.     end;
  247.     ikProcedure: begin
  248.       Inc(Data.TotalProcedures); SetLength(Data.Procedures, Data.TotalProcedures);
  249.       with Data.Procedures[Data.TotalProcedures-1] do begin
  250.         Name := AName; TypeID := AType; Namespace := CurNamespace;
  251.         Index := AllocateData(4, AValue);
  252.         Location := ilGlobal;
  253.       end;
  254. //      Inc(CurNamespace.TotalProcedures); SetLength(CurNamespace.Procedures, CurNamespace.TotalProcedures);
  255. //      CurNamespace.Procedures[CurNamespace.TotalProcedures-1].Value := TotalProcedures-1;
  256.       Result := Data.TotalProcedures-1
  257.     end;
  258.     ikType:;{ begin
  259.       Inc(Data.TotalTypes); SetLength(Data.Types, Data.TotalTypes);
  260.       with Data.Types[Data.TotalTypes-1] do begin
  261.         Name := AName; Value := AValue; TypeID := AType; Namespace := CurNamespace;
  262.       end;
  263.     end;}
  264.     else Assert(False, 'Invalid identifier kind');
  265.   end;
  266. end;
  267. function TCompiler.AddIdentS(AKind: Int32; AName: TName; AType: Integer; AValue: Single): Integer;
  268. begin
  269.   Result := AddIdent(AKind, AName, AType, Integer((@AValue)^));
  270. end;
  271. procedure TCompiler.SynError(ASource: string; AErrorNum: Integer; AErrorData: Integer);
  272. begin
  273.   if Error then Exit;
  274.   with CError do begin
  275.     Source := ASource;
  276.     Line := Scaner.CurLine;
  277.     Position := Scaner.SourcePos;
  278.     Number := AErrorNum;
  279.     Data := AErrorData;
  280.   end;
  281.   Error := True;
  282. end;
  283. function TCompiler.CheckEnd(Buf: string): Integer;
  284. var i: Integer;
  285. begin
  286.   Result := -1;
  287.   for i := 0 to TotalEndTokens-1 do if Buf = EndTokenStr[i] then begin
  288.     Result := i;
  289.     Break;
  290.   end;
  291. end;
  292. function TCompiler.CheckOperator(Buf: string): Integer;
  293. var i: Integer;
  294. begin
  295.   Result := -1;
  296.   for i := 0 to TotalOperators-1 do if Buf = OperatorStr[i] then begin
  297.     Result := i;
  298.     Break;
  299.   end;
  300. end;
  301. function TCompiler.SpecifyArray(TypeID: Integer; var Offset: Integer; var RuntimeOffs: Boolean): Integer;
  302. // Parses "["Exp"]"
  303. var i, ExpStartPIN: Integer; ch: Char;
  304. begin
  305. //  Assert(Data.Types[TID].ID = TID, 'CheckIdent.SpecifyArray: Type ID mismatch');
  306.   Scaner.SkipDelims;
  307.   Scaner.ReadChar(ch);
  308.   if ch <> '[' then begin Result := TypeID; Scaner.ReturnChar(ch); Exit; end;
  309.   ExpStartPIN := Data.PINItems;
  310.   LastExpConstant := True;
  311.   if not isInteger(Exp1) then begin
  312.     SynError('SpecifyArray', eIntExpExpected, 0);
  313.     Exit;
  314.   end;
  315.   if Error then Exit;
  316.   if LastExpConstant then begin
  317.     Offset := Offset + ComputeExpression(ExpStartPIN) * GetTypeSize(Data.Types[TypeID].ID);
  318.     Data.PINItems := ExpStartPIN;
  319.   end else begin
  320.     Inc(Data.PINItems, 3); SetLength(Data.PIN, Data.PINItems);
  321.     Data.PIN[Data.PINItems-3] := dtInt;
  322.     Data.PIN[Data.PINItems-2] := GetTypeSize(Data.Types[TypeID].ID);
  323.     Data.PIN[Data.PINItems-1] := aoMulII;                              // Multiply expression by element size
  324.     if RuntimeOffs then begin
  325.       Inc(Data.PINItems, 1); SetLength(Data.PIN, Data.PINItems);
  326.       Data.PIN[Data.PINItems-1] := aoAddII;                              // Add base variable address
  327.     end;
  328.     RuntimeOffs := True;
  329.   end;
  330.   Scaner.SkipDelims;
  331.   Scaner.ReadChar(ch);
  332.   if ch <> ']' then begin
  333.     SynError('SpecifyArray', eRightBracketExpected, 0);
  334.     Exit;
  335.   end;
  336.   case Data.Types[Data.Types[TypeID].ID].Kind of
  337.     tkCommon: Result := Data.Types[TypeID].ID;
  338.     tkRecord: Result := SpecifyRecord(Data.Types[TypeID].ID, Offset, RuntimeOffs);
  339.     tkArray: Result := SpecifyArray(Data.Types[TypeID].ID, Offset, RuntimeOffs);
  340.   end;
  341. end;
  342. function TCompiler.SpecifyRecord(TypeID: Integer; var Offset: Integer; var RuntimeOffs: Boolean): Integer;
  343. // Parses "."ident
  344. // Returns field index
  345. var ch: Char; FieldIndex, TempIdentKind: Integer;
  346. begin
  347.   Scaner.SkipDelims;
  348.   Scaner.ReadChar(ch);
  349.   if ch <> '.' then begin Result := TypeID; Scaner.ReturnChar(ch); Exit; end;
  350.   Scaner.SkipDelims;
  351.   Scaner.ReadChar(ch);
  352.   Scaner.GetIdent(ch);
  353.   if Scaner.Buf = '' then SynError('SpecifyRecord', eVariableExpected, 0) else
  354.   FieldIndex := CheckIdent(Scaner.Buf, Data.Types[TypeID].Namespace, False, TempIdentKind);
  355.   if FieldIndex = -1 then begin                                       // Not found
  356.     SynError('SpecifyRecord', eUndeclaredIdentifier, 0); Exit;
  357.   end;
  358.   if (TempIdentKind and ResWordMask > 0) then begin                     // Found, but is reserved word
  359.     SynError('SpecifyRecord', eUnexpectedResWord, 0); Exit;
  360.   end;
  361.   Offset := Offset + Data.Variables[FieldIndex].Index;
  362.   case Data.Types[Data.Variables[FieldIndex].TypeID].Kind of
  363.     tkCommon: Result := Data.Variables[FieldIndex].TypeID;
  364.     tkRecord: Result := SpecifyRecord(Data.Variables[FieldIndex].TypeID, Offset, RuntimeOffs);
  365.     tkArray: Result := SpecifyArray(Data.Variables[FieldIndex].TypeID, Offset, RuntimeOffs);
  366.   end;
  367. end;
  368. function TCompiler.SpecifyVariable(AName: TName; TypeID: Integer; var Offset: Integer; var RuntimeOffs: Boolean): Integer;
  369. // Calculates offset of specified field in record or array element of specified type
  370. // Returns type ID of the element specified
  371. // In offset returns offset of specified element
  372. // In IdentKind returns identifier kind (constant offset or run-time calculated offset)
  373. // Adds to PIN code to calculate runtime calculating offset
  374. begin
  375.   Result := TypeID;
  376.   RuntimeOffs := False;
  377.   case Data.Types[TypeID].Kind of
  378.     tkRecord: Result := SpecifyRecord(TypeID, Offset, RuntimeOffs);
  379.     tkArray: Result := SpecifyArray(TypeID, Offset, RuntimeOffs);
  380.   end;
  381.   if RuntimeOffs then begin
  382.       Inc(Data.PINItems, 3); SetLength(Data.PIN, Data.PINItems);
  383.       Data.PIN[Data.PINItems-3] := dtInt;
  384.       Data.PIN[Data.PINItems-2] := Offset;
  385.       Data.PIN[Data.PINItems-1] := aoAddII;                              // Add base variable address
  386.     end;
  387. {  if Result and ArrayMask > 0 then begin
  388.     Inc(Data.PINItems, 3); SetLength(Data.PIN, Data.PINItems);
  389.     Data.PIN[Data.PINItems-3] := dtInt;
  390.     Data.PIN[Data.PINItems-2] := Offset;
  391.     Data.PIN[Data.PINItems-1] := aoAddII;                              // Add base variable address
  392.   end;}
  393. end;
  394. function TCompiler.CheckIdent(AName: TName; NS: PNamespace; SearchToRoot: Boolean; var IdentKind: Integer): Int32;
  395. // Searches identifier by name specified
  396. // in current namespace and above namespaces if SearchToRoot is true.
  397. // Returns index in Constants, Variables etc array
  398. // In IdentKind returns kind of identifier (reserved word, constant, variable or procedure)
  399. var i: Integer; ch: Char;
  400. begin
  401.   Result := -1;
  402.   for i := 0 to TotalReservedWords-1 do if AName = ReservedWord[i] then begin
  403.     Result := i; IdentKind := ResWordMask; Exit;
  404.   end;
  405.   while NS <> nil do begin
  406.     for i := 0 to NS.TotalConstants-1 do if Data.Constants[NS.Constants[i]].Name = AName then begin
  407.       Result := NS.Constants[i]; IdentKind := ConstMask; Exit;
  408.     end;
  409.     for i := 0 to NS.TotalVariables-1 do if Data.Variables[NS.Variables[i]].Name = AName then begin
  410.       Result := NS.Variables[i]; IdentKind := VarMask; Exit;
  411.     end;
  412.     for i := 0 to NS.TotalProcedures-1 do if NS.Procedures[i].Name = AName then begin
  413.       Result := NS.Procedures[i].ID; IdentKind := ProcMask; Exit;
  414.     end;
  415.     if SearchToRoot then NS := NS.Parent else NS := nil;
  416.   end;
  417. end;
  418. procedure TCompiler.AddOperation(LastOp, OldType: Integer; var Res: Integer);
  419. begin
  420.   if LastOp <> aoNull then begin
  421.     Res := ControlTypes(LastOp, OldType, Res);
  422.     Inc(Data.PINItems, 1); SetLength(Data.PIN, Data.PINItems);
  423.     Data.PIN[Data.PINItems-1] := LastOp;
  424.   end;
  425. end;
  426. function TCompiler.GetOp1: Integer;
  427. var i: Integer;
  428. begin
  429.   Result := -1;
  430.   for i := 0 to TotalOperations1-1 do if Scaner.Buf = Op1Str[i] then begin
  431.     Result := Op1ID[i]; Break;
  432.   end;
  433. end;
  434. function TCompiler.Exp1: Integer;
  435. var ch: Char; LastOp, OldType: Integer;
  436. begin
  437. // Exp1 = ['-' | '+'] Exp2 { ['-' | '+', 'OR'] Exp2}
  438. // Result - expression type
  439.   Result := -1; OldType := -1;
  440.   LastOp := aoNull;
  441. {  Scaner.SkipDelims;
  442.   Scaner.ReadChar(ch);
  443.   if ch = '-' then NegOp := oNeg else if ch <> '+' then Scaner.ReturnChar(ch);}
  444.   Result := Exp2;                                               //
  445.   Scaner.SkipDelims;
  446.   while not Error and Scaner.ReadChar(ch) and (ch <> ';') do begin
  447.     Scaner.Buf := ch;
  448.     if Scaner.isAlpha(ch) then Scaner.GetIdent(ch);
  449.     if (ch = ',') or (ch = ')') or (ch = '}') or (ch = ']') or Scaner.isRelation(ch) or
  450.        (CheckEnd(Scaner.Buf) <> -1) or (CheckOperator(Scaner.Buf) <> -1) or (Scaner.Buf = RelationStr[6]) or (Scaner.Buf = RelationStr[7])  then begin
  451.       Scaner.ReturnBuf(Scaner.Buf); Break;
  452.     end;
  453.     LastOp := GetOp1;
  454.     if LastOp = -1 then begin
  455.       SynError('Exp1', eOperationExpected, 0);
  456.       Break;
  457.     end;
  458.     OldType := Result; Result := Exp2;
  459.     if Error then Break;
  460.     AddOperation(LastOp, OldType, Result);
  461.   end;
  462.   if ch = ';' then Scaner.ReturnBuf(ch);
  463. end;
  464. function TCompiler.Exp2: Integer;
  465. var ch: Char; LastOp, IdentIndex, IdentKind: Int32; OldType: Integer;
  466. function GetOp2: Integer;
  467. var i: Integer;
  468. begin
  469.   Result := -1;
  470.   for i := 0 to TotalOperations2-1 do if Scaner.Buf = Op2Str[i] then begin
  471.     Result := Op2ID[i]; Break;
  472.   end;
  473. end;
  474. function ParseSetConstructor: Integer;
  475. var TotalElements: Integer; ch: Char;
  476. // Set = "{" [El {, El}] "}"
  477. // El = Exp [..Exp]
  478. begin
  479.   Result := -1;
  480.   TotalElements := 0;
  481. // First element if exists
  482.   Scaner.SkipDelims; Scaner.ReadChar(ch);
  483.   Scaner.ReturnChar(ch);
  484.   if ch <> '}' then
  485.    if isInteger(Exp1) then Inc(TotalElements) else
  486.     SynError('ParseSetConstructor', eIncompatibleTypes, 0);
  487. // Rest of elements
  488.   while Scaner.ReadChar(ch) and (ch = ',') and not Error do begin
  489.     if not isInteger(Exp1) then begin SynError('ParseSetConstructor', eIncompatibleTypes, 0); Break; end;
  490.     Inc(TotalElements);
  491.     Scaner.SkipDelims;
  492.   end;
  493.   if Error then Exit;
  494.   Inc(Data.PINItems); SetLength(Data.PIN, Data.PINItems);
  495.   Data.PIN[Data.PINItems-1] := dtSet + TotalElements shl 16;
  496.   Result := dtSet;
  497. end;
  498. function ParseStdFunction: Integer;
  499. // STDPROC
  500. var i, Op, ExpType: Integer;
  501. begin
  502. {  Result := StandardFunctions[IdentIndex].ResultType;
  503.   Op := oAssign;
  504.   ExpType := Expression;
  505.   if Error then Exit;
  506.   if ControlTypes(Op, dtReal, ExpType) = -1 then Exit;
  507.   Inc(Data.PINItems, 1); SetLength(Data.PIN, Data.PINItems);
  508.   Data.PIN[Data.PINItems-1] := StandardFunctions[IdentIndex].OperationID;}
  509. end;
  510. function ParseMultiplier: Integer;
  511. var InvOp, NegOp, VarOfs, VarLoc: Integer; RTOffs: Boolean;
  512. // Mult = ~Mult | Const | Ident | (Expression)
  513. // Result - multiplier's type
  514. begin
  515.   Result := -1;
  516.   Scaner.SkipDelims; Scaner.ReadChar(ch);
  517.   if ch = '-' then begin
  518.     NegOp := oNeg;
  519.     Result := ControlTypes(NegOp, ParseMultiplier, 0);
  520.     if Result = -1 then Exit;
  521.     Inc(Data.PINItems); SetLength(Data.PIN, Data.PINItems);
  522.     Data.PIN[Data.PINItems-1] := NegOp;
  523.   end else if ch='~' then begin
  524.     InvOp := oInv;
  525.     Result := ControlTypes(InvOp, ParseMultiplier, 0);
  526.     if Result = -1 then Exit;
  527.     Inc(Data.PINItems); SetLength(Data.PIN, Data.PINItems);
  528.     Data.PIN[Data.PINItems-1] := InvOp;
  529.     Exit;
  530.   end else if Scaner.isNumber(ch) then begin
  531.     Scaner.GetNumber(ch);
  532.     Inc(Data.PINItems, 2); SetLength(Data.PIN, Data.PINItems);
  533. //    OldType := Result;
  534.     Result := SetNValue(Data.PINItems-2, Scaner.Buf, True);
  535. //    AddOperation(LastOp, OldType, Result);
  536.     Exit;
  537.   end else if Scaner.isAlpha(ch) then begin
  538.     Scaner.GetIdent(ch);
  539. //    if CheckOp1 then begin Scaner.ReturnBuf(Scaner.Buf); Break; end;
  540.     IdentIndex := CheckIdent(Scaner.Buf, CurNamespace, True, IdentKind);
  541.     if IdentIndex >= 0 then begin
  542.       case IdentKind of
  543.         VarMask: begin                                // Variable
  544.           if (IdentKind and VarMask <> 0) then begin                                // Variable
  545.             VarOfs := Data.Variables[IdentIndex].Index;
  546.             Result := SpecifyVariable(Scaner.Buf, Data.Variables[IdentIndex].TypeID, VarOfs, RTOffs);
  547.             VarLoc := Data.Variables[IdentIndex].Location;
  548.             if RTOffs then begin
  549.               Inc(Data.PINItems);
  550. //              if VarLoc = ilExternal then Inc(Data.PINItems);
  551.               SetLength(Data.PIN, Data.PINItems);
  552.               case VarLoc of
  553.                 ilStack: Data.PIN[Data.PINItems-1] := dtStackVariableByOfs;
  554.                 ilGlobal: Data.PIN[Data.PINItems-1] := dtVariableByOfs;
  555.                 ilExternal: Data.PIN[Data.PINItems-1] := dtExtVariableByOfs;
  556.               end;
  557. //              if VarLoc = ilExternal then Data.PIN[Data.PINItems-1] := VarOfs;
  558.             end else begin
  559.               Inc(Data.PINItems, 2); SetLength(Data.PIN, Data.PINItems);
  560.               case VarLoc of
  561.                 ilStack: Data.PIN[Data.PINItems-2] := dtStackVariable;
  562.                 ilGlobal: Data.PIN[Data.PINItems-2] := dtVariable;
  563.                 ilExternal: Data.PIN[Data.PINItems-2] := dtExtVariable;
  564.               end;
  565.               Data.PIN[Data.PINItems-1] := VarOfs;
  566.             end;
  567.             LastExpConstant := False;
  568.           end else begin
  569.             SynError('ParseAssign', eCannotAssign, 0); Exit;
  570.           end;
  571.           LastExpConstant := False;
  572.         end;
  573.         ConstMask: begin                              // Constant
  574.           Inc(Data.PINItems, 2); SetLength(Data.PIN, Data.PINItems);
  575.           Data.PIN[Data.PINItems-2] := Data.Constants[IdentIndex].TypeID;
  576.           Data.PIN[Data.PINItems-1] := GetConst(IdentIndex);
  577.           Result := Data.Constants[IdentIndex].TypeID;
  578.         end;
  579.         ProcMask: begin                               // Procedure-function
  580.           if Data.Procedures[IdentIndex].TypeID = -1 then begin
  581.             SynError('ParseMultiplier', eMustBeFunction, 0);
  582.             Exit;
  583.           end;
  584.           ParseCall(IdentIndex);
  585.           Result := Data.Procedures[IdentIndex].TypeID;
  586.           LastExpConstant := False;                       // ToFix: Take in account compile-time computable functions
  587.         end;
  588.         ResWordMask: begin
  589.           SynError('ParseMultiplier', eUnexpectedResWord, 0); Exit;
  590.         end;
  591.         else begin
  592.           MessageDlg('Unknown identifier type', mtError, [mbOK], 0);
  593.           SynError('ParseMultiplier', eUndeclaredIdentifier, 0); Exit;
  594.         end;
  595.       end;
  596.     end else begin SynError('ParseMultiplier', eUndeclaredIdentifier, 0); Exit; end;
  597.   end else if (ch='''') or (ch='"') then begin
  598.     Scaner.GetString(ch);
  599.     Inc(Data.PINItems, 2); SetLength(Data.PIN, Data.PINItems);
  600. //    OldType := Result;
  601.     Result := SetSValue(Data.PINItems-2, Scaner.Buf);
  602. //    AddOperation(LastOp, OldType, Result);
  603.   end else if (ch='{') then Result := ParseSetConstructor else if (ch='(') then begin
  604.     Result := Expression;
  605.     Scaner.SkipDelims; Scaner.ReadChar(ch);
  606.     if ch <> ')' then SynError('ParseMultiplier', eRightParenthesisExpected, 0);
  607.   end;
  608. end;
  609. begin
  610. // Exp2 =  Mult { "*" | "/" | DIV | MOD | "&"  Mult }
  611.   Result := -1; OldType := -1;
  612.   LastOp := aoNull;
  613.   Result := ParseMultiplier;
  614.   if Result = -1 then Exit;
  615.   Scaner.SkipDelims;
  616.   while not Error and Scaner.ReadChar(ch) do begin
  617.     if (ch = ';') or (ch = ',') or (ch = ')') or (ch = '}') or (ch = ']') or Scaner.isRelation(ch) then begin Scaner.ReturnChar(ch); Break; end;
  618.     if Scaner.isOperation(ch) then Scaner.GetOperation(ch) else
  619.      if Scaner.isAlpha(ch) then Scaner.GetIdent(ch);
  620.     if (GetOp1 <> -1) or (CheckEnd(Scaner.Buf) <> -1) or (Scaner.Buf = RelationStr[6]) or (Scaner.Buf = RelationStr[7]) then begin
  621.       Scaner.ReturnBuf(Scaner.Buf);
  622.       Break;
  623.     end;
  624.     LastOp := GetOp2;
  625.     if LastOp = -1 then begin
  626.       SynError('Exp2', eOperationExpected, 0);
  627.     end else begin
  628.       OldType := Result;
  629.       Result := ParseMultiplier;
  630.       AddOperation(LastOp, OldType, Result);
  631.       Scaner.SkipDelims;
  632.     end;
  633.   end;
  634. end;
  635. function TCompiler.SimplifyExpression(Loc: Integer): Integer;
  636. var IP, i1, i2: Integer; r1, r2: Single;
  637. type TStackItem = Integer;
  638. const StackCapacityStep = 32;
  639. var
  640.   Stack: array of TStackItem;
  641.   TotalStack, StackCapacity: Integer;
  642. procedure Push(Item: TStackItem);
  643. begin
  644.   Inc(TotalStack);
  645.   if TotalStack > StackCapacity then begin
  646.     Inc(StackCapacity, StackCapacityStep); SetLength(Stack, StackCapacity);
  647.   end;
  648.   Stack[TotalStack-1] := Item;
  649. end;
  650. procedure PushS(Item: Single); 
  651. begin
  652.   Inc(TotalStack);
  653.   if TotalStack > StackCapacity then begin
  654.     Inc(StackCapacity, StackCapacityStep); SetLength(Stack, StackCapacity);
  655.   end;
  656.   Stack[TotalStack-1] := TStackItem((@Item)^);
  657. end;
  658. function Pop: TStackItem;
  659. begin
  660.   if TotalStack = 0 then Exit;
  661.   Result := Stack[TotalStack-1];
  662.   Dec(TotalStack);
  663. end;
  664. function PopS: Single;
  665. begin
  666.   if TotalStack = 0 then Exit;
  667.   Result := Single((@Stack[TotalStack-1])^);
  668.   Dec(TotalStack);
  669. end;
  670. // 2, 3, * 7, x, * 8 * + x, 2 * 3 * x * + 2, 4, * 1, 2, x, * + * + ( 2*3+7*x*8+x*2*3*x+2*4*(1+2*x) )
  671. // x, 2, 4, * x, 2, x * + * + ( x+2*4*(x+2*x) )
  672. begin
  673. end;
  674. function TCompiler.Expression: Integer;
  675. var i: Integer; ch: Char; LastOp, OldType: Integer;
  676. begin
  677. // Exp1 [rel Exp1]
  678.   LastExpConstant := True;
  679.   Result := -1; OldType := -1;
  680.   LastOp := aoNull;
  681.   Scaner.SkipDelims;
  682.   Result := Exp1;
  683.   if (Result = -1) then begin
  684.     if not Error then SynError('Expression', eUnexpectedExpEnd, Ord(ch));
  685.     Exit;
  686.   end;
  687.   Scaner.SkipDelims;
  688.   if not Scaner.ReadChar(ch) then Exit;
  689.   if Scaner.isRelation(ch) then Scaner.GetRelation(ch) else if Scaner.isAlpha(ch) then Scaner.GetIdent(ch) else begin
  690.     Scaner.ReturnChar(ch); Exit;
  691.   end;
  692.   for i := 0 to TotalRelations-1 do if Scaner.Buf = RelationStr[i] then begin
  693.     LastOp := RelationID[i];
  694.     Break;
  695.   end;
  696.   if LastOp = aoNull then begin Scaner.ReturnBuf(Scaner.Buf); Exit; end;
  697.   Scaner.SkipDelims;
  698.   OldType := Result;
  699.   Result := Exp1;
  700.   if (Result = -1) and not Error then begin SynError('Expression', eUnexpectedExpEnd, Ord(ch)); Exit; end;
  701.   AddOperation(LastOp, OldType, Result);
  702. end;
  703. function TCompiler.ConstantExpression(var ExpResult: Integer): Integer;
  704. // Parses expression, compute it and return result in ExpResult
  705. // Returns type of expression
  706. var i, ExpStartPIN: Integer;
  707. begin
  708.   ExpStartPIN := Data.PINItems;
  709.   Result := Expression;
  710.   if Error then Exit;
  711.   if not LastExpConstant then SynError('ConstantExpression', eConstExpExpected, 0);
  712.   ExpResult := ComputeExpression(ExpStartPIN);
  713.   Data.PINItems := ExpStartPIN;
  714. end;
  715. constructor TCompiler.Create(AScaner: TScaner);
  716. begin
  717.   Scaner := AScaner;
  718.   Data   := TRTData.Create;
  719.   Reset;
  720. end;
  721. procedure TCompiler.Reset;
  722. var i: Integer;
  723. begin
  724.   Data.EntryPIN := -1;
  725.   CError.Number := 0;
  726.   Scaner.Create(Scaner.Source);
  727. //  Constants := nil; Variables := nil; Procedures := nil;
  728.   Data.TotalConstants := 0; Data.TotalVariables := 0; Data.TotalProcedures := 0;
  729.   for i := 0 to Data.TotalTypes-1 do begin
  730.     ClearType(Data.Types[i]);
  731.     Dispose(Data.Types[i]);
  732.   end;
  733.   Data.TotalTypes := 0;
  734. //  Data.PIN := nil;
  735.   Data.PINItems := 0;
  736. //  if Assigned(Data) then FreeMem(Data);
  737. //  Data.DataLength := 0;
  738.   if Namespace <> nil then begin
  739.     ClearNamespace(Namespace);
  740.     Dispose(Namespace);
  741.   end;
  742.   Namespace := nil;
  743.   CurNamespace := nil;
  744.   TotalNamesSpaces := 0;
  745.   Data.DataLength := 0; SetLength(Data.Data, Data.DataLength);
  746.   Data.BaseData := nil;
  747.   ExternalVars := nil; Data.TotalExternalVariables := 0; 
  748. end;
  749. function TCompiler.GetOperator(Buf: string): Integer;
  750. var i: Integer;
  751. begin
  752.   Result := -1;
  753.   for i := 0 to TotalOperators-1 do if Buf = OperatorStr[i] then begin
  754.     Result := i; Exit;
  755.   end;
  756. end;
  757. procedure TCompiler.ParseAssign(IdentID, IdentOffset: Integer);
  758. var Op: Integer; ch: Char; AssignType, ExpType, IdentKind, VarLoc: Integer; RTOffs: Boolean;
  759. begin
  760.   IdentKind := VarMask;
  761.   if IdentID = -1 then begin
  762.     Scaner.SkipDelims;
  763.     Scaner.ReadChar(ch);
  764.     if Scaner.isAlpha(ch) then Scaner.GetIdent(ch) else begin SynError('ParseAssign', eVariableExpected, 0); Exit; end;
  765.     IdentID := CheckIdent(Scaner.Buf, CurNamespace, True, IdentKind);
  766.     if IdentID = -1 then begin SynError('ParseAssign', eUndeclaredIdentifier, 0); Exit; end;
  767.   end;
  768.   if (IdentKind and VarMask > 0) then begin                                // Variable
  769.     IdentOffset := Data.Variables[IdentID].Index;
  770.     AssignType := SpecifyVariable(Scaner.Buf, Data.Variables[IdentID].TypeID, IdentOffset, RTOffs);
  771.     VarLoc := Data.Variables[IdentID].Location;
  772.     if RTOffs then begin
  773. {      Inc(Data.PINItems);
  774.       if VarLoc = ilExternal then Inc(Data.PINItems);
  775.       SetLength(Data.PIN, Data.PINItems);
  776.       case VarLoc of
  777.         ilStack: Data.PIN[Data.PINItems-1] := dtStackVariableByOfs;
  778.         ilGlobal: Data.PIN[Data.PINItems-1] := dtVariableByOfs;
  779.         ilExternal: Data.PIN[Data.PINItems-2] := dtExtVariableByOfs;
  780.       end;
  781.       if VarLoc = ilExternal then Data.PIN[Data.PINItems-1] := VarOfs;}
  782.     end else begin
  783.       if (IdentID and ArrayMask = 0) then begin
  784.         Inc(Data.PINItems, 2); SetLength(Data.PIN, Data.PINItems);
  785.         Data.PIN[Data.PINItems-2] := dtVariableRef;
  786.         Data.PIN[Data.PINItems-1] := IdentOffset;
  787.       end;
  788.     end;
  789.     LastExpConstant := False;
  790.   end else begin
  791.     SynError('ParseAssign', eCannotAssign, 0); Exit;
  792.   end;
  793.   Scaner.SkipDelims;
  794.   Scaner.ReadChar(ch);
  795.   Scaner.GetOperator(ch);
  796.   if Scaner.Buf <> ':=' then begin
  797.     SynError('ParseAssign', eAssignationExpected, 0);
  798.     Exit;
  799.   end;
  800.   Op := oAssign;
  801.   ExpType := ControlTypes(Op, AssignType, Expression);
  802.   if Exptype = -1 then Exit;
  803.   if Data.Variables[IdentID and not AllMask].Location = ilStack then case Op of
  804.     aoAssign1, aoAssign2, aoAssign4: Op := aoStackAssign4;
  805.     aoAssignSize: Op := aoStackAssignSize;
  806.     aoAssign4RI: Op := aoStackAssign4RI;
  807.   end else if Data.Variables[IdentID and not AllMask].Location = ilExternal then case Op of
  808.     aoAssign1, aoAssign2, aoAssign4: Op := aoExtAssign4;
  809.     aoAssignSize: Op := aoExtAssignSize;
  810.     aoAssign4RI: Op := aoExtAssign4RI;
  811.   end;
  812.   Inc(Data.PINItems, 1); SetLength(Data.PIN, Data.PINItems);
  813.   Data.PIN[Data.PINItems-1] := Op;
  814. end;
  815. procedure TCompiler.ParseLoop(ReturnType: Integer);
  816. var ch: Char; BegIP, ExitPIN: Integer;
  817. begin
  818. // LOOP ops; END;
  819.   Inc(LoopCount);
  820.   Inc(Data.PINItems, 2); SetLength(Data.PIN, Data.PINItems);
  821.   Data.PIN[Data.PINItems-2] := dtInt; ExitPIN := Data.PINItems-1;
  822.   BegIP := Data.PINItems-1;
  823.   Operators(ReturnType);
  824.   if Error then Exit;
  825.   Scaner.SkipDelims;
  826.   Scaner.ReadChar(ch);
  827.   Scaner.GetIdent(ch);
  828.   if Scaner.Buf <> EndTokenStr[etEnd] then begin
  829.     SynError('OpLoop', eEndExpected, 0); Exit;
  830.   end;
  831.   Inc(Data.PINItems, 2); SetLength(Data.PIN, Data.PINItems);
  832.   Data.PIN[Data.PINItems-2] := aoGoto; Data.PIN[Data.PINItems-1] := BegIP;
  833.   if ExitPIN <> -1 then Data.PIN[ExitPIN] := Data.PINItems-1;
  834.   Dec(LoopCount);
  835. end;
  836. procedure TCompiler.ParseWhile(ReturnType: Integer);
  837. var ch: Char; BegIP, JumpPIN, ExitPIN: Integer;
  838. begin
  839. // WHILE Expr DO Ops; END
  840.   Inc(LoopCount);
  841.   Inc(Data.PINItems, 2); SetLength(Data.PIN, Data.PINItems);
  842.   Data.PIN[Data.PINItems-2] := dtInt; ExitPIN := Data.PINItems-1;
  843.   BegIP := Data.PINItems-1;
  844.   Scaner.SkipDelims;
  845.   if Expression <> dtBoolean then begin
  846.     SynError('OpWhile', eBooleanExpExpected, 0); Exit;
  847.   end;
  848.   Scaner.SkipDelims;
  849.   Scaner.ReadChar(ch);
  850.   Scaner.GetIdent(ch);
  851.   if Scaner.Buf <> EndTokenStr[etDo] then begin
  852.     SynError('OpWhile', eDoExpected, 0); Exit;
  853.   end;
  854.   Inc(Data.PINItems, 2); SetLength(Data.PIN, Data.PINItems);
  855.   Data.PIN[Data.PINItems-2] := aoJumpIfZero; JumpPIN := Data.PINItems-1;
  856.   if Operators(ReturnType) = -1 then begin
  857.   end;
  858.   if Error then Exit;
  859.   Scaner.SkipDelims;
  860.   Scaner.ReadChar(ch);
  861.   Scaner.GetIdent(ch);
  862.   if Scaner.Buf <> EndTokenStr[etEnd] then begin
  863.     SynError('OpWhile', eEndExpected, 0); Exit;
  864.   end;
  865.   Inc(Data.PINItems, 2); SetLength(Data.PIN, Data.PINItems);
  866.   Data.PIN[Data.PINItems-2] := aoGoto; Data.PIN[Data.PINItems-1] := BegIP;
  867.   Data.PIN[JumpPin] := Data.PINItems-1;
  868.   if ExitPIN <> -1 then Data.PIN[ExitPIN] := Data.PINItems-1;
  869.   Dec(LoopCount);
  870. end;
  871. procedure TCompiler.ParseRepeat(ReturnType: Integer);
  872. var ch: Char; BegIP, ExitPIN: Integer;
  873. begin
  874. // REPEAT ops; UNTIL Expr;
  875.   ExitPIN := -1;
  876.   BegIP := Data.PINItems-1;
  877.   if Operators(ReturnType) = -1 then begin
  878.     Inc(Data.PINItems, 2); SetLength(Data.PIN, Data.PINItems);
  879.     Data.PIN[Data.PINItems-2] := aoGoto; ExitPIN := Data.PINItems-1;
  880.   end;
  881.   if Error then Exit;
  882.   Scaner.SkipDelims;
  883.   Scaner.ReadChar(ch);
  884.   Scaner.GetIdent(ch);
  885.   if Scaner.Buf <> EndTokenStr[etUntil] then begin
  886.     SynError('OpRepeat', eUntilExpected, 0); Exit;
  887.   end;
  888.   Scaner.SkipDelims;
  889.   if Expression <> dtBoolean then begin
  890.     SynError('OpRepeat', eBooleanExpExpected, 0); Exit;
  891.   end;
  892.   Inc(Data.PINItems, 2); SetLength(Data.PIN, Data.PINItems);
  893.   Data.PIN[Data.PINItems-2] := aoJumpIfZero; Data.PIN[Data.PINItems-1] := BegIP;
  894.   if ExitPIN <> -1 then Data.PIN[ExitPIN] := Data.PINItems-1;
  895. end;
  896. procedure TCompiler.ParseFor(ReturnType: Integer);
  897. var ch: Char; BegIP, JumpPIN, ExitPIN, VarRef, VarOfs, IdentKind: Integer;
  898. begin
  899. // FOR Ident := Expr TO Expr [BY ConstExpr] DO Ops END
  900.   ExitPIN := -1;
  901.   Scaner.SkipDelims;
  902.   Scaner.ReadChar(ch);
  903.   if Scaner.isAlpha(ch) then Scaner.GetIdent(ch) else begin SynError('OpFor', eVariableExpected, 0); Exit; end;
  904.   VarOfs := 0;
  905.   VarRef := CheckIdent(Scaner.Buf, CurNamespace, True, IdentKind);
  906.   if VarRef = -1 then begin SynError('OpAssign', eUndeclaredIdentifier, 0); Exit; end;
  907.   if (IdentKind and VarMask = 0) then begin SynError('OpAssign', eCannotAssign, 0); Exit; end;
  908.   ParseAssign(VarRef, VarOfs);
  909.   Scaner.SkipDelims;
  910.   Scaner.ReadChar(ch);
  911.   Scaner.GetIdent(ch);
  912.   if Scaner.Buf <> EndTokenStr[etTo] then begin
  913.     SynError('OpFor', eToExpected, 0); Exit;
  914.   end;
  915.   BegIP := Data.PINItems-1;
  916.   Expression;
  917.   Scaner.SkipDelims;
  918.   Scaner.ReadChar(ch);
  919.   Scaner.GetIdent(ch);
  920.   if Scaner.Buf <> EndTokenStr[etDo] then begin
  921.     SynError('OpFor', eDoExpected, 0); Exit;
  922.   end;
  923.   Inc(Data.PINItems, 5); SetLength(Data.PIN, Data.PINItems);
  924.   Data.PIN[Data.PINItems-5] := dtVariable; Data.PIN[Data.PINItems-4] := Data.Variables[VarRef].Index;
  925.   Data.PIN[Data.PINItems-3] := arGreaterEqualII;  
  926.   Data.PIN[Data.PINItems-2] := aoJumpIfZero; JumpPIN := Data.PINItems-1;
  927.   if Operators(ReturnType) = -1 then begin
  928.     Inc(Data.PINItems, 2); SetLength(Data.PIN, Data.PINItems);
  929.     Data.PIN[Data.PINItems-2] := aoGoto; ExitPIN := Data.PINItems-1;
  930.   end;
  931.   if Error then Exit;
  932.   Scaner.SkipDelims;
  933.   Scaner.ReadChar(ch);
  934.   if ch = ';' then begin
  935.     while ch = ';' do Scaner.ReadChar(ch);
  936.     Scaner.SkipDelims;
  937.     Scaner.ReadChar(ch);
  938.   end;
  939.   Scaner.GetIdent(ch);
  940.   if Scaner.Buf <> EndTokenStr[etEnd] then begin
  941.     SynError('OpFor', eEndExpected, 0); Exit;
  942.   end;
  943.   Inc(Data.PINItems, 10); SetLength(Data.PIN, Data.PINItems);                         //ToFix: BY support
  944.   Data.PIN[Data.PINItems-10] := dtVariableRef; Data.PIN[Data.PINItems-9] := Data.Variables[VarRef].Index;
  945.   Data.PIN[Data.PINItems-8] := dtVariable; Data.PIN[Data.PINItems-7] := Data.Variables[VarRef].Index;
  946.   Data.PIN[Data.PINItems-6] := dtInt; Data.PIN[Data.PINItems-5] := 1;
  947.   Data.PIN[Data.PINItems-4] := aoAddII; Data.PIN[Data.PINItems-3] := aoAssign4;
  948.   Data.PIN[Data.PINItems-2] := aoGoto; Data.PIN[Data.PINItems-1] := BegIP;
  949.   Data.PIN[JumpPin] := Data.PINItems-1;
  950.   if ExitPIN <> -1 then Data.PIN[ExitPIN] := Data.PINItems-1;
  951. end;
  952. procedure TCompiler.ParseIf(ReturnType: Integer);
  953. var i, JumpPIN: Integer; ch: Char; ExitPINs: array of Integer; TotalExitPINs: Integer;
  954. procedure ProcessIf;
  955. begin
  956.   if JumpPIN <> -1 then begin
  957.     Inc(TotalExitPINs); SetLength(ExitPINs, TotalExitPINs);
  958.     Inc(Data.PINItems, 2); SetLength(Data.PIN, Data.PINItems);
  959.     Data.PIN[Data.PINItems-2] := aoGoto; ExitPINs[TotalExitPINs-1] := Data.PINItems-1;
  960.   end;
  961.   Scaner.SkipDelims;
  962.   if Expression <> dtBoolean then begin
  963.     SynError('ProcessIf', eBooleanExpExpected, 0); Exit;
  964.   end;
  965.   Inc(Data.PINItems, 2); SetLength(Data.PIN, Data.PINItems);
  966.   Data.PIN[Data.PINItems-2] := aoJumpIfZero; JumpPIN := Data.PINItems-1;
  967.   Scaner.SkipDelims;
  968.   Scaner.ReadChar(ch);
  969.   Scaner.GetIdent(ch);
  970.   if Scaner.Buf <> EndTokenStr[etThen] then begin
  971.     SynError('ProcessIf', eThenExpected, 0); Exit;
  972.   end;
  973.   if Operators(ReturnType) = -1 then SynError('ProcessIf', eUnexpectedBreak, 0);
  974.   if Error then Exit;
  975. {  Inc(TotalExitPINs); SetLength(ExitPINs, TotalExitPINs);
  976.   Inc(Data.PINItems, 2); SetLength(Data.PIN, Data.PINItems);
  977.   Data.PIN[Data.PINItems-2] := aoGoto; ExitPINs[TotalExitPINs-1] := Data.PINItems-1;}
  978.   Data.PIN[JumpPIN] := Data.PINItems+1;
  979.   Scaner.SkipDelims;
  980.   Scaner.ReadChar(ch);
  981.   Scaner.GetIdent(ch);
  982.   if Scaner.Buf = EndTokenStr[etElseIf] then ProcessIf;
  983. end;
  984. begin
  985. // IF expr THEN ops {ELSEIF expr THEN ops }[ELSE os ]END
  986.   TotalExitPINs := 0; JumpPIN := -1;
  987.   ProcessIf;
  988.   if Error then Exit;
  989.   if Scaner.Buf = EndTokenStr[etElse] then begin
  990.     Inc(TotalExitPINs); SetLength(ExitPINs, TotalExitPINs);
  991.     Inc(Data.PINItems, 2); SetLength(Data.PIN, Data.PINItems);
  992.     Data.PIN[Data.PINItems-2] := aoGoto; ExitPINs[TotalExitPINs-1] := Data.PINItems-1;
  993.     if Operators(ReturnType) = -1 then SynError('ParseIf', eUnexpectedBreak, 0);
  994.     if not Error then begin
  995.       Scaner.SkipDelims;
  996.       Scaner.ReadChar(ch);
  997.       Scaner.GetIdent(ch);
  998.       if Scaner.Buf = EndTokenStr[etElseIf] then ProcessIf;
  999. //      Inc(TotalExitPINs);
  1000.     end;
  1001.   end else Dec(Data.PIN[JumpPIN], 2);
  1002.   if not Error and (Scaner.Buf <> EndTokenStr[etEnd]) then SynError('ParseIf', eEndExpected, 0);
  1003.   if TotalExitPINs >= 1 then for i := 0 to TotalExitPINs-1 do Data.PIN[ExitPINs[i]] := Data.PINItems-1;
  1004.   SetLength(ExitPins, 0);
  1005. end;
  1006. procedure TCompiler.ParseCall(const ProcID: Integer);
  1007. var LastParameter: Boolean; CurPar, Op, ExpType: Integer; ch: Char;
  1008. begin
  1009. // Procname [([Arg] {, Arg} )];
  1010.   Scaner.SkipDelims; Scaner.ReadChar(ch);
  1011.   CurPar := 0;
  1012.   if ch = '(' then begin
  1013.     Scaner.SkipDelims; Scaner.ReadChar(ch);
  1014.     if ch <> ')' then begin
  1015.       Scaner.ReturnChar(ch);
  1016.       repeat
  1017.         if CurPar >= Data.Procedures[ProcID].Namespace.ParamCount then begin
  1018.           SynError('ParseCall', eTooManyParameters, 0);
  1019.           Exit;
  1020.         end;
  1021.         LastParameter := True;
  1022.         Op := oAssign;
  1023.         ExpType := Expression;
  1024.         if Error then Exit;
  1025.         if ControlTypes(Op, Data.Variables[Data.Procedures[ProcID].Namespace.Variables[Curpar]].TypeID, ExpType) = -1 then Exit;
  1026.         Scaner.SkipDelims; Scaner.ReadChar(ch);
  1027.         if ch = ',' then begin
  1028.           LastParameter := False;
  1029. //          Scaner.SkipDelims; Scaner.ReadChar(ch);
  1030.         end else if ch <> ')' then begin
  1031.           SynError('ParseCall', eRightParenthesisExpected, 0);
  1032.           Exit;
  1033.         end;
  1034.         Inc(CurPar);
  1035.       until LastParameter or Scaner.EOS;
  1036.     end;
  1037.   end else Scaner.ReturnChar(ch);                        // ToFix: return procedure reference in this case
  1038.   if CurPar <> Data.Procedures[ProcID].Namespace.ParamCount then begin
  1039.     SynError('ParseCall', eNotEnoughParameters, 0);
  1040.     Exit;
  1041.   end;
  1042.   if ProcID < TotalStandardProcedures then begin
  1043.     Inc(Data.PINItems, 1); SetLength(Data.PIN, Data.PINItems);
  1044.     Data.PIN[Data.PINItems-1] := Data.Procedures[ProcID].CommandID;
  1045.   end else begin
  1046.     Inc(Data.PINItems, 3); SetLength(Data.PIN, Data.PINItems);
  1047.     Data.PIN[Data.PINItems-3] := dtInt; Data.PIN[Data.PINItems-2] := Data.Procedures[ProcID].Index;
  1048.     Data.PIN[Data.PINItems-1] := aoCall;
  1049.   end;
  1050. end;
  1051. function TCompiler.Operators(ReturnType: Integer): Integer;
  1052. var i, Op, Operation, IdentID, IdentOfs, ExpType, ReturnOp, IdentKind: Integer; ch: Char;
  1053. begin
  1054.   Result := 0;
  1055.   Scaner.SkipDelims;
  1056.   while (not Error) and Scaner.ReadChar(ch) do begin
  1057.     if ch = ';' then begin Scaner.SkipDelims; Continue; end;
  1058.     if Scaner.isAlpha(ch) then begin
  1059.       Scaner.GetIdent(ch);
  1060.       Op := GetOperator(Scaner.Buf);
  1061.       if Op >= 0 then begin
  1062.         case Op of
  1063.           1: ParseLoop(ReturnType);
  1064.           2: ParseWhile(ReturnType);
  1065.           3: ParseRepeat(ReturnType);
  1066.           4: ParseFor(ReturnType);
  1067.           5: ParseIf(ReturnType);
  1068.           6: if LoopCount > 0 then begin                       // Exit operator
  1069.             Inc(Data.PINItems); SetLength(Data.PIN, Data.PINItems);
  1070.             Data.PIN[Data.PINItems-1] := aoExit;
  1071.           end else SynError('Operators', eUnexpectedBreak, 0);
  1072.           7: if ReturnType = rtModule then SynError('Operators', eUnexpectedReturn, 0) else begin
  1073.             Scaner.SkipDelims;
  1074.             if ReturnType <> rtProcedure then begin
  1075.               Operation := oAssign;
  1076.               ExpType := Expression;
  1077.               if Error then Exit;
  1078.               if ControlTypes(Operation, ReturnType, ExpType) = -1 then Exit;
  1079.               ReturnOp := aoReturnF;
  1080.             end else ReturnOp := aoReturnP;
  1081.             Inc(Data.PINItems, 3); SetLength(Data.PIN, Data.PINItems);
  1082.             Data.PIN[Data.PINItems-3] := ReturnOp;
  1083.             Data.PIN[Data.PINItems-2] := CurNamespace.ParamCount;          // Number of parameters
  1084.             Data.PIN[Data.PINItems-1] := CurNamespace.StackLength div 4;   // Size of all local data
  1085.           end;
  1086.         end;
  1087.       end else if CheckEnd(Scaner.Buf) <> -1 then begin
  1088.         Scaner.ReturnBuf(Scaner.Buf);
  1089.         Break;
  1090.       end else begin
  1091.         IdentID := CheckIdent(Scaner.Buf, CurNamespace, True, IdentKind);
  1092.         if (IdentID <> -1) then begin
  1093.           if (IdentKind and ProcMask > 0) then begin
  1094.             if Data.Procedures[IdentID and not AllMask].TypeID <> -1 then begin
  1095.               SynError('Operators', eMustBeProcedure, 0);
  1096.               Exit;
  1097.             end;
  1098.             ParseCall(IdentID);
  1099.           end else if (IdentKind and ResWordMask > 0) then begin
  1100.             SynError('Operators', eUnexpectedResWord, 0); Exit;
  1101.           end else if (IdentKind and VarMask > 0) then ParseAssign(IdentID, IdentOfs);
  1102.         end else begin
  1103.           SynError('Operators', eUndeclaredIdentifier, 0); Exit;
  1104.         end;
  1105.       end;
  1106.     end else begin Scaner.ReturnChar(ch); ParseAssign(-1, 0); end;               // ?
  1107.     Scaner.SkipDelims;
  1108.   end;
  1109. end;
  1110. function TCompiler.GetDeclaration(Buf: string): Integer;
  1111. var i: Integer;
  1112. begin
  1113.   Result := -1;
  1114.   for i := 0 to TotalDeclarations-1 do if Buf = DeclarationStr[i] then begin
  1115.     Result := i; Exit;
  1116.   end;
  1117. end;
  1118. {function TCompiler.GetTypeKind(TID: Integer): Integer;
  1119. begin
  1120.   Result := -1;
  1121.   if TID = -1 then Exit;
  1122.   if TID < TotalSTDTypes then Result := TypeKind[TID] else begin
  1123.     case Data.Types[TID].Kind of
  1124.       tkCommon: Result := GetTypeKind(Data.Types[TID].ID);
  1125.       tkArray: Result := dtArray;
  1126.       tkRecord: Result := dtRecord;
  1127.       tkPointer: Result := dtPointer;
  1128.       tkProcedure: Result := dtProcedure;
  1129.     end;
  1130.   end;
  1131. end;}
  1132. function TCompiler.GetType(Buf: string): Integer;
  1133. var i: Integer;
  1134. begin
  1135.   Result := -1;
  1136.   for i := 0 to Data.TotalTypes-1 do if Buf = Data.Types[i].Name then begin
  1137.     Result := i; Exit;
  1138.   end;
  1139. end;
  1140. function TCompiler.ParseTypeDef(TypeName: TName; AlwaysNew: Boolean): Integer;
  1141. // Returns type ID of existing or just created type
  1142. // TypeDef = Ident | ARRAY [n] OF Type | RECORD ... END | POINTER TO TYPE | ProcDef
  1143. var ch: Char; OldNS, NS: PNamespace; T: PType;
  1144.   function ParseArray: Integer;
  1145.   // Parses ARRAY [Len {, Len}] OF Type
  1146.   var
  1147.     Dims: array of Integer; TotalDims: Integer; ch: Char; TID: Integer;
  1148.     T: PType;
  1149.   begin
  1150.     T := AddType(TypeName);
  1151.     Result := Data.TotalTypes-1;
  1152.     TotalDims := 1; SetLength(Dims, TotalDims);
  1153.     if not isInteger(ConstantExpression(Dims[TotalDims-1])) then SynError('ParseArray', eIntExpExpected, 0);
  1154.     if Dims[TotalDims-1] < 0 then SynError('ParseArray', ePositiveIntExpExpected, 0);
  1155.     if Error then Exit;
  1156.     Scaner.SkipDelims;
  1157.     Scaner.ReadChar(ch);
  1158.     Scaner.GetIdent(ch);
  1159.     if Scaner.Buf <> 'OF' then begin
  1160.       SynError('ParseArray', eOfExpected, 0);
  1161.       Exit;
  1162.     end;
  1163.     TID := ParseTypeDef('$internal$', False);
  1164.     if TID = -1 then begin SynError('ParseArray', eUnknownType, TID); Exit; end;
  1165.     T.Kind := tkArray;
  1166.     T.Dimension := Dims[TotalDims-1];
  1167.     T.Size := T.Dimension * Data.Types[TID].Size;
  1168.     T.ID := TID;
  1169.   end;
  1170.   function ParseRecord: Integer;
  1171.   // Returns size of record
  1172.   // Parses: RECORD ["(" Base type ")"] Fields {";" [Fields]} END
  1173.   var ch: Char;
  1174.   begin
  1175.     T := AddType(TypeName);
  1176.     Result := Data.TotalTypes-1;
  1177.     NS := NewNamespace(TypeName);
  1178.     T.Namespace := NS;
  1179.     T.Kind := tkRecord;
  1180.     NS.Kind := nskRecord;
  1181.     if CurNamespace.Kind = nskRecord then NS.Parent := CurNamespace;
  1182.     OldNS := CurNamespace;
  1183.     CurNamespace := NS;
  1184.     T.Size := ParseVar;
  1185.     Scaner.SkipDelims;
  1186.     Scaner.ReadChar(ch);
  1187.     while (ch = ';') or Scaner.isDelim(ch) do Scaner.ReadChar(ch);
  1188.     Scaner.GetIdent(ch);
  1189.     if Scaner.Buf <> 'END' then SynError('ParseRecord', eEndExpected, 0);
  1190.     CurNamespace := OldNS;
  1191.   end;
  1192.   function ParsePointer: Integer;
  1193.   var ch: Char;
  1194.   // TO <array or record type>
  1195.   begin
  1196.     Scaner.SkipDelims;
  1197.     Scaner.ReadChar(ch);
  1198.     Scaner.GetIdent(ch);
  1199.   //  if Scaner.Buf
  1200.   end;
  1201.   function ParseProcType: Integer;
  1202.   begin
  1203.   end;
  1204. begin
  1205.   Scaner.SkipDelims;
  1206.   Scaner.ReadChar(ch);
  1207.   Scaner.GetIdent(ch);
  1208.   Result := GetType(Scaner.Buf);
  1209.   if Result <> -1 then begin
  1210.     if AlwaysNew then begin
  1211.       T := AddType(TypeName);
  1212.       T.Kind := tkCommon;
  1213.       T.ID := Result;
  1214.     end;
  1215.   end else if Scaner.Buf = 'ARRAY' then begin
  1216.     Result := ParseArray;
  1217.   end else if Scaner.Buf = 'RECORD' then begin
  1218.     Result := ParseRecord;
  1219.   end else if Scaner.Buf = 'POINTER' then ParsePointer
  1220.    else if Scaner.Buf = 'PROCEDURE' then ParseProcType
  1221.     else SynError('ParseTypeDef', eUnknownType, 0);
  1222. end;
  1223. procedure TCompiler.ParseType;
  1224. // TYPE {Ident = TypeDef}
  1225. // TypeDef = Ident | ARRAY [n] OF Type | RECORD ... END | POINTER TO TYPE | ProcDef
  1226. var
  1227.   TypeEnd: Boolean; ch: Char;
  1228.   i, Ident, IdentOfs, TID, IdentKind: Integer; TypeName: TName;
  1229. begin
  1230.   repeat
  1231.     TypeEnd := True;
  1232.     Scaner.SkipDelims;
  1233.     Scaner.ReadChar(ch);
  1234.     Scaner.GetIdent(ch);
  1235.     IdentOfs := 0;
  1236.     Ident := CheckIdent(Scaner.Buf, CurNamespace, False, IdentKind);
  1237.     if Ident <> -1 then begin
  1238.       SynError('ParseType', eIdentRedeclared, Ident);
  1239.       Break;
  1240.     end;
  1241.     TypeName := Scaner.Buf;
  1242.     Scaner.SkipDelims;
  1243.     Scaner.ReadChar(ch);
  1244.     if (ch <> '=') then SynError('ParseType', eEqualExpected, 0) else begin
  1245.       TID := ParseTypeDef(TypeName, True);
  1246.     end;
  1247.     AddIdent(ikType, TypeName, TID, 0);
  1248.     if Error then Exit;
  1249.     Scaner.SkipDelims;
  1250.     Scaner.ReadChar(ch);
  1251.     if ch <> ';' then SynError('ParseType', eSemicolonExpected, 0);
  1252.     while ch = ';' do Scaner.ReadChar(ch);
  1253.     Scaner.ReturnChar(ch);
  1254.     if not Error then begin
  1255.       Scaner.SkipDelims;
  1256.       Scaner.ReadChar(ch);
  1257.       if Scaner.isAlpha(ch) then begin
  1258.         Scaner.GetIdent(ch);
  1259.         if (Scaner.Buf <> 'BEGIN') and (Scaner.Buf <> 'END') and (GetDeclaration(Scaner.Buf) = -1) then TypeEnd := False;
  1260.         Scaner.ReturnBuf(Scaner.Buf);
  1261.       end else SynError('ParseType', eUnexpectedSimbol, Ord(ch));
  1262.     end;
  1263.   until TypeEnd or Scaner.EOS or Error;
  1264. end;
  1265. function TCompiler.ParseVarSection: Integer;
  1266. // Parses variable section and returns size of all declared variables
  1267. // ident1, ident2, ... : Type;
  1268. var ch: Char; ListEnd: Boolean;
  1269. var i, j, Ident, IdentOfs, OldTotalVars, NSOldTotalVars, VarCount, TID, IdentKind: Integer;
  1270. begin
  1271.   Result := 0;
  1272.   OldTotalVars := Data.TotalVariables;
  1273.   NSOldTotalVars := CurNamespace.TotalVariables;
  1274.   VarCount := 0;
  1275.   repeat
  1276.     ListEnd := True;
  1277.     Scaner.SkipDelims;
  1278.     Scaner.ReadChar(ch);
  1279.     Scaner.GetIdent(ch);
  1280.     IdentOfs := 0;
  1281.     Ident := CheckIdent(Scaner.Buf, CurNamespace, False, IdentKind);
  1282.     if Ident <> -1 then begin
  1283.       SynError('ParseVarSection', eIdentRedeclared, Ident);
  1284.       Break;
  1285.     end;
  1286.     AddIdent(ikVariable, Scaner.Buf, 0, 0);
  1287.     Scaner.SkipDelims;
  1288.     Scaner.ReadChar(ch);
  1289.     if ch = ',' then ListEnd := False;
  1290.     Inc(VarCount);
  1291.   until ListEnd or Scaner.EOS or Error;
  1292.   if not Error and (ch <> ':') then SynError('ParseVarSection', eColonExpected, 0);
  1293.   if not Error then begin
  1294.     TID := ParseTypeDef('$internal$', False);
  1295.     if TID = -1 then begin SynError('ParseVarSection', eUnknownType, TID); Exit; end;
  1296.   end;
  1297.   if Error then begin
  1298.     Data.TotalVariables := OldTotalVars;
  1299.     CurNamespace.TotalVariables := NSOldTotalVars;
  1300.     SetLength(Data.Variables, Data.TotalVariables);
  1301.     Exit;
  1302.   end;
  1303.   for i := OldTotalVars to OldTotalVars+VarCount-1 do begin
  1304.     Inc(Result, GetTypeSize(TID));
  1305.     if (CurNamespace.Kind = nskModule) or (CurNamespace.Kind = nskRecord) then begin
  1306.       if GetExternalVarIndex(Data.Variables[i].Name) <> -1 then
  1307.        Data.Variables[i].Index := AllocateData(0, 0) else begin
  1308.          Data.Variables[i].Index := AllocateData(GetTypeSize(TID), 0);
  1309.          SetVarLocation(Data.Variables[i], ilGlobal);
  1310.        end;
  1311.     end else begin
  1312.       Data.Variables[i].Index := AllocateStack(GetTypeSize(TID));
  1313.       SetVarLocation(Data.Variables[i], ilStack);
  1314.     end;
  1315.     Data.Variables[i].TypeID := TID;
  1316.   end;
  1317. end;
  1318. function TCompiler.ParseVar: Integer;
  1319. // Parses: {ident { , ident}: Type ;}
  1320. // Returns size of all declared variables
  1321. var VarEnd: Boolean; ch: Char;
  1322. begin
  1323.   Result := 0;
  1324.   repeat
  1325.     VarEnd := True;
  1326.     Inc(Result, ParseVarSection);
  1327.     if Error then Exit;
  1328.     Scaner.SkipDelims;
  1329.     Scaner.ReadChar(ch);
  1330.     if ch <> ';' then SynError('ParseVar', eSemicolonExpected, 0);
  1331.     while ch = ';' do Scaner.ReadChar(ch);
  1332.     Scaner.ReturnChar(ch);
  1333.     if not Error then begin
  1334.       Scaner.SkipDelims;
  1335.       Scaner.ReadChar(ch);
  1336.       if Scaner.isAlpha(ch) then begin
  1337.         Scaner.GetIdent(ch);
  1338.         if (Scaner.Buf <> 'BEGIN') and (Scaner.Buf <> 'END') and (GetDeclaration(Scaner.Buf) = -1) then VarEnd := False;
  1339.         Scaner.ReturnBuf(Scaner.Buf);
  1340.       end else SynError('ParseVar', eUnexpectedSimbol, Ord(ch));
  1341.     end;
  1342.   until VarEnd or Scaner.EOS or Error;
  1343. end;
  1344. procedure TCompiler.ParseConst;
  1345. var
  1346.   ConstEnd: Boolean; ch: Char;
  1347.   i, Ident, IdentOfs, TID, ExpStartPIN, ExpResult, IdentKind: Integer; ConstName: TName;
  1348. begin
  1349. // CONST {ident = Expression}
  1350.   repeat
  1351.     ConstEnd := True;
  1352.     Scaner.SkipDelims;
  1353.     Scaner.ReadChar(ch);
  1354.     Scaner.GetIdent(ch);
  1355.     IdentOfs := 0;
  1356.     Ident := CheckIdent(Scaner.Buf, CurNamespace, False, IdentKind);
  1357.     if Ident <> -1 then begin
  1358.       SynError('ParseConst', eIdentRedeclared, Ident);
  1359.       Break;
  1360.     end;
  1361.     ConstName := Scaner.Buf;
  1362.     Scaner.SkipDelims;
  1363.     Scaner.ReadChar(ch);
  1364.     if (ch = '=') then TID := ConstantExpression(ExpResult) else SynError('ParseConst', eEqualExpected, 0);
  1365.     if Error then Exit;
  1366.     AddIdent(ikConstant, ConstName, TID, ExpResult);
  1367.     Scaner.SkipDelims;
  1368.     Scaner.ReadChar(ch);
  1369.     if ch <> ';' then SynError('ParseConst', eSemicolonExpected, 0);
  1370.     while ch = ';' do Scaner.ReadChar(ch);
  1371.     Scaner.ReturnChar(ch);
  1372.     if not Error then begin
  1373.       Scaner.SkipDelims;
  1374.       Scaner.ReadChar(ch);
  1375.       if Scaner.isAlpha(ch) then begin
  1376.         Scaner.GetIdent(ch);
  1377.         if (Scaner.Buf <> 'BEGIN') and (Scaner.Buf <> 'END') and (GetDeclaration(Scaner.Buf) = -1) then ConstEnd := False;
  1378.         Scaner.ReturnBuf(Scaner.Buf);
  1379.       end else SynError('ParseConst', eUnexpectedSimbol, Ord(ch));
  1380.     end;
  1381.   until ConstEnd or Scaner.EOS or Error;
  1382. end;
  1383. procedure TCompiler.ParseProc;
  1384. var ch: Char; Ident, IdentOfs, FuncType, IdentKind: Integer; ProcName: string[128];
  1385. // PROCEDURE ident [ "(" [[var] Vars {";" [var] Vars}] ")" [":" Type] ] ";"
  1386. // Declarations BEGIN ops END ident
  1387. function ParseFormalPars: Integer;
  1388. // "(" [[var] Vars {";" [var] Vars}] ")" [":" Type]
  1389. var LastParameter: Boolean;
  1390. begin
  1391.   Result := rtProcedure;
  1392.   Scaner.SkipDelims; Scaner.ReadChar(ch);
  1393.   if ch = '(' then begin
  1394.     Scaner.SkipDelims; Scaner.ReadChar(ch);
  1395.     if ch <> ')' then repeat
  1396.       LastParameter := True;
  1397.       if not Scaner.isAlpha(ch) then begin
  1398.         SynError('ParseFormalPars', eUnexpectedSimbol, 0);
  1399.         Exit;
  1400.       end;
  1401.       Scaner.GetIdent(ch);
  1402.       if Scaner.Buf = 'VAR' then  else Scaner.ReturnBuf(Scaner.Buf);
  1403.       ParseVarSection;
  1404.       Scaner.SkipDelims; Scaner.ReadChar(ch);
  1405.       if ch = ';' then begin
  1406.         LastParameter := False;
  1407.         Scaner.SkipDelims; Scaner.ReadChar(ch);
  1408.       end;
  1409.     until LastParameter;
  1410.   end else Scaner.ReturnChar(ch);
  1411.   Scaner.SkipDelims; Scaner.ReadChar(ch);
  1412.   if ch = ':' then begin
  1413.     Result := ParseTypeDef('$internal$', False);
  1414.     if Result = -1 then SynError('ParseFormalPars', eUnknownType, Result);
  1415.   end else Scaner.ReturnChar(ch);
  1416. end;
  1417. begin
  1418. // Procedure header
  1419.   Scaner.SkipDelims;
  1420.   Scaner.ReadChar(ch);
  1421.   Scaner.GetIdent(ch);
  1422.   IdentOfs := 0;
  1423.   Ident := CheckIdent(Scaner.Buf, CurNamespace, False, IdentKind);
  1424.   if Ident <> -1 then begin
  1425.     SynError('ParseProc', eIdentRedeclared, Ident);
  1426.     Exit;
  1427.   end;
  1428.   ProcName := Scaner.Buf;
  1429.   AddNameSpace(ProcName);
  1430.   CurNamespace.Kind := nskProcedure;
  1431.   CurNamespace.Parent.Procedures[CurNamespace.Parent.TotalProcedures-1].ID := Data.TotalProcedures;
  1432.   AddIdent(ikProcedure, ProcName, 0, Data.PINItems);                   // Procedure identifier
  1433.   FuncType := ParseFormalPars;                                    // Procedure result type
  1434.   Data.Procedures[Data.TotalProcedures-1].TypeID := FuncType;
  1435.   CurNamespace.ParamCount := CurNamespace.TotalVariables;              // Parameters count
  1436.   if Error then Exit;
  1437.   Scaner.SkipDelims; Scaner.ReadChar(ch);
  1438.   if ch <> ';' then begin SynError('ParseProc', eSemicolonExpected, 0); Exit; end;
  1439. // Procedure body
  1440.   Inc(CurNamespace.StackLength, 2*SizeOf(TStackItem));
  1441.   CompileBlock(FuncType); if Error then Exit;
  1442.   if (FuncType = rtProcedure) and (Data.PINItems >= 3) and (Data.PIN[Data.PINItems-3] <> aoReturnP) then begin
  1443.     Inc(Data.PINItems, 3); SetLength(Data.PIN, Data.PINItems);
  1444.     Data.PIN[Data.PINItems-3] := aoReturnP;
  1445.     Data.PIN[Data.PINItems-2] := CurNamespace.ParamCount;           // Number of parameters
  1446.     Data.PIN[Data.PINItems-1] := CurNamespace.StackLength div 4;    // Length of all local data
  1447.   end else
  1448.    if (Data.PINItems >= 3) and (Data.PIN[Data.PINItems-3] <> aoReturnF) and (FuncType <> -1) then Synerror('ParseProc', eReturnExpected, 0);
  1449.   Scaner.SkipDelims; Scaner.ReadChar(ch); Scaner.GetIdent(ch);
  1450.   if Scaner.Buf <> ProcName then SynError('ParseProc', eProcNameMismatch, 0);
  1451. //  Inc(CurNamespace.Parent.StackLength, CurNamespace.StackLength);
  1452.   CurNamespace := CurNamespace.Parent;
  1453. end;
  1454. function TCompiler.Declarations: Integer;
  1455. var i, D: Integer; ch: Char;
  1456. begin
  1457. // { CONST {吾