9370 lines
225 KiB
ObjectPascal
9370 lines
225 KiB
ObjectPascal
///////////////////////////////////////////////////////////////////////////
|
|
// PaxCompiler
|
|
// Site: http://www.paxcompiler.com
|
|
// Author: Alexander Baranovsky (paxscript@gmail.com)
|
|
// ========================================================================
|
|
// Copyright (c) Alexander Baranovsky, 2006-2014. All rights reserved.
|
|
// Code Version: 4.2
|
|
// ========================================================================
|
|
// Unit: PAXCOMP_PASCAL_PARSER.pas
|
|
// ========================================================================
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
{$I PaxCompiler.def}
|
|
unit PAXCOMP_PASCAL_PARSER;
|
|
interface
|
|
uses {$I uses.def}
|
|
SysUtils,
|
|
Classes,
|
|
PAXCOMP_CONSTANTS,
|
|
PAXCOMP_TYPES,
|
|
PAXCOMP_SYS,
|
|
PAXCOMP_BASESYMBOL_TABLE,
|
|
PAXCOMP_SCANNER,
|
|
PAXCOMP_BYTECODE,
|
|
PAXCOMP_MODULE,
|
|
|
|
PAXCOMP_STDLIB,
|
|
PAXCOMP_PARSER,
|
|
PAXCOMP_KERNEL,
|
|
PAXCOMP_BASERUNNER,
|
|
PAXCOMP_CLASSFACT,
|
|
PAXCOMP_GENERIC,
|
|
PAXCOMP_PASCAL_SCANNER;
|
|
|
|
const
|
|
dirNONE = 0;
|
|
dirFORWARD = 1;
|
|
dirOVERLOAD = 2;
|
|
dirABSTRACT = 3;
|
|
dirVIRTUAL = 4;
|
|
dirOVERRIDE = 5;
|
|
dirREINTRODUCE = 6;
|
|
dirDYNAMIC = 7;
|
|
dirSTATIC = 8;
|
|
dirFINAL = 9;
|
|
|
|
type
|
|
TPascalParser = class(TBaseParser)
|
|
private
|
|
I_STRICT: Integer;
|
|
I_PRIVATE: Integer;
|
|
I_PROTECTED: Integer;
|
|
I_PUBLIC: Integer;
|
|
I_PUBLISHED: Integer;
|
|
WasInherited: Boolean;
|
|
ForInCounter: Integer;
|
|
CONST_ONLY: Boolean;
|
|
OuterList: TAssocStringInt;
|
|
procedure GenExternalSub(SubId: Integer);
|
|
function MatchEx(const S: String): Boolean;
|
|
function InScope(const S: String): Boolean;
|
|
function Parse_AnonymousRoutine(IsFunc: Boolean): Integer;
|
|
procedure RemoveKeywords;
|
|
procedure RestoreKeywords;
|
|
protected
|
|
function CreateScanner: TBaseScanner; override;
|
|
function GetLanguageName: String; override;
|
|
function GetFileExt: String; override;
|
|
function GetLanguageId: Integer; override;
|
|
function GetUpcase: Boolean; override;
|
|
public
|
|
OnParseUnitName: TParserIdentEvent;
|
|
OnParseImplementationSection: TParserNotifyEvent;
|
|
OnParseBeginUsedUnitList: TParserNotifyEvent;
|
|
OnParseEndUsedUnitList: TParserNotifyEvent;
|
|
OnParseUsedUnitName: TParserIdentEvent;
|
|
OnParseTypeDeclaration: TParserIdentEvent;
|
|
OnParseForwardTypeDeclaration: TParserIdentEvent;
|
|
OnParseBeginClassTypeDeclaration: TParserIdentEventEx;
|
|
OnParseEndClassTypeDeclaration: TParserIdentEvent;
|
|
OnParseAncestorTypeDeclaration: TParserIdentEvent;
|
|
OnParseUsedInterface: TParserIdentEvent;
|
|
OnParseClassReferenceTypeDeclaration: TParserTypedIdentEvent;
|
|
OnParseAliasTypeDeclaration: TParserTypedIdentEvent;
|
|
OnParseProceduralTypeDeclaration: TParserIdentEventEx;
|
|
OnParseEventTypeDeclaration: TParserIdentEventEx;
|
|
OnParseMethodReferenceTypeDeclaration: TParserIdentEventEx;
|
|
OnParseSetTypeDeclaration: TParserTypedIdentEvent;
|
|
OnParsePointerTypeDeclaration: TParserTypedIdentEvent;
|
|
OnParseArrayTypeDeclaration: TParserArrayTypeEvent;
|
|
OnParseDynArrayTypeDeclaration: TParserTypedIdentEvent;
|
|
OnParseShortStringTypeDeclaration: TParserNamedValueEvent;
|
|
OnParseSubrangeTypeDeclaration: TParserDeclarationEvent;
|
|
OnParseBeginRecordTypeDeclaration: TParserIdentEventEx;
|
|
OnParseEndRecordTypeDeclaration: TParserIdentEvent;
|
|
OnParseBeginClassHelperTypeDeclaration: TParserTypedIdentEvent;
|
|
OnParseEndClassHelperTypeDeclaration: TParserIdentEvent;
|
|
OnParseBeginRecordHelperTypeDeclaration: TParserTypedIdentEvent;
|
|
OnParseEndRecordHelperTypeDeclaration: TParserIdentEvent;
|
|
OnParseBeginInterfaceTypeDeclaration: TParserIdentEvent;
|
|
OnParseEndInterfaceTypeDeclaration: TParserIdentEvent;
|
|
OnParseBeginEnumTypeDeclaration: TParserIdentEvent;
|
|
OnParseEndEnumTypeDeclaration: TParserIdentEvent;
|
|
OnParseEnumName: TParserNamedValueEvent;
|
|
OnParseFieldDeclaration: TParserTypedIdentEvent;
|
|
OnParseVariantRecordFieldDeclaration: TParserVariantRecordFieldEvent;
|
|
OnParsePropertyDeclaration: TParserTypedIdentEvent;
|
|
OnParseConstantDeclaration: TParserNamedValueEvent;
|
|
OnParseResourceStringDeclaration: TParserNamedValueEvent;
|
|
OnParseTypedConstantDeclaration: TParserNamedTypedValueEvent;
|
|
OnParseVariableDeclaration: TParserTypedIdentEvent;
|
|
OnParseBeginSubDeclaration: TParserIdentEvent;
|
|
OnParseEndSubDeclaration: TParserDeclarationEvent;
|
|
OnParseBeginFormalParameterList: TParserNotifyEvent;
|
|
OnParseEndFormalParameterList: TParserNotifyEvent;
|
|
OnParseFormalParameterDeclaration: TParserNamedTypedValueEvent;
|
|
OnParseResultType: TParserIdentEvent;
|
|
OnParseSubDirective: TParserIdentEvent;
|
|
|
|
constructor Create; override;
|
|
destructor Destroy; override;
|
|
procedure ParseProgram; override;
|
|
procedure Call_SCANNER; override;
|
|
procedure Match(const S: String); override;
|
|
procedure ReadToken; override;
|
|
procedure InitSub(var SubId: Integer); override;
|
|
function GetIncludedFileExt: String; override;
|
|
procedure Init(i_kernel: Pointer; M: TModule); override;
|
|
function Parse_DirectiveList(SubId: Integer): TIntegerList;
|
|
function Parse_PortabilityDirective: TPortDir;
|
|
|
|
procedure GenDefaultConstructor(ClassId: Integer);
|
|
procedure GenDefaultDestructor(ClassId: Integer);
|
|
|
|
procedure Parse_Attribute;
|
|
procedure Parse_Message(SubId: Integer);
|
|
procedure Parse_Library;
|
|
procedure Parse_ProgramBlock(namespace_id: Integer);
|
|
procedure Parse_Unit(IsExternalUnit: Boolean = false); override;
|
|
procedure Parse_Block;
|
|
|
|
procedure Parse_NamespaceDeclaration;
|
|
procedure Parse_UsesClause(IsImplementationSection: Boolean);
|
|
procedure Parse_NamespaceMemberDeclaration;
|
|
|
|
procedure Parse_DeclarationPart(IsImplementation: Boolean = false);
|
|
procedure Parse_VariableDeclaration(vis: TClassVisibility = cvNone);
|
|
procedure Parse_ConstantDeclaration(vis: TClassVisibility = cvNone);
|
|
procedure Parse_ResourcestringDeclaration;
|
|
procedure Parse_LabelDeclaration;
|
|
function Parse_FormalParameterList(SubId: Integer;
|
|
bracket: Char = '('): Integer;
|
|
procedure Parse_ProcedureDeclaration(IsSharedMethod: Boolean = false);
|
|
procedure Parse_FunctionDeclaration(IsSharedMethod: Boolean = false);
|
|
procedure Parse_OperatorDeclaration;
|
|
procedure Parse_ConstructorDeclaration;
|
|
procedure Parse_DestructorDeclaration;
|
|
procedure Parse_SubBlock;
|
|
procedure Parse_ConstantInitialization(ID: Integer);
|
|
function Parse_VariableInitialization: Integer;
|
|
|
|
// types
|
|
procedure Parse_TypeDeclaration(IsExternalUnit: Boolean = false;
|
|
vis: TClassVisibility = cvPublic);
|
|
procedure Parse_ProceduralTypeDeclaration(TypeID: Integer;
|
|
var SubId: Integer);
|
|
procedure Parse_ArrayTypeDeclaration(ArrayTypeID: Integer; IsPacked: Boolean);
|
|
function Parse_RecordConstructorHeading(IsSharedMethod: Boolean;
|
|
RecordTypeId: Integer;
|
|
Vis: TClassVisibility;
|
|
IsExternalUnit: Boolean): Integer;
|
|
function Parse_RecordDestructorHeading(IsSharedMethod: Boolean;
|
|
RecordTypeId: Integer;
|
|
Vis: TClassVisibility;
|
|
IsExternalUnit: Boolean): Integer;
|
|
function Parse_RecordProcedureHeading(IsSharedMethod: Boolean;
|
|
RecordTypeId: Integer;
|
|
Vis: TClassVisibility;
|
|
IsExternalUnit: Boolean): Integer;
|
|
function Parse_RecordFunctionHeading(IsSharedMethod: Boolean;
|
|
RecordTypeId: Integer;
|
|
Vis: TClassVisibility;
|
|
IsExternalUnit: Boolean): Integer;
|
|
function Parse_RecordOperatorHeading(RecordTypeId: Integer;
|
|
Vis: TClassVisibility;
|
|
IsExternalUnit: Boolean): Integer;
|
|
function Parse_RecordProperty(RecordTypeId: Integer;
|
|
Vis: TClassVisibility;
|
|
IsExternalUnit: Boolean): Integer;
|
|
procedure Parse_RecordVariantPart(VarLevel: Integer;
|
|
CurrVarCnt: Int64;
|
|
vis: TClassVisibility);
|
|
procedure Parse_RecordHelperItem;
|
|
procedure Parse_RecordTypeDeclaration(RecordTypeID: Integer; IsPacked: Boolean;
|
|
IsExternalUnit: Boolean = false);
|
|
function Parse_ClassConstructorHeading(IsSharedMethod: Boolean;
|
|
ClassTypeId: Integer;
|
|
vis: TClassVisibility;
|
|
IsExternalUnit: Boolean): Integer;
|
|
function Parse_ClassDestructorHeading(IsSharedMethod: Boolean;
|
|
ClassTypeId: Integer;
|
|
vis: TClassVisibility;
|
|
IsExternalUnit: Boolean): Integer;
|
|
function Parse_ClassProcedureHeading(IsSharedMethod: Boolean;
|
|
ClassTypeId: Integer;
|
|
vis: TClassVisibility;
|
|
IsExternalUnit: Boolean): Integer;
|
|
function Parse_ClassFunctionHeading(IsSharedMethod: Boolean;
|
|
ClassTypeId: Integer;
|
|
vis: TClassVisibility;
|
|
IsExternalUnit: Boolean): Integer;
|
|
function Parse_ClassProperty(IsShared: Boolean;
|
|
ClassTypeId: Integer;
|
|
vis: TClassVisibility;
|
|
IsExternalUnit: Boolean): Integer;
|
|
procedure Parse_ClassTypeDeclaration(ClassTypeID: Integer; IsPacked: Boolean;
|
|
IsExternalUnit: Boolean = false);
|
|
procedure Parse_InterfaceTypeDeclaration(IntfTypeID: Integer);
|
|
procedure Parse_MethodRefTypeDeclaration(TypeID: Integer);
|
|
procedure Parse_EnumTypeDeclaration(TypeID: Integer);
|
|
procedure Parse_PointerTypeDeclaration(TypeID: Integer);
|
|
{$IFNDEF PAXARM}
|
|
procedure Parse_ShortStringTypeDeclaration(TypeID: Integer);
|
|
{$ENDIF}
|
|
procedure Parse_SetTypeDeclaration(TypeID: Integer);
|
|
procedure Parse_SubrangeTypeDeclaration(TypeID, TypeBaseId: Integer;
|
|
var Declaration: String;
|
|
Expr1ID: Integer = 0);
|
|
function Parse_OrdinalType(var Declaration: String): Integer;
|
|
function Parse_Type: Integer;
|
|
function Parse_OpenArrayType(var ElemTypeName: String): Integer;
|
|
|
|
procedure ParseExternalSub(SubId: Integer);
|
|
|
|
//statements
|
|
function Parse_Statement: Boolean;
|
|
procedure Parse_CompoundStmt;
|
|
procedure Parse_StmtList;
|
|
procedure Parse_Write;
|
|
procedure Parse_Writeln;
|
|
procedure Parse_Print;
|
|
procedure Parse_Println;
|
|
procedure Parse_AssignmentStmt;
|
|
procedure Parse_CaseStmt;
|
|
procedure Parse_IfStmt;
|
|
procedure Parse_GotoStmt;
|
|
procedure Parse_BreakStmt;
|
|
procedure Parse_ContinueStmt;
|
|
procedure Parse_ExitStmt;
|
|
procedure Parse_WhileStmt;
|
|
procedure Parse_RepeatStmt;
|
|
procedure Parse_ForStmt;
|
|
procedure Parse_WithStmt;
|
|
procedure Parse_TryStmt;
|
|
procedure Parse_RaiseStmt;
|
|
|
|
function Parse_LoopStmt(l_break, l_continue, l_loop: Integer): Boolean;
|
|
|
|
//expressions
|
|
function Parse_LambdaParameters(SubId: Integer) : Integer;
|
|
function Parse_LambdaExpression: Integer;
|
|
function Parse_AnonymousFunction: Integer;
|
|
function Parse_AnonymousProcedure: Integer;
|
|
function Parse_ArgumentList(SubId: Integer): Integer;
|
|
function Parse_ConstantExpression: Integer;
|
|
function Parse_Expression: Integer; override;
|
|
function Parse_SimpleExpression: Integer;
|
|
function Parse_Term: Integer;
|
|
function Parse_Factor: Integer; override;
|
|
function Parse_SetConstructor: Integer;
|
|
function Parse_Designator(init_id: Integer = 0): Integer;
|
|
function Parse_Label: Integer;
|
|
function Parse_Ident: Integer; override;
|
|
// generic
|
|
procedure EndMethodDef(SubId: Integer); override;
|
|
procedure Parse_TypeRestriction(LocalTypeParams: TStringObjectList); override;
|
|
end;
|
|
|
|
TPascalExprParser = class
|
|
private
|
|
kernel: Pointer;
|
|
scanner: TPascalScanner;
|
|
function GetCurrToken: String;
|
|
function GetTokenClass: TTokenClass;
|
|
function Parse_SetConstructor: Variant;
|
|
function IsCurrText(const S: String): Boolean;
|
|
procedure Match(const S: String);
|
|
function NotMatch(const S: String): Boolean;
|
|
procedure Cancel;
|
|
procedure Call_SCANNER;
|
|
function Parse_Expression: Variant;
|
|
function Parse_SimpleExpression: Variant;
|
|
function Parse_Term: Variant;
|
|
function Parse_Factor: Variant;
|
|
public
|
|
LevelList: TIntegerList;
|
|
IsSet: Boolean;
|
|
ResExpr: String;
|
|
constructor Create(akernel: Pointer; const Expr: String);
|
|
destructor Destroy; override;
|
|
function ParseExpression: Variant;
|
|
function Lookup(const S: String): Variant;
|
|
function LegalValue(const V: Variant): Boolean;
|
|
property CurrToken: String read GetCurrToken;
|
|
property TokenClass: TTokenClass read GetTokenClass;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
PAXCOMP_VAROBJECT;
|
|
|
|
constructor TPascalExprParser.Create(akernel: Pointer; const Expr: String);
|
|
begin
|
|
inherited Create;
|
|
LevelList := TIntegerList.Create(true);
|
|
kernel := akernel;
|
|
scanner := TPascalScanner.Create;
|
|
scanner.Init(kernel, Expr, 0);
|
|
ResExpr := '';
|
|
end;
|
|
|
|
destructor TPascalExprParser.Destroy;
|
|
begin
|
|
scanner.Free;
|
|
LevelList.Free;
|
|
inherited;
|
|
end;
|
|
|
|
function TPascalExprParser.GetCurrToken: String;
|
|
begin
|
|
result := scanner.Token.Text;
|
|
end;
|
|
|
|
function TPascalExprParser.GetTokenClass: TTokenClass;
|
|
begin
|
|
result := scanner.Token.TokenClass;
|
|
end;
|
|
|
|
function TPascalExprParser.IsCurrText(const S: String): Boolean;
|
|
begin
|
|
result := StrEql(S, CurrToken);
|
|
end;
|
|
|
|
function TPascalExprParser.LegalValue(const V: Variant): Boolean;
|
|
begin
|
|
result := VarType(V) <> varEmpty;
|
|
end;
|
|
|
|
procedure TPascalExprParser.Match(const S: String);
|
|
begin
|
|
if IsCurrText(S) then
|
|
Call_SCANNER
|
|
else
|
|
Cancel;
|
|
end;
|
|
|
|
procedure TPascalExprParser.Cancel;
|
|
begin
|
|
raise PaxCancelException.Create('');
|
|
end;
|
|
|
|
procedure TPascalExprParser.Call_SCANNER;
|
|
begin
|
|
scanner.ReadToken;
|
|
ResExpr := ResExpr + CurrToken;
|
|
end;
|
|
|
|
function TPascalExprParser.NotMatch(const S: String): Boolean;
|
|
begin
|
|
if not IsCurrText(S) then
|
|
result := true
|
|
else
|
|
begin
|
|
result := false;
|
|
Call_SCANNER;
|
|
end;
|
|
end;
|
|
|
|
function TPascalExprParser.Lookup(const S: String): Variant;
|
|
var
|
|
I, L, Id: Integer;
|
|
begin
|
|
for I := 0 to LevelList.Count - 1 do
|
|
begin
|
|
L := LevelList[I];
|
|
Id := TKernel(kernel).SymbolTable.LookUp(S, L, true);
|
|
if Id > 0 then
|
|
begin
|
|
result := TKernel(kernel).SymbolTable[Id].Value;
|
|
Exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TPascalExprParser.ParseExpression: Variant;
|
|
begin
|
|
Call_SCANNER;
|
|
Call_SCANNER;
|
|
Call_SCANNER;
|
|
try
|
|
result := Parse_Expression;
|
|
except
|
|
// canceled
|
|
end;
|
|
end;
|
|
|
|
function TPascalExprParser.Parse_Expression: Variant;
|
|
var
|
|
Op: Integer;
|
|
V: Variant;
|
|
begin
|
|
result := Parse_SimpleExpression;
|
|
if not LegalValue(result) then
|
|
Cancel;
|
|
|
|
if CurrToken = '=' then
|
|
Op := OP_EQ
|
|
else if CurrToken = '<>' then
|
|
Op := OP_NE
|
|
else if CurrToken = '>' then
|
|
Op := OP_GT
|
|
else if CurrToken = '>=' then
|
|
Op := OP_GE
|
|
else if CurrToken = '<' then
|
|
Op := OP_LT
|
|
else if CurrToken = '<=' then
|
|
Op := OP_LT
|
|
else
|
|
Op := 0;
|
|
|
|
while Op <> 0 do
|
|
begin
|
|
Call_SCANNER;
|
|
V := Parse_SimpleExpression;
|
|
if not LegalValue(V) then
|
|
Cancel;
|
|
|
|
if Op = OP_EQ then
|
|
result := result = V
|
|
else if Op = OP_NE then
|
|
result := result <> V
|
|
else if Op = OP_GT then
|
|
result := result > V
|
|
else if Op = OP_GE then
|
|
result := result >= V
|
|
else if Op = OP_LT then
|
|
result := result < V
|
|
else if Op = OP_LE then
|
|
result := result <= V;
|
|
|
|
if CurrToken = '=' then
|
|
Op := OP_EQ
|
|
else if CurrToken = '<>' then
|
|
Op := OP_NE
|
|
else if CurrToken = '>' then
|
|
Op := OP_GT
|
|
else if CurrToken = '>=' then
|
|
Op := OP_GE
|
|
else if CurrToken = '<' then
|
|
Op := OP_LT
|
|
else if CurrToken = '<=' then
|
|
Op := OP_LT
|
|
else
|
|
Op := 0;
|
|
end;
|
|
end;
|
|
|
|
function TPascalExprParser.Parse_SimpleExpression: Variant;
|
|
var
|
|
Op: Integer;
|
|
V: Variant;
|
|
begin
|
|
result := Parse_Term;
|
|
if not LegalValue(result) then
|
|
Cancel;
|
|
|
|
if CurrToken = '+' then
|
|
Op := OP_PLUS
|
|
else if CurrToken = '-' then
|
|
Op := OP_MINUS
|
|
else if StrEql(CurrToken, 'or') then
|
|
Op := OP_OR
|
|
else if StrEql(CurrToken, 'xor') then
|
|
Op := OP_XOR
|
|
else
|
|
Op := 0;
|
|
|
|
while Op <> 0 do
|
|
begin
|
|
Call_SCANNER;
|
|
V := Parse_Term;
|
|
if not LegalValue(V) then
|
|
Cancel;
|
|
|
|
if Op = OP_PLUS then
|
|
result := result + V
|
|
else if Op = OP_MINUS then
|
|
result := result - V
|
|
else if Op = OP_OR then
|
|
result := result or V
|
|
else if Op = OP_XOR then
|
|
result := result xor V;
|
|
|
|
if CurrToken = '+' then
|
|
Op := OP_PLUS
|
|
else if CurrToken = '-' then
|
|
Op := OP_MINUS
|
|
else if StrEql(CurrToken, 'or') then
|
|
Op := OP_OR
|
|
else if StrEql(CurrToken, 'xor') then
|
|
Op := OP_XOR
|
|
else
|
|
Op := 0;
|
|
end;
|
|
end;
|
|
|
|
function TPascalExprParser.Parse_Term: Variant;
|
|
var
|
|
Op: Integer;
|
|
V: Variant;
|
|
begin
|
|
result := Parse_Factor;
|
|
if not LegalValue(result) then
|
|
Cancel;
|
|
|
|
if CurrToken = '*' then
|
|
Op := OP_MULT
|
|
else if CurrToken = '/' then
|
|
Op := OP_DIV
|
|
else if StrEql(CurrToken, 'div') then
|
|
Op := OP_IDIV
|
|
else if StrEql(CurrToken, 'mod') then
|
|
Op := OP_MOD
|
|
else if StrEql(CurrToken, 'shl') then
|
|
Op := OP_SHL
|
|
else if StrEql(CurrToken, 'shr') then
|
|
Op := OP_SHL
|
|
else if StrEql(CurrToken, 'and') then
|
|
Op := OP_AND
|
|
else
|
|
Op := 0;
|
|
|
|
while Op <> 0 do
|
|
begin
|
|
Call_SCANNER;
|
|
V := Parse_Factor;
|
|
if not LegalValue(V) then
|
|
Cancel;
|
|
|
|
if Op = OP_MULT then
|
|
result := result * V
|
|
else if Op = OP_DIV then
|
|
begin
|
|
if V = 0.0 then
|
|
begin
|
|
if result = 0.0 then
|
|
result := NaN
|
|
else if result = 1.0 then
|
|
result := Infinity
|
|
else if result = - 1.0 then
|
|
result := NegInfinity
|
|
end
|
|
else
|
|
result := result / V;
|
|
end
|
|
else if Op = OP_IDIV then
|
|
result := result div V
|
|
else if Op = OP_MOD then
|
|
result := result mod V
|
|
else if Op = OP_SHL then
|
|
result := result shl V
|
|
else if Op = OP_SHR then
|
|
result := result shr V
|
|
else if Op = OP_AND then
|
|
result := result and V;
|
|
|
|
if CurrToken = '*' then
|
|
Op := OP_MULT
|
|
else if CurrToken = '/' then
|
|
Op := OP_DIV
|
|
else if StrEql(CurrToken, 'div') then
|
|
Op := OP_IDIV
|
|
else if StrEql(CurrToken, 'mod') then
|
|
Op := OP_MOD
|
|
else if StrEql(CurrToken, 'shl') then
|
|
Op := OP_SHL
|
|
else if StrEql(CurrToken, 'shr') then
|
|
Op := OP_SHL
|
|
else if StrEql(CurrToken, 'and') then
|
|
Op := OP_AND
|
|
else
|
|
Op := 0;
|
|
end;
|
|
end;
|
|
|
|
function TPascalExprParser.Parse_Factor: Variant;
|
|
var
|
|
I, J: Integer;
|
|
D: Double;
|
|
begin
|
|
{$IFDEF PAXARM}
|
|
if TokenClass = tcCharConst then
|
|
begin
|
|
result := Ord(CurrToken[1]);
|
|
Call_SCANNER;
|
|
end
|
|
else if TokenClass = tcNumCharConst then
|
|
begin
|
|
result := StrToInt(CurrToken);
|
|
Call_SCANNER;
|
|
end
|
|
else if TokenClass = tcPCharConst then
|
|
begin
|
|
result := CurrToken;
|
|
Call_SCANNER;
|
|
end
|
|
{$ELSE}
|
|
if TokenClass = tcCharConst then
|
|
begin
|
|
result := Ord(CurrToken[1]);
|
|
Call_SCANNER;
|
|
end
|
|
else if TokenClass = tcNumCharConst then
|
|
begin
|
|
result := StrToInt(CurrToken);
|
|
Call_SCANNER;
|
|
end
|
|
else if TokenClass = tcPCharConst then
|
|
begin
|
|
result := CurrToken;
|
|
Call_SCANNER;
|
|
end
|
|
{$ENDIF}
|
|
else if TokenClass = tcIntegerConst then
|
|
begin
|
|
val(CurrToken, i, j);
|
|
if j = 0 then begin
|
|
if Pos('$', CurrToken) > 0 then
|
|
begin
|
|
{$IFDEF VARIANTS}
|
|
result := Cardinal(i);
|
|
{$ELSE}
|
|
result := Integer(i);
|
|
{$ENDIF}
|
|
end
|
|
else
|
|
begin
|
|
result := i;
|
|
end;
|
|
end;
|
|
Call_SCANNER;
|
|
end
|
|
else if TokenClass = tcVariantConst then
|
|
begin
|
|
Call_SCANNER;
|
|
end
|
|
else if TokenClass = tcDoubleConst then
|
|
begin
|
|
Val(CurrToken, D, I);
|
|
result := D;
|
|
Call_SCANNER;
|
|
end
|
|
else if IsCurrText('nil') then
|
|
begin
|
|
result := 0;
|
|
Call_SCANNER;
|
|
end
|
|
else if IsCurrText('true') then
|
|
begin
|
|
result := true;
|
|
Call_SCANNER;
|
|
end
|
|
else if IsCurrText('false') then
|
|
begin
|
|
result := false;
|
|
Call_SCANNER;
|
|
end
|
|
else if IsCurrText('+') then
|
|
begin
|
|
Call_SCANNER;
|
|
result := Parse_Factor;
|
|
end
|
|
else if IsCurrText('-') then
|
|
begin
|
|
Call_SCANNER;
|
|
result := - Parse_Factor;
|
|
end
|
|
else if IsCurrText('not') then
|
|
begin
|
|
Call_SCANNER;
|
|
result := not Parse_Factor;
|
|
end
|
|
else if IsCurrText('low') then
|
|
begin
|
|
Call_SCANNER;
|
|
Match('(');
|
|
result := Lookup(CurrToken);
|
|
Call_SCANNER;
|
|
Match(')');
|
|
end
|
|
else if IsCurrText('high') then
|
|
begin
|
|
Call_SCANNER;
|
|
Match('(');
|
|
I := Lookup(CurrToken);
|
|
Call_SCANNER;
|
|
Match(')');
|
|
end
|
|
else if IsCurrText('SizeOf') then
|
|
begin
|
|
Call_SCANNER;
|
|
Match('(');
|
|
I := Lookup(CurrToken);
|
|
Call_SCANNER;
|
|
Match(')');
|
|
end
|
|
else if IsCurrText('pred') then
|
|
begin
|
|
Call_SCANNER;
|
|
Match('(');
|
|
result := Parse_Expression - 1;
|
|
Match(')');
|
|
end
|
|
else if IsCurrText('succ') then
|
|
begin
|
|
Call_SCANNER;
|
|
Match('(');
|
|
result := Parse_Expression + 1;
|
|
Match(')');
|
|
end
|
|
else if IsCurrText('ord') then
|
|
begin
|
|
Call_SCANNER;
|
|
Match('(');
|
|
result := Parse_Expression;
|
|
Match(')');
|
|
end
|
|
else if IsCurrText('chr') then
|
|
begin
|
|
Call_SCANNER;
|
|
Match('(');
|
|
result := Parse_Expression;
|
|
Match(')');
|
|
end
|
|
else if IsCurrText('(') then
|
|
begin
|
|
Match('(');
|
|
result := Parse_Expression;
|
|
Match(')');
|
|
end
|
|
else if IsCurrText('@') then
|
|
begin
|
|
Cancel;
|
|
end
|
|
else if IsCurrText('[') then
|
|
begin
|
|
result := Parse_SetConstructor;
|
|
end
|
|
else if IsCurrText('procedure') then
|
|
begin
|
|
Cancel;
|
|
end
|
|
else if IsCurrText('function') then
|
|
begin
|
|
Cancel;
|
|
end
|
|
else if IsCurrText('array') then
|
|
begin
|
|
Cancel;
|
|
end
|
|
else if IsCurrText('deprecated') then
|
|
begin
|
|
Cancel;
|
|
end
|
|
else if IsCurrText('pchar') then
|
|
begin
|
|
Cancel;
|
|
end
|
|
else if IsCurrText('[') then
|
|
begin
|
|
result := Parse_SetConstructor;
|
|
end
|
|
else
|
|
begin
|
|
result := LookUp(CurrToken);
|
|
Call_SCANNER;
|
|
while IsCurrText('.') do
|
|
begin
|
|
Match('.');
|
|
result := LookUp(CurrToken);
|
|
Call_SCANNER;
|
|
end;
|
|
if IsCurrText('(') then
|
|
begin
|
|
Match('(');
|
|
result := Parse_Expression;
|
|
Match(')');
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TPascalExprParser.Parse_SetConstructor: Variant;
|
|
begin
|
|
Match('[');
|
|
if not IsCurrText(']') then
|
|
begin
|
|
repeat
|
|
Parse_Expression;
|
|
if IsCurrText('..') then
|
|
begin
|
|
Match('..');
|
|
Parse_Expression;
|
|
end;
|
|
If NotMatch(',') then
|
|
break;
|
|
until false;
|
|
end;
|
|
Match(']');
|
|
IsSet := true;
|
|
result := ResExpr;
|
|
end;
|
|
|
|
constructor TPascalParser.Create;
|
|
begin
|
|
inherited;
|
|
|
|
OuterList := TAssocStringInt.Create;
|
|
|
|
AddKeyword('and');
|
|
AddKeyword('array');
|
|
AddKeyword('as');
|
|
AddKeyword('asm');
|
|
AddKeyword('begin');
|
|
AddKeyword('case');
|
|
AddKeyword('class');
|
|
AddKeyword('const');
|
|
AddKeyword('constructor');
|
|
AddKeyword('destructor');
|
|
AddKeyword('dispinterface');
|
|
AddKeyword('div');
|
|
AddKeyword('do');
|
|
AddKeyword('downto');
|
|
AddKeyword('else');
|
|
|
|
AddKeyword('end');
|
|
AddKeyword('except');
|
|
AddKeyword('exports');
|
|
|
|
AddKeyword('external');
|
|
|
|
AddKeyword('file');
|
|
AddKeyword('finalization');
|
|
AddKeyword('finally');
|
|
AddKeyword('for');
|
|
AddKeyword('function');
|
|
AddKeyword('goto');
|
|
AddKeyword('if');
|
|
AddKeyword('implementation');
|
|
AddKeyword('in');
|
|
AddKeyword('inherited');
|
|
AddKeyword('initialization');
|
|
AddKeyword('inline');
|
|
AddKeyword('interface');
|
|
AddKeyword('is');
|
|
AddKeyword('label');
|
|
AddKeyword('library');
|
|
AddKeyword('mod');
|
|
AddKeyword('nil');
|
|
AddKeyword('not');
|
|
AddKeyword('object');
|
|
AddKeyword('of');
|
|
AddKeyword('on');
|
|
AddKeyword('or');
|
|
AddKeyword('out');
|
|
AddKeyword('packed');
|
|
I_STRICT := AddKeyword('strict');
|
|
I_PRIVATE := AddKeyword('private');
|
|
AddKeyword('procedure');
|
|
AddKeyword('program');
|
|
AddKeyword('property');
|
|
I_PROTECTED := AddKeyword('protected');
|
|
I_PUBLIC := AddKeyword('public');
|
|
I_PUBLISHED := AddKeyword('published');
|
|
AddKeyword('raise');
|
|
AddKeyword('record');
|
|
AddKeyword('repeat');
|
|
AddKeyword('resourcestring');
|
|
AddKeyword('set');
|
|
AddKeyword('shl');
|
|
AddKeyword('shr');
|
|
AddKeyword('string');
|
|
AddKeyword('then');
|
|
AddKeyword('threadvar');
|
|
AddKeyword('to');
|
|
AddKeyword('try');
|
|
AddKeyword('type');
|
|
AddKeyword('unit');
|
|
AddKeyword('until');
|
|
AddKeyword('uses');
|
|
AddKeyword('var');
|
|
AddKeyword('while');
|
|
AddKeyword('with');
|
|
AddKeyword('xor');
|
|
AddKeyword(EXTRA_KEYWORD);
|
|
|
|
AddOperator(pascal_Implicit, gen_Implicit);
|
|
AddOperator(pascal_Explicit, gen_Explicit);
|
|
AddOperator(pascal_Add, gen_Add);
|
|
AddOperator(pascal_Divide, gen_Divide);
|
|
AddOperator(pascal_IntDivide, gen_IntDivide);
|
|
AddOperator(pascal_Modulus, gen_Modulus);
|
|
AddOperator(pascal_Multiply, gen_Multiply);
|
|
AddOperator(pascal_Subtract, gen_Subtract);
|
|
AddOperator(pascal_Negative, gen_Negative);
|
|
AddOperator(pascal_Positive, gen_Positive);
|
|
AddOperator(pascal_LogicalNot, gen_LogicalNot);
|
|
AddOperator(pascal_LeftShift, gen_LeftShift);
|
|
AddOperator(pascal_RightShift, gen_RightShift);
|
|
AddOperator(pascal_LogicalAnd, gen_LogicalAnd);
|
|
AddOperator(pascal_LogicalOr, gen_LogicalOr);
|
|
AddOperator(pascal_LogicalXor, gen_LogicalXor);
|
|
AddOperator(pascal_LessThan, gen_LessThan);
|
|
AddOperator(pascal_LessThanOrEqual, gen_LessThanOrEqual);
|
|
AddOperator(pascal_GreaterThan, gen_GreaterThan);
|
|
AddOperator(pascal_GreaterThanOrEqual, gen_GreaterThanOrEqual);
|
|
AddOperator(pascal_Equal, gen_Equal);
|
|
AddOperator(pascal_NotEqual, gen_NotEqual);
|
|
AddOperator(pascal_Inc, gen_Inc);
|
|
AddOperator(pascal_Dec, gen_Dec);
|
|
end;
|
|
|
|
destructor TPascalParser.Destroy;
|
|
begin
|
|
FreeAndNil(OuterList);
|
|
inherited;
|
|
end;
|
|
|
|
function TPascalParser.CreateScanner: TBaseScanner;
|
|
begin
|
|
result := TPascalScanner.Create;
|
|
end;
|
|
|
|
function TPascalParser.GetLanguageName: String;
|
|
begin
|
|
result := 'Pascal';
|
|
end;
|
|
|
|
function TPascalParser.GetFileExt: String;
|
|
begin
|
|
result := 'pas';
|
|
end;
|
|
|
|
function TPascalParser.GetIncludedFileExt: String;
|
|
begin
|
|
result := 'pas';
|
|
end;
|
|
|
|
function TPascalParser.GetLanguageId: Integer;
|
|
begin
|
|
result := PASCAL_LANGUAGE;
|
|
end;
|
|
|
|
function TPascalParser.GetUpcase: Boolean;
|
|
begin
|
|
result := true;
|
|
end;
|
|
|
|
procedure TPascalParser.Init(i_kernel: Pointer; M: TModule);
|
|
begin
|
|
Inherited Init(i_kernel, M);
|
|
WasInherited := true;
|
|
ForInCounter := 0;
|
|
IMPLEMENTATION_SECTION := false;
|
|
OuterList.Clear;
|
|
end;
|
|
|
|
procedure TPascalParser.GenDefaultConstructor(ClassId: Integer);
|
|
var
|
|
SubId, ResId, L: Integer;
|
|
begin
|
|
GenComment('BEGIN OF DEFAULT CONSTRUCTOR OF ' + GetName(ClassId));
|
|
|
|
LevelStack.Push(ClassId);
|
|
SubId := NewTempVar;
|
|
SetName(SubId, 'Create');
|
|
|
|
BeginClassConstructor(SubId, ClassId);
|
|
SetVisibility(SubId, cvPublic);
|
|
inherited InitSub(SubId);
|
|
|
|
SetCallMode(SubId, cmOVERRIDE);
|
|
Gen(OP_ADD_MESSAGE, SubId, NewConst(typeINTEGER, -1000), 0);
|
|
Gen(OP_CHECK_OVERRIDE, SubId, 0, 0);
|
|
|
|
Gen(OP_SAVE_EDX, 0, 0, 0);
|
|
|
|
L := NewLabel;
|
|
Gen(OP_GO_DL, L, 0, 0);
|
|
Gen(OP_CREATE_OBJECT, ClassId, 0, CurrSelfId);
|
|
|
|
if GetSymbolRec(ClassId).IsAbstract then
|
|
Gen(OP_ERR_ABSTRACT, NewConst(typeSTRING,
|
|
GetFullName(ClassId)), 0, SubId);
|
|
|
|
SetLabelHere(L);
|
|
|
|
Gen(OP_BEGIN_WITH, CurrSelfId, 0, 0);
|
|
WithStack.Push(CurrSelfId);
|
|
|
|
NewTempVar;
|
|
ResId := NewTempVar;
|
|
|
|
Gen(OP_PUSH_CLASSREF, CurrSelfId, 0, ResId);
|
|
Gen(OP_EVAL_INHERITED, SubId, 0, ResId);
|
|
|
|
SetDefault(SubId, true);
|
|
Gen(OP_UPDATE_DEFAULT_CONSTRUCTOR, SubId, 0, ResId);
|
|
// will insertion here
|
|
|
|
Gen(OP_CALL_INHERITED, ResId, 0, 0);
|
|
|
|
Gen(OP_END_WITH, WithStack.Top, 0, 0);
|
|
WithStack.Pop;
|
|
|
|
Gen(OP_RESTORE_EDX, 0, 0, 0);
|
|
L := NewLabel;
|
|
Gen(OP_GO_DL, L, 0, 0);
|
|
Gen(OP_ONCREATE_OBJECT, CurrSelfId, 0, 0);
|
|
Gen(OP_ON_AFTER_OBJECT_CREATION, CurrSelfId, 0, 0);
|
|
SetLabelHere(L);
|
|
|
|
EndSub(SubId);
|
|
LevelStack.Pop;
|
|
|
|
GenComment('END OF DEFAULT CONSTRUCTOR OF ' + GetName(ClassId));
|
|
end;
|
|
|
|
procedure TPascalParser.GenDefaultDestructor(ClassId: Integer);
|
|
var
|
|
SubId, Id, ResId: Integer;
|
|
begin
|
|
GenComment('BEGIN OF DEFAULT DESTRUCTOR OF ' + GetName(ClassId));
|
|
|
|
LevelStack.Push(ClassId);
|
|
SubId := NewTempVar;
|
|
SetName(SubId, 'Destroy');
|
|
BeginClassDestructor(SubId, ClassId);
|
|
SetVisibility(SubId, cvPublic);
|
|
SetCallMode(SubId, cmOVERRIDE);
|
|
inherited InitSub(SubId);
|
|
|
|
Gen(OP_BEGIN_WITH, CurrSelfId, 0, 0);
|
|
WithStack.Push(CurrSelfId);
|
|
|
|
Id := NewTempVar;
|
|
ResId := NewTempVar;
|
|
SetName(Id, 'Destroy');
|
|
Gen(OP_EVAL, 0, 0, Id);
|
|
Gen(OP_EVAL_INHERITED, Id, 0, ResId);
|
|
|
|
Gen(OP_CALL, ResId, 0, 0);
|
|
|
|
Gen(OP_END_WITH, WithStack.Top, 0, 0);
|
|
WithStack.Pop;
|
|
|
|
EndSub(SubId);
|
|
LevelStack.Pop;
|
|
|
|
GenComment('END OF DEFAULT DESTRUCTOR OF ' + GetName(ClassId));
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_DeclarationPart(IsImplementation: Boolean = false);
|
|
var
|
|
ok: Boolean;
|
|
begin
|
|
repeat
|
|
ok := false;
|
|
if IsCurrText('label') then
|
|
begin
|
|
Parse_LabelDeclaration;
|
|
ok := true;
|
|
end
|
|
else if IsCurrText('var') then
|
|
begin
|
|
Parse_VariableDeclaration;
|
|
ok := true;
|
|
end
|
|
else if IsCurrText('threadvar') then
|
|
begin
|
|
Parse_VariableDeclaration;
|
|
ok := true;
|
|
end
|
|
else if IsCurrText('const') then
|
|
begin
|
|
Parse_ConstantDeclaration;
|
|
ok := true;
|
|
end
|
|
else if IsCurrText('resourcestring') then
|
|
begin
|
|
Parse_ResourcestringDeclaration;
|
|
ok := true;
|
|
end
|
|
else if IsCurrText('procedure') then
|
|
begin
|
|
Parse_ProcedureDeclaration;
|
|
ok := true;
|
|
end
|
|
else if IsCurrText('function') then
|
|
begin
|
|
Parse_FunctionDeclaration;
|
|
ok := true;
|
|
end
|
|
else if IsCurrText('class') then
|
|
begin
|
|
Call_SCANNER;
|
|
if IsCurrText('procedure') then
|
|
Parse_ProcedureDeclaration(true)
|
|
else if IsCurrText('function') then
|
|
Parse_FunctionDeclaration(true)
|
|
else if IsCurrText('operator') then
|
|
Parse_OperatorDeclaration
|
|
else
|
|
Match('procedure');
|
|
ok := true;
|
|
end
|
|
else if IsCurrText('constructor') then
|
|
begin
|
|
Parse_ConstructorDeclaration;
|
|
ok := true;
|
|
end
|
|
else if IsCurrText('destructor') then
|
|
begin
|
|
Parse_DestructorDeclaration;
|
|
ok := true;
|
|
end
|
|
else if IsCurrText('type') then
|
|
begin
|
|
Parse_TypeDeclaration;
|
|
ok := true;
|
|
end
|
|
until not ok;
|
|
|
|
if GetKind(LevelStack.Top) in KindSUBS then
|
|
Exit;
|
|
end;
|
|
|
|
procedure TPascalParser.ParseProgram;
|
|
var
|
|
namespace_id: Integer;
|
|
begin
|
|
EXECUTABLE_SWITCH := 0;
|
|
Call_SCANNER;
|
|
|
|
if IsEOF then
|
|
Exit;
|
|
|
|
namespace_id := 0;
|
|
|
|
if IsCurrText('program') then
|
|
begin
|
|
DECLARE_SWITCH := true;
|
|
Call_SCANNER;
|
|
// SetKind(CurrToken.Id, KindNONE);
|
|
// Call_SCANNER;
|
|
namespace_id := Parse_Ident;
|
|
DECLARE_SWITCH := false;
|
|
Match(';');
|
|
end;
|
|
|
|
if IsCurrText('unit') then
|
|
Parse_Unit
|
|
else if IsCurrText('library') then
|
|
Parse_Library
|
|
else
|
|
Parse_ProgramBlock(namespace_id);
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_Library;
|
|
var
|
|
id, I: Integer;
|
|
L: TAssocStringInt;
|
|
S: String;
|
|
begin
|
|
DECLARE_SWITCH := true;
|
|
Match('library');
|
|
|
|
Gen(OP_BEGIN_LIBRARY, Parse_Ident, 0, 0);
|
|
Match(';');
|
|
|
|
while IsCurrText('uses') do
|
|
begin
|
|
Parse_UsesClause(false);
|
|
end;
|
|
|
|
Gen(OP_END_IMPORT, 0, 0, 0);
|
|
|
|
repeat
|
|
if IsEOF then
|
|
Match('exports');
|
|
if IsCurrText('exports') then
|
|
break;
|
|
Parse_NamespaceMemberDeclaration;
|
|
until false;
|
|
|
|
DECLARE_SWITCH := false;
|
|
|
|
Gen(OP_BEGIN_EXPORT, 0, 0, 0);
|
|
Match('exports');
|
|
|
|
L := TAssocStringInt.Create;
|
|
try
|
|
repeat
|
|
S := CurrToken.Text;
|
|
id := Parse_Ident;
|
|
L.AddValue(S, id);
|
|
if IsCurrText(',') then
|
|
Call_SCANNER
|
|
else
|
|
break;
|
|
until false;
|
|
// L.Sort;
|
|
for I := 0 to L.Count - 1 do
|
|
begin
|
|
Id := L.Values[I];
|
|
Gen(OP_EXPORTS, id, 0, 0);
|
|
end;
|
|
finally
|
|
FreeAndNil(L);
|
|
end;
|
|
Match(';');
|
|
|
|
Parse_CompoundStmt;
|
|
MatchFinal('.');
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_NamespaceDeclaration;
|
|
var
|
|
l: TIntegerList;
|
|
i, namespace_id: Integer;
|
|
begin
|
|
DECLARE_SWITCH := true;
|
|
RemoveLastIdent(CurrToken.Id);
|
|
Match('namespace');
|
|
|
|
l := TIntegerList.Create;
|
|
|
|
try
|
|
repeat // ParseQualifiedIdentifier
|
|
namespace_id := Parse_Ident;
|
|
l.Add(namespace_id);
|
|
BeginNamespace(namespace_id);
|
|
if NotMatch('.') then
|
|
break;
|
|
until false;
|
|
|
|
// Parse namespace body
|
|
|
|
repeat
|
|
if IsEOF then
|
|
Match('end');
|
|
if IsCurrText('end') then
|
|
break;
|
|
Parse_NamespaceMemberDeclaration;
|
|
until false;
|
|
|
|
for i := l.Count - 1 downto 0 do
|
|
begin
|
|
EndNamespace(l[i]);
|
|
Gen(OP_BEGIN_USING, l[i], 0, 0);
|
|
end;
|
|
|
|
finally
|
|
FreeAndNil(L);
|
|
end;
|
|
|
|
Match('end');
|
|
Match(';');
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_UsesClause(IsImplementationSection: Boolean);
|
|
var
|
|
unit_id, id: Integer;
|
|
S: String;
|
|
AlreadyExists: Boolean;
|
|
RootKernel: TKernel;
|
|
begin
|
|
RootKernel := TKernel(Kernel).RootKernel;
|
|
|
|
UsedUnitList.Clear;
|
|
|
|
DECLARE_SWITCH := false;
|
|
Match('uses');
|
|
if Assigned(OnParseBeginUsedUnitList) then
|
|
OnParseBeginUsedUnitList(Owner);
|
|
|
|
repeat
|
|
unit_id := Parse_UnitName(S);
|
|
if Assigned(OnParseUsedUnitName) then
|
|
OnParseUsedUnitName(Owner, S, unit_id);
|
|
|
|
AlreadyExists := GetKind(unit_id) = kindNAMESPACE;
|
|
|
|
Gen(OP_BEGIN_USING, unit_id, 0, 0);
|
|
|
|
if IsCurrText('in') then
|
|
begin
|
|
Call_SCANNER;
|
|
id := Parse_PCharLiteral;
|
|
S := GetValue(id);
|
|
if (PosCh('\', S) > 0) or (PosCh('/', S) > 0) then
|
|
if not Assigned(RootKernel.OnUsedUnit) then
|
|
begin
|
|
if (Pos('.\', S) > 0) or (Pos('./', S) > 0) then
|
|
S := ExpandFileName(S)
|
|
else
|
|
S := GetCurrentDir + S;
|
|
end;
|
|
|
|
AlreadyExists := false;
|
|
end
|
|
else
|
|
S := S + '.' + GetFileExt;
|
|
|
|
if not AlreadyExists then
|
|
if not ImportOnly then
|
|
AddModuleFromFile(S, unit_id, IsImplementationSection);
|
|
|
|
if NotMatch(',') then
|
|
Break;
|
|
until false;
|
|
|
|
Match(';');
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_NamespaceMemberDeclaration;
|
|
begin
|
|
if IsCurrText('type') then
|
|
Parse_TypeDeclaration
|
|
else if IsCurrText('procedure') then
|
|
Parse_ProcedureDeclaration
|
|
else if IsCurrText('function') then
|
|
Parse_FunctionDeclaration
|
|
else if IsCurrText('class') then
|
|
begin
|
|
Call_SCANNER;
|
|
if IsCurrText('procedure') then
|
|
Parse_ProcedureDeclaration(true)
|
|
else if IsCurrText('function') then
|
|
Parse_FunctionDeclaration(true)
|
|
else if IsCurrText('operator') then
|
|
Parse_OperatorDeclaration
|
|
else
|
|
Match('procedure');
|
|
end
|
|
else if IsCurrText('var') then
|
|
Parse_VariableDeclaration
|
|
else if IsCurrText('const') then
|
|
Parse_ConstantDeclaration
|
|
else if IsCurrText('resourcestring') then
|
|
Parse_ResourcestringDeclaration
|
|
else
|
|
Match('end');
|
|
end;
|
|
|
|
function TPascalParser.Parse_Statement: Boolean;
|
|
begin
|
|
result := false;
|
|
|
|
if CurrToken.TokenClass = tcIdentifier then
|
|
if GetKind(CurrToken.Id) = KindLABEL then
|
|
if GetName(CurrToken.Id) <> '' then
|
|
begin
|
|
SetLabelHere(CurrToken.Id);
|
|
Call_SCANNER;
|
|
Match(':');
|
|
end;
|
|
|
|
Gen(OP_STMT, 0, 0, 0);
|
|
|
|
if IsCurrText('begin') then
|
|
begin
|
|
Parse_CompoundStmt;
|
|
result := true;
|
|
end
|
|
else if IsCurrText('case') then
|
|
Parse_CaseStmt
|
|
else if IsCurrText('if') then
|
|
Parse_IfStmt
|
|
else if IsCurrText('goto') then
|
|
Parse_GotoStmt
|
|
else if IsCurrText('while') then
|
|
Parse_WhileStmt
|
|
else if IsCurrText('repeat') then
|
|
Parse_RepeatStmt
|
|
else if IsCurrText('for') then
|
|
Parse_ForStmt
|
|
else if IsCurrText('break') then
|
|
begin
|
|
if (BreakStack.Count = 0) or (Lookups('break', LevelStack) > 0) then
|
|
Parse_AssignmentStmt
|
|
else
|
|
begin
|
|
RemoveLastEvalInstructionAndName('break');
|
|
Parse_BreakStmt;
|
|
end;
|
|
end
|
|
else if IsCurrText('continue') then
|
|
begin
|
|
if (ContinueStack.Count = 0) or (Lookups('continue', LevelStack) > 0) then
|
|
Parse_AssignmentStmt
|
|
else
|
|
begin
|
|
RemoveLastEvalInstructionAndName('continue');
|
|
Parse_ContinueStmt;
|
|
end;
|
|
end
|
|
else if IsCurrText('exit') then
|
|
begin
|
|
if Lookups('exit', LevelStack) > 0 then
|
|
Parse_AssignmentStmt
|
|
else
|
|
begin
|
|
RemoveLastEvalInstructionAndName('exit');
|
|
Parse_ExitStmt;
|
|
end;
|
|
end
|
|
else if IsCurrText('with') then
|
|
Parse_WithStmt
|
|
else if IsCurrText('try') then
|
|
Parse_TryStmt
|
|
else if IsCurrText('raise') then
|
|
Parse_RaiseStmt
|
|
else
|
|
begin
|
|
if IsCurrText(PrintKeyword) then
|
|
begin
|
|
if (CurrToken.Id > StdCard) and (GetKind(CurrToken.Id) = kindSUB) then
|
|
Parse_AssignmentStmt
|
|
else
|
|
begin
|
|
Call_SCANNER;
|
|
Parse_Print;
|
|
end;
|
|
end
|
|
else if IsCurrText(PrintlnKeyword) then
|
|
begin
|
|
if (CurrToken.Id > StdCard) and (GetKind(CurrToken.Id) = kindSUB) then
|
|
Parse_AssignmentStmt
|
|
else
|
|
begin
|
|
Call_SCANNER;
|
|
Parse_Println;
|
|
end;
|
|
end
|
|
else if IsCurrText('write') then
|
|
begin
|
|
Call_SCANNER;
|
|
Parse_Write;
|
|
end
|
|
else if IsCurrText('writeln') then
|
|
begin
|
|
Call_SCANNER;
|
|
Parse_Writeln;
|
|
end
|
|
else
|
|
Parse_AssignmentStmt;
|
|
end;
|
|
Gen(OP_STMT, 0, 0, 0);
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_Write;
|
|
var
|
|
ID, ID_L1, ID_L2: Integer;
|
|
begin
|
|
IsConsoleApp := true;
|
|
|
|
Match('(');
|
|
repeat
|
|
ID := Parse_Expression;
|
|
ID_L1 := 0;
|
|
ID_L2 := 0;
|
|
if IsCurrText(':') then
|
|
begin
|
|
Call_SCANNER;
|
|
ID_L1 := Parse_Expression;
|
|
end;
|
|
if IsCurrText(':') then
|
|
begin
|
|
Call_SCANNER;
|
|
ID_L2 := Parse_Expression;
|
|
end;
|
|
|
|
Gen(OP_PRINT, ID, ID_L1, ID_L2);
|
|
if NotMatch(',') then
|
|
Break;
|
|
until false;
|
|
Match(')');
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_Writeln;
|
|
begin
|
|
IsConsoleApp := true;
|
|
|
|
if IsCurrText('(') then
|
|
Parse_Write;
|
|
Gen(OP_PRINT, 0, 0, 0);
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_Print;
|
|
var
|
|
ID, ID_L1, ID_L2: Integer;
|
|
begin
|
|
if IsCurrText(';') then
|
|
begin
|
|
Exit;
|
|
end;
|
|
|
|
repeat
|
|
ID := Parse_Expression;
|
|
ID_L1 := 0;
|
|
ID_L2 := 0;
|
|
if IsCurrText(':') then
|
|
begin
|
|
Call_SCANNER;
|
|
ID_L1 := Parse_Expression;
|
|
end;
|
|
if IsCurrText(':') then
|
|
begin
|
|
Call_SCANNER;
|
|
ID_L2 := Parse_Expression;
|
|
end;
|
|
|
|
Gen(OP_PRINT_EX, ID, ID_L1, ID_L2);
|
|
if NotMatch(',') then
|
|
Break;
|
|
until false;
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_Println;
|
|
begin
|
|
if not IsCurrText(';') then
|
|
Parse_Print;
|
|
{$IFDEF PAXARM}
|
|
Gen(OP_PRINT_EX, NewConst(typeUNICSTRING, #13#10), 0, 0);
|
|
{$ELSE}
|
|
Gen(OP_PRINT_EX, NewConst(typeANSISTRING, #13#10), 0, 0);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_Block;
|
|
begin
|
|
DECLARE_SWITCH := true;
|
|
Parse_DeclarationPart;
|
|
Parse_CompoundStmt;
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_ProgramBlock(namespace_id: Integer);
|
|
var
|
|
B1, B2: Integer;
|
|
begin
|
|
{$IFDEF ZERO_NS}
|
|
namespace_id := 0;
|
|
{$ENDIF}
|
|
while IsCurrText('uses') do
|
|
Parse_UsesClause(false);
|
|
|
|
Gen(OP_END_IMPORT, 0, 0, 0);
|
|
B1 := CodeCard;
|
|
|
|
if namespace_id > 0 then
|
|
begin
|
|
BeginNamespace(namespace_id, false);
|
|
end;
|
|
|
|
while IsCurrText('namespace') do
|
|
Parse_NamespaceDeclaration;
|
|
|
|
// parse block
|
|
|
|
DECLARE_SWITCH := true;
|
|
Parse_DeclarationPart;
|
|
|
|
Gen(OP_END_INTERFACE_SECTION, CurrModule.ModuleNumber, 0, 0);
|
|
|
|
Gen(OP_BEGIN_GLOBAL_BLOCK, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
|
|
{$IFDEF HTML}
|
|
Inc(EXECUTABLE_SWITCH);
|
|
DECLARE_SWITCH := false;
|
|
Parse_StmtList;
|
|
Dec(EXECUTABLE_SWITCH);
|
|
{$ELSE}
|
|
Parse_CompoundStmt;
|
|
{$ENDIF}
|
|
|
|
B2 := CodeCard;
|
|
|
|
Gen(OP_EPILOGUE_GLOBAL_BLOCK, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_EPILOGUE_GLOBAL_BLOCK2, 0, 0, 0);
|
|
|
|
GenDestroyGlobalDynamicVariables(B1, B2);
|
|
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_END_GLOBAL_BLOCK, 0, 0, 0);
|
|
|
|
if IsCurrText('.') then
|
|
begin
|
|
// ok
|
|
end
|
|
else
|
|
begin
|
|
{$IFDEF HTML}
|
|
// ok
|
|
CALL_SCANNER;
|
|
{$ELSE}
|
|
MatchFinal('.');
|
|
{$ENDIF}
|
|
end;
|
|
|
|
if namespace_id > 0 then
|
|
EndNamespace(namespace_id, false);
|
|
end;
|
|
|
|
|
|
procedure TPascalParser.ParseExternalSub(SubId: Integer);
|
|
var
|
|
SubNameId, LibId, L, I: Integer;
|
|
S: String;
|
|
b: Boolean;
|
|
label
|
|
LabName;
|
|
begin
|
|
ReplaceForwardDeclaration(SubId);
|
|
|
|
SetExternal(SubId, true);
|
|
|
|
S := GetName(SubId);
|
|
L := GetLevel(SubId);
|
|
if L > 0 then
|
|
if GetKind(L) = KindTYPE then
|
|
begin
|
|
b := false;
|
|
for I := 0 to OuterList.Count - 1 do
|
|
if OuterList.Values[I] = L then
|
|
begin
|
|
S := ExtractFullName(OuterList.Keys[I]) + '.' + GetName(L) + '.' + S;
|
|
b := true;
|
|
break;
|
|
end;
|
|
|
|
if not b then
|
|
S := GetName(L) + '.' + S;
|
|
end;
|
|
|
|
SubNameId := NewConst(typeSTRING, S);
|
|
|
|
ReadToken; // skip external
|
|
|
|
EndSub(SubId);
|
|
|
|
if ImportOnly then
|
|
begin
|
|
if IsCurrText(';') then
|
|
begin
|
|
Call_SCANNER;
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
if CurrToken.TokenClass = tcPCharConst then
|
|
begin
|
|
S := RemoveCh('''', CurrToken.Text);
|
|
LibId := NewConst(typeSTRING, S);
|
|
end
|
|
else
|
|
begin
|
|
LibId := Lookup(CurrToken.Text, CurrLevel);
|
|
if (LibId = 0) or (not IsStringConst(LibId)) then
|
|
LibId := Lookup(S, CurrLevel);
|
|
if not ImportOnly then
|
|
begin
|
|
if LibId = 0 then
|
|
RaiseError(errUndeclaredIdentifier, [S]);
|
|
if not IsStringConst(LibId) then
|
|
RaiseError(errIncompatibleTypesNoArgs, []);
|
|
end;
|
|
end;
|
|
|
|
if ImportOnly then
|
|
if IsCurrText('name') then
|
|
goto LabName;
|
|
|
|
|
|
ReadToken;
|
|
RemoveSub;
|
|
|
|
if IsCurrText(';') then
|
|
begin
|
|
Gen(OP_LOAD_PROC, SubId, SubNameId, LibId);
|
|
Match(';');
|
|
end
|
|
else
|
|
begin
|
|
if IsCurrText('delayed') then
|
|
begin
|
|
RemoveLastIdent(CurrToken.Id);
|
|
Call_SCANNER;
|
|
Match(';');
|
|
Exit;
|
|
end;
|
|
|
|
LabName:
|
|
|
|
Match('name');
|
|
SubNameId := CurrToken.Id;
|
|
Gen(OP_LOAD_PROC, SubId, SubNameId, LibId);
|
|
if ImportOnly then
|
|
Parse_ConstantExpression
|
|
else
|
|
Call_SCANNER;
|
|
|
|
if IsCurrText('delayed') then
|
|
begin
|
|
RemoveLastIdent(CurrToken.Id);
|
|
Call_SCANNER;
|
|
end;
|
|
|
|
Match(';');
|
|
end;
|
|
end;
|
|
|
|
procedure TPascalParser.GenExternalSub(SubId: Integer);
|
|
var
|
|
SubNameId, LibId, namespace_id: Integer;
|
|
S, TypeName: String;
|
|
begin
|
|
namespace_id := GetLevel(SubId);
|
|
if GetKind(namespace_id) = kindTYPE then
|
|
TypeName := GetName(namespace_id)
|
|
else
|
|
TypeName := '';
|
|
|
|
while GetKind(namespace_id) <> kindNAMESPACE do
|
|
namespace_id := GetLevel(namespace_id);
|
|
|
|
SetForward(SubId, false);
|
|
|
|
SetExternal(SubId, true);
|
|
|
|
ReplaceForwardDeclaration(SubId, true);
|
|
S := GetName(SubId);
|
|
if TypeName <> '' then
|
|
S := TypeName + '.' + S;
|
|
SubNameId := NewConst(typeSTRING, S);
|
|
EndSub(SubId);
|
|
RemoveSub;
|
|
|
|
LibId := NewConst(typeSTRING,
|
|
GetName(namespace_id) + '.' + PCU_FILE_EXT);
|
|
|
|
Gen(OP_LOAD_PROC, SubId, SubNameId, LibId);
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_Unit(IsExternalUnit: Boolean = false);
|
|
var
|
|
B1, B2: Integer;
|
|
|
|
procedure Parse_InterfaceSection;
|
|
|
|
procedure Parse_ProcedureHeading;
|
|
var
|
|
SubId: Integer;
|
|
DirectiveList: TIntegerList;
|
|
Declaration: String;
|
|
SavedPosition: Integer;
|
|
begin
|
|
SavedPosition := CurrToken.Position;
|
|
DECLARE_SWITCH := true;
|
|
Match('procedure');
|
|
SubId := Parse_Ident;
|
|
BeginSub(SubId);
|
|
if Assigned(OnParseBeginSubDeclaration) then
|
|
OnParseBeginSubDeclaration(Owner, GetName(SubId), SubId);
|
|
try
|
|
Parse_FormalParameterList(SubId);
|
|
SetName(CurrResultId, '');
|
|
SetKind(CurrResultId, KindNONE);
|
|
SetType(SubId, TypeVOID);
|
|
SetType(CurrResultId, TypeVOID);
|
|
|
|
if InterfaceOnly then
|
|
begin
|
|
if IsCurrText(';') then
|
|
Match(';');
|
|
end
|
|
else
|
|
Match(';');
|
|
|
|
DirectiveList := Parse_DirectiveList(SubId);
|
|
FreeAndNil(DirectiveList);
|
|
|
|
if IsCurrText('external') then
|
|
begin
|
|
ParseExternalSub(SubId);
|
|
Exit;
|
|
end;
|
|
|
|
if IsExternalUnit then
|
|
begin
|
|
GenExternalSub(SubId);
|
|
Exit;
|
|
end;
|
|
|
|
SetForward(SubId, true);
|
|
EndSub(SubId);
|
|
finally
|
|
if Assigned(OnParseEndSubDeclaration) then
|
|
begin
|
|
Declaration := ExtractText(SavedPosition, PrevPosition + PrevLength - 1);
|
|
OnParseEndSubDeclaration(Owner, GetName(SubId), SubId, Declaration);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure Parse_FunctionHeading;
|
|
var
|
|
SubId, TypeId: Integer;
|
|
DirectiveList: TIntegerList;
|
|
Declaration, StrType: String;
|
|
SavedPosition: Integer;
|
|
begin
|
|
SavedPosition := CurrToken.Position;
|
|
DECLARE_SWITCH := true;
|
|
Match('function');
|
|
SubId := Parse_Ident;
|
|
BeginSub(SubId);
|
|
if Assigned(OnParseBeginSubDeclaration) then
|
|
OnParseBeginSubDeclaration(Owner, GetName(SubId), SubId);
|
|
try
|
|
Parse_FormalParameterList(SubId);
|
|
DECLARE_SWITCH := false;
|
|
|
|
StrType := '';
|
|
|
|
TypeId := 0;
|
|
if ImportOnly then
|
|
begin
|
|
if IsCurrText(':') then
|
|
begin
|
|
Match(':');
|
|
Parse_Attribute;
|
|
DECLARE_SWITCH := true;
|
|
TypeID := Parse_Type;
|
|
StrType := GetName(TypeId);
|
|
Gen(OP_ASSIGN_TYPE, SubId, TypeID, 0);
|
|
Gen(OP_ASSIGN_TYPE, CurrResultId, TypeID, 0);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
Match(':');
|
|
Parse_Attribute;
|
|
DECLARE_SWITCH := true;
|
|
TypeID := Parse_Type;
|
|
StrType := GetName(TypeId);
|
|
Gen(OP_ASSIGN_TYPE, SubId, TypeID, 0);
|
|
Gen(OP_ASSIGN_TYPE, CurrResultId, TypeID, 0);
|
|
end;
|
|
|
|
if Assigned(OnParseResultType) then
|
|
OnParseResultType(Owner, StrType, TypeId);
|
|
|
|
DECLARE_SWITCH := true;
|
|
|
|
if InterfaceOnly then
|
|
begin
|
|
if IsCurrText(';') then
|
|
Match(';');
|
|
end
|
|
else
|
|
Match(';');
|
|
|
|
DirectiveList := Parse_DirectiveList(SubId);
|
|
FreeAndNil(DirectiveList);
|
|
|
|
if IsCurrText('external') then
|
|
begin
|
|
ParseExternalSub(SubId);
|
|
Exit;
|
|
end;
|
|
|
|
if IsExternalUnit then
|
|
begin
|
|
GenExternalSub(SubId);
|
|
Exit;
|
|
end;
|
|
|
|
SetForward(SubId, true);
|
|
EndSub(SubId);
|
|
finally
|
|
Declaration := ExtractText(SavedPosition, PrevPosition + PrevLength - 1);
|
|
if Assigned(OnParseEndSubDeclaration) then
|
|
OnParseEndSubDeclaration(Owner, GetName(SubId), SubId, Declaration);
|
|
end;
|
|
end;
|
|
|
|
var
|
|
ok: Boolean;
|
|
begin
|
|
Match('interface');
|
|
while IsCurrText('uses') do
|
|
Parse_UsesClause(false);
|
|
if Assigned(OnParseEndUsedUnitList) then
|
|
OnParseEndUsedUnitList(Owner);
|
|
|
|
Gen(OP_END_IMPORT, 0, 0, 0);
|
|
|
|
B1 := CodeCard;
|
|
|
|
repeat
|
|
ok := false;
|
|
if IsCurrText('var') then
|
|
begin
|
|
Parse_VariableDeclaration;
|
|
ok := true;
|
|
end
|
|
else if IsCurrText('threadvar') then
|
|
begin
|
|
Parse_VariableDeclaration;
|
|
ok := true;
|
|
end
|
|
else if IsCurrText('const') then
|
|
begin
|
|
Parse_ConstantDeclaration;
|
|
ok := true;
|
|
end
|
|
else if IsCurrText('resourcestring') then
|
|
begin
|
|
Parse_ResourcestringDeclaration;
|
|
ok := true;
|
|
end
|
|
else if IsCurrText('procedure') then
|
|
begin
|
|
Parse_ProcedureHeading;
|
|
ok := true;
|
|
end
|
|
else if IsCurrText('function') then
|
|
begin
|
|
Parse_FunctionHeading;
|
|
ok := true;
|
|
end
|
|
else if IsCurrText('type') then
|
|
begin
|
|
Parse_TypeDeclaration(IsExternalUnit);
|
|
ok := true;
|
|
end
|
|
until not ok;
|
|
end; // interface section
|
|
|
|
procedure Parse_ImplementationSection;
|
|
var
|
|
I, InnerTypeId, OuterTypeId: Integer;
|
|
S, OldFullName: String;
|
|
R: TPaxClassFactoryRec;
|
|
begin
|
|
for I := 0 to OuterList.Count - 1 do
|
|
begin
|
|
S := OuterList.Keys[I];
|
|
InnerTypeId := OuterList.Values[I];
|
|
OuterTypeId := TKernel(kernel).SymbolTable.LookupFullName(S, true);
|
|
if OuterTypeId = 0 then
|
|
RaiseError(errUndeclaredIdentifier, [S]);
|
|
OldFullName := GetFullName(InnerTypeId);
|
|
R := TKernel(kernel).ClassFactory.FindRecordByFullName(OldFullName);
|
|
if R = nil then
|
|
RaiseError(errInternalError, [S]);
|
|
R.FullClassName := S + '.' + GetName(InnerTypeId);
|
|
|
|
SetLevel(InnerTypeId, OuterTypeId);
|
|
end;
|
|
|
|
IMPLEMENTATION_SECTION := true;
|
|
Match('implementation');
|
|
while IsCurrText('uses') do
|
|
Parse_UsesClause(true);
|
|
Parse_DeclarationPart(true);
|
|
end;
|
|
|
|
procedure Parse_InitSection;
|
|
begin
|
|
DECLARE_SWITCH := false;
|
|
if IsCurrText('initialization') then
|
|
begin
|
|
BeginInitialization;
|
|
|
|
Gen(OP_BEGIN_GLOBAL_BLOCK, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
|
|
Call_SCANNER;
|
|
Parse_StmtList;
|
|
|
|
Gen(OP_EPILOGUE_GLOBAL_BLOCK, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
|
|
Gen(OP_EPILOGUE_GLOBAL_BLOCK2, 0, 0, 0);
|
|
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_END_GLOBAL_BLOCK, 0, 0, 0);
|
|
|
|
EndInitialization;
|
|
if IsCurrText('finalization') then
|
|
begin
|
|
BeginFinalization;
|
|
|
|
Gen(OP_BEGIN_GLOBAL_BLOCK, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
|
|
Call_SCANNER;
|
|
Parse_StmtList;
|
|
|
|
B2 := CodeCard;
|
|
|
|
Gen(OP_EPILOGUE_GLOBAL_BLOCK, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_EPILOGUE_GLOBAL_BLOCK2, 0, 0, 0);
|
|
|
|
GenDestroyGlobalDynamicVariables(B1, B2);
|
|
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_END_GLOBAL_BLOCK, 0, 0, 0);
|
|
|
|
EndFinalization;
|
|
end
|
|
else
|
|
begin
|
|
BeginFinalization;
|
|
|
|
Gen(OP_BEGIN_GLOBAL_BLOCK, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
|
|
B2 := CodeCard;
|
|
|
|
Gen(OP_EPILOGUE_GLOBAL_BLOCK, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_EPILOGUE_GLOBAL_BLOCK2, 0, 0, 0);
|
|
|
|
GenDestroyGlobalDynamicVariables(B1, B2);
|
|
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_END_GLOBAL_BLOCK, 0, 0, 0);
|
|
|
|
EndFinalization;
|
|
end;
|
|
|
|
Match('end');
|
|
end
|
|
else if IsCurrText('begin') then
|
|
begin
|
|
BeginInitialization;
|
|
|
|
Gen(OP_BEGIN_GLOBAL_BLOCK, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
|
|
Call_SCANNER;
|
|
Parse_StmtList;
|
|
|
|
Gen(OP_EPILOGUE_GLOBAL_BLOCK, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_EPILOGUE_GLOBAL_BLOCK2, 0, 0, 0);
|
|
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_END_GLOBAL_BLOCK, 0, 0, 0);
|
|
|
|
EndInitialization;
|
|
Match('end');
|
|
|
|
BeginFinalization;
|
|
|
|
Gen(OP_BEGIN_GLOBAL_BLOCK, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
|
|
B2 := CodeCard;
|
|
|
|
Gen(OP_EPILOGUE_GLOBAL_BLOCK, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_EPILOGUE_GLOBAL_BLOCK2, 0, 0, 0);
|
|
|
|
GenDestroyGlobalDynamicVariables(B1, B2);
|
|
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_END_GLOBAL_BLOCK, 0, 0, 0);
|
|
|
|
EndFinalization;
|
|
|
|
end
|
|
else if IsCurrText('finalization') then
|
|
begin
|
|
BeginFinalization;
|
|
|
|
Gen(OP_BEGIN_GLOBAL_BLOCK, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
|
|
Call_SCANNER;
|
|
Parse_StmtList;
|
|
|
|
B2 := CodeCard;
|
|
|
|
Gen(OP_EPILOGUE_GLOBAL_BLOCK, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_EPILOGUE_GLOBAL_BLOCK2, 0, 0, 0);
|
|
|
|
GenDestroyGlobalDynamicVariables(B1, B2);
|
|
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_END_GLOBAL_BLOCK, 0, 0, 0);
|
|
|
|
EndFinalization;
|
|
Match('end');
|
|
end
|
|
else if IsCurrText('end') then
|
|
begin
|
|
BeginFinalization;
|
|
|
|
Gen(OP_BEGIN_GLOBAL_BLOCK, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
|
|
Call_SCANNER;
|
|
|
|
B2 := CodeCard;
|
|
|
|
Gen(OP_EPILOGUE_GLOBAL_BLOCK, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_EPILOGUE_GLOBAL_BLOCK2, 0, 0, 0);
|
|
|
|
GenDestroyGlobalDynamicVariables(B1, B2);
|
|
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
Gen(OP_END_GLOBAL_BLOCK, 0, 0, 0);
|
|
|
|
EndFinalization;
|
|
end
|
|
else
|
|
Match('end');
|
|
end;
|
|
|
|
var
|
|
namespace_name: String;
|
|
namespace_id: Integer;
|
|
begin
|
|
DECLARE_SWITCH := true;
|
|
Match('unit');
|
|
namespace_id := Parse_UnitName(namespace_name);
|
|
if Assigned(OnParseUnitName) then
|
|
OnParseUnitName(Owner, namespace_name, namespace_id);
|
|
|
|
if CurrModule.IsExtra then
|
|
SaveExtraNamespace(namespace_id);
|
|
|
|
Parse_PortabilityDirective;
|
|
Match(';');
|
|
Parse_InterfaceSection;
|
|
|
|
if IsExternalUnit then
|
|
begin
|
|
Match('implementation');
|
|
Exit;
|
|
end;
|
|
|
|
Gen(OP_END_INTERFACE_SECTION, CurrModule.ModuleNumber, 0, 0);
|
|
|
|
if InterfaceOnly then
|
|
begin
|
|
if Assigned(OnParseImplementationSection) then
|
|
OnParseImplementationSection(Owner);
|
|
if ImportOnly then
|
|
Exit;
|
|
Match('implementation');
|
|
while not scanner.IsEOF do
|
|
ReadToken;
|
|
EndNamespace(namespace_id);
|
|
end
|
|
else
|
|
begin
|
|
Parse_ImplementationSection;
|
|
Inc(EXECUTABLE_SWITCH);
|
|
Parse_InitSection;
|
|
Dec(EXECUTABLE_SWITCH);
|
|
EndNamespace(namespace_id);
|
|
MatchFinal('.');
|
|
end;
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_VariableDeclaration(vis: TClassVisibility = cvNone);
|
|
var
|
|
L: TIntegerList;
|
|
I, ID, TypeID, ExprID: Integer;
|
|
S, Declaration: String;
|
|
VarNameId, LibId: Integer;
|
|
begin
|
|
L := TIntegerList.Create;
|
|
try
|
|
if InterfaceOnly then
|
|
Gen(OP_BEGIN_VAR, 0, 0, 0);
|
|
|
|
DECLARE_SWITCH := true;
|
|
if IsCurrText('threadvar') then
|
|
Call_SCANNER
|
|
else
|
|
Match('var');
|
|
|
|
repeat
|
|
Parse_Attribute;
|
|
|
|
L.Clear;
|
|
repeat
|
|
ID := Parse_Ident;
|
|
SetVisibility(ID, vis);
|
|
Gen(OP_DECLARE_LOCAL_VAR, CurrLevel, ID, 0);
|
|
L.Add(ID);
|
|
if NotMatch(',') then break;
|
|
until false;
|
|
DECLARE_SWITCH := false;
|
|
|
|
if EXPLICIT_OFF then
|
|
begin
|
|
TypeId := 0;
|
|
if IsCurrText(';') then
|
|
begin
|
|
//ok
|
|
end
|
|
else
|
|
begin
|
|
Match(':');
|
|
TypeID := Parse_Type;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
Match(':');
|
|
TypeID := Parse_Type;
|
|
end;
|
|
|
|
for I:=0 to L.Count - 1 do
|
|
Gen(OP_ASSIGN_TYPE, L[I], TypeID, 0);
|
|
|
|
S := '';
|
|
if IsCurrText('absolute') then
|
|
begin
|
|
RemoveLastIdent(CurrToken.Id);
|
|
|
|
DECLARE_SWITCH := false;
|
|
|
|
Call_SCANNER;
|
|
ExprId := Parse_Ident;
|
|
for I:=0 to L.Count - 1 do
|
|
Gen(OP_ABSOLUTE, L[I], ExprID, 0);
|
|
end
|
|
else if IsCurrText('=') then
|
|
begin
|
|
if GetKind(CurrLevel) = KindSUB then
|
|
CreateError(errCannotInitializeLocalVariables, []);
|
|
DECLARE_SWITCH := false;
|
|
|
|
Match('=');
|
|
|
|
Id := L[0];
|
|
BeginInitConst(Id);
|
|
|
|
ExprID := Parse_VariableInitialization;
|
|
S := ExtractText(PrevPosition, PrevPosition + PrevLength - 1);
|
|
for I:=0 to L.Count - 1 do
|
|
Gen(OP_ASSIGN, L[I], ExprID, L[I]);
|
|
|
|
EndInitConst(Id);
|
|
end;
|
|
|
|
Parse_PortabilityDirective;
|
|
|
|
if Assigned(OnParseVariableDeclaration) then
|
|
for I:=0 to L.Count - 1 do
|
|
begin
|
|
if S = '' then
|
|
Declaration := GetName(L[I]) + ':' + GetName(TypeID) + ';'
|
|
else
|
|
Declaration := GetName(L[I]) + ':' + GetName(TypeID) + '=' + ';';
|
|
|
|
OnParseVariableDeclaration(Owner, GetName(L[I]), L[I], GetName(TypeID),
|
|
Declaration);
|
|
end;
|
|
|
|
DECLARE_SWITCH := true;
|
|
if not MatchEx(';') then
|
|
break;
|
|
|
|
if IsCurrText('external') then
|
|
begin
|
|
SetExternal(Id, true);
|
|
|
|
S := GetName(Id);
|
|
VarNameId := NewConst(typeSTRING, S);
|
|
ReadToken; // skip external
|
|
if CurrToken.TokenClass = tcPCharConst then
|
|
begin
|
|
S := RemoveCh('''', CurrToken.Text);
|
|
LibId := NewConst(typeSTRING, S);
|
|
end
|
|
else
|
|
begin
|
|
LibId := Lookup(S, CurrLevel);
|
|
|
|
if LibId = 0 then
|
|
RaiseError(errUndeclaredIdentifier, [S]);
|
|
|
|
if not IsStringConst(LibId) then
|
|
RaiseError(errIncompatibleTypesNoArgs, []);
|
|
end;
|
|
|
|
ReadToken;
|
|
Gen(OP_LOAD_PROC, Id, VarNameId, LibId);
|
|
Match(';');
|
|
Exit;
|
|
end;
|
|
|
|
|
|
until CurrToken.TokenClass <> tcIdentifier;
|
|
|
|
finally
|
|
if InterfaceOnly then
|
|
Gen(OP_END_VAR, 0, 0, 0);
|
|
|
|
FreeAndNil(L);
|
|
end;
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_ConstantDeclaration(vis: TClassVisibility = cvNone);
|
|
var
|
|
ID: Integer;
|
|
S: String;
|
|
VarNameId, LibId, ConstId, TypeId: Integer;
|
|
Declaration: String;
|
|
SavedPosition: Integer;
|
|
IsBuildingPCU: Boolean;
|
|
begin
|
|
IsBuildingPCU := BuildingAll;
|
|
|
|
Gen(OP_EMIT_OFF, 0, 0, 0);
|
|
try
|
|
|
|
DECLARE_SWITCH := true;
|
|
Match('const');
|
|
|
|
repeat
|
|
Parse_Attribute;
|
|
|
|
SavedPosition := CurrToken.Position;
|
|
ID := Parse_Ident;
|
|
|
|
SetVisibility(Id, vis);
|
|
|
|
if InterfaceOnly then
|
|
Gen(OP_BEGIN_CONST, Id, 0, 0);
|
|
|
|
Gen(OP_DECLARE_LOCAL_VAR, CurrLevel, ID, 0);
|
|
|
|
SetKind(ID, kindCONST);
|
|
DECLARE_SWITCH := false;
|
|
if IsCurrText(':') then
|
|
begin
|
|
Match(':');
|
|
TypeId := Parse_Type;
|
|
Gen(OP_ASSIGN_TYPE, ID, TypeId, 0);
|
|
|
|
if not ImportOnly then
|
|
levelStack.Push(CurrNamespaceId);
|
|
Match('=');
|
|
Parse_ConstantInitialization(ID);
|
|
if Assigned(OnParseTypedConstantDeclaration) then
|
|
begin
|
|
Declaration := ExtractText(SavedPosition,
|
|
CurrToken.Position + CurrToken.Length - 1);
|
|
OnParseTypedConstantDeclaration(Owner,
|
|
GetName(ID), ID, GetName(TypeId), GetValue(ID), Declaration);
|
|
end;
|
|
if not ImportOnly then
|
|
levelStack.Pop;
|
|
end
|
|
else
|
|
begin
|
|
if not ImportOnly then
|
|
levelStack.Push(CurrNamespaceId);
|
|
Match('=');
|
|
if IsBuildingPCU or IsCurrText('[') then
|
|
begin
|
|
Parse_ConstantInitialization(ID);
|
|
ConstId := Id;
|
|
end
|
|
else
|
|
begin
|
|
ConstId := Parse_ConstantExpression;
|
|
if TKernel(kernel).SignCodeCompletion then
|
|
SetType(ID, GetSymbolRec(ConstId).TypeID);
|
|
|
|
Gen(OP_ASSIGN_CONST, ID, ConstId, ID);
|
|
end;
|
|
if Assigned(OnParseConstantDeclaration) then
|
|
begin
|
|
Declaration := ExtractText(SavedPosition,
|
|
CurrToken.Position + CurrToken.Length - 1);
|
|
OnParseConstantDeclaration(Owner, GetName(ID), ID, GetValue(ConstID), Declaration);
|
|
end;
|
|
if not ImportOnly then
|
|
levelStack.Pop;
|
|
end;
|
|
|
|
DECLARE_SWITCH := true;
|
|
|
|
if InterfaceOnly then
|
|
Gen(OP_END_CONST, Id, 0, 0);
|
|
|
|
Parse_PortabilityDirective;
|
|
|
|
if not MatchEx(';') then
|
|
break;
|
|
|
|
if IsCurrText('external') then
|
|
begin
|
|
S := GetName(Id);
|
|
VarNameId := NewConst(typeSTRING, S);
|
|
ReadToken; // skip external
|
|
if CurrToken.TokenClass = tcPCharConst then
|
|
begin
|
|
S := RemoveCh('''', CurrToken.Text);
|
|
LibId := NewConst(typeSTRING, S);
|
|
end
|
|
else
|
|
begin
|
|
LibId := Lookup(S, CurrLevel);
|
|
|
|
if LibId = 0 then
|
|
RaiseError(errUndeclaredIdentifier, [S]);
|
|
|
|
if not IsStringConst(LibId) then
|
|
RaiseError(errIncompatibleTypesNoArgs, []);
|
|
end;
|
|
|
|
ReadToken;
|
|
Gen(OP_LOAD_PROC, Id, VarNameId, LibId);
|
|
Match(';');
|
|
Exit;
|
|
end;
|
|
|
|
until CurrToken.TokenClass <> tcIdentifier;
|
|
|
|
finally
|
|
Gen(OP_EMIT_ON, 0, 0, 0);
|
|
end;
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_ResourcestringDeclaration;
|
|
var
|
|
ID: Integer;
|
|
Value: Variant;
|
|
Declaration: String;
|
|
IsBuildingPCU: Boolean;
|
|
begin
|
|
IsBuildingPCU := BuildingAll;
|
|
|
|
Gen(OP_EMIT_OFF, 0, 0, 0);
|
|
try
|
|
|
|
DECLARE_SWITCH := true;
|
|
Match('resourcestring');
|
|
|
|
repeat
|
|
|
|
ID := Parse_Ident;
|
|
Gen(OP_DECLARE_LOCAL_VAR, CurrLevel, ID, 0);
|
|
|
|
SetKind(ID, kindCONST);
|
|
DECLARE_SWITCH := false;
|
|
Match('=');
|
|
if IsBuildingPCU then
|
|
Parse_ConstantInitialization(ID)
|
|
else
|
|
Gen(OP_ASSIGN_CONST, ID, Parse_ConstantExpression, ID);
|
|
|
|
if Assigned(OnParseConstantDeclaration) then
|
|
begin
|
|
Value := GetValue(Id);
|
|
if not VariantIsString(Value) then
|
|
Value := String(Chr(Integer(Value)));
|
|
Declaration := GetName(Id) + ' = ' + Value;
|
|
OnParseResourceStringDeclaration(Owner, GetName(ID), ID, Value, Declaration);
|
|
end;
|
|
|
|
Parse_PortabilityDirective;
|
|
|
|
DECLARE_SWITCH := true;
|
|
if not MatchEx(';') then
|
|
break;
|
|
|
|
until CurrToken.TokenClass <> tcIdentifier;
|
|
|
|
finally
|
|
Gen(OP_EMIT_ON, 0, 0, 0);
|
|
end;
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_ConstantInitialization(ID: Integer);
|
|
var
|
|
ExprId, ItemId, NameId, K, ConstId: Integer;
|
|
begin
|
|
BeginInitConst(Id);
|
|
|
|
if IsCurrText('(') then
|
|
begin
|
|
K := -1;
|
|
Call_SCANNER;
|
|
repeat
|
|
if IsCurrText(')') then
|
|
break;
|
|
|
|
Inc(K);
|
|
if IsCurrText('(') then
|
|
begin
|
|
ExprId := NewTempVar();
|
|
SetLevel(ExprId, 0);
|
|
Parse_ConstantInitialization(ExprId);
|
|
Gen(OP_ASSIGN_SHIFT, 0, K, ExprId);
|
|
if NotMatch(',') then
|
|
break;
|
|
end
|
|
else
|
|
begin
|
|
ItemId := NewTempVar();
|
|
SetLevel(ItemId, 0);
|
|
|
|
if IsNextText(':') then
|
|
begin
|
|
SetName(CurrToken.Id, '');
|
|
SetKind(CurrToken.Id, KindNONE);
|
|
NameId := NewConst(typeSTRING, CurrToken.Text);
|
|
SetKind(NameId, kindNONE);
|
|
|
|
Call_SCANNER;
|
|
Match(':');
|
|
if IsCurrText('(') then
|
|
begin
|
|
ExprId := NewTempVar();
|
|
SetLevel(ExprId, 0);
|
|
|
|
Parse_ConstantInitialization(ExprId);
|
|
Gen(OP_ASSIGN_SHIFT, 0, K, ExprId);
|
|
end
|
|
else
|
|
begin
|
|
ExprId := Parse_ConstantExpression;
|
|
Gen(OP_RECORD_ITEM, ID, NameId, ItemId);
|
|
Gen(OP_ASSIGN, ItemId, ExprId, ItemId);
|
|
end;
|
|
if NotMatch(';') then
|
|
break;
|
|
end
|
|
else
|
|
begin
|
|
ExprId := Parse_ConstantExpression;
|
|
Gen(OP_ITEM, ID, K, ItemId);
|
|
Gen(OP_ASSIGN, ItemId, ExprId, ItemId);
|
|
if NotMatch(',') then
|
|
break;
|
|
end;
|
|
end;
|
|
until false;
|
|
Match(')');
|
|
end
|
|
else
|
|
begin
|
|
ConstId := Parse_ConstantExpression;
|
|
Gen(OP_ASSIGN, ID, ConstId, ID);
|
|
SetValue(Id, GetValue(ConstId));
|
|
end;
|
|
|
|
EndInitConst(Id);
|
|
end;
|
|
|
|
function TPascalParser.Parse_VariableInitialization: Integer;
|
|
var
|
|
ExprId, ItemId, NameId, K: Integer;
|
|
begin
|
|
if IsCurrText('(') then
|
|
begin
|
|
result := NewTempVar;
|
|
K := -1;
|
|
Call_SCANNER;
|
|
repeat
|
|
if IsCurrText(')') then
|
|
break;
|
|
|
|
Inc(K);
|
|
if IsCurrText('(') then
|
|
begin
|
|
ExprId := NewTempVar();
|
|
SetLevel(ExprId, 0);
|
|
Gen(OP_ASSIGN, ExprId, Parse_VariableInitialization, ExprId);
|
|
Gen(OP_ASSIGN_SHIFT, 0, K, ExprId);
|
|
if NotMatch(',') then
|
|
break;
|
|
end
|
|
else
|
|
begin
|
|
ItemId := NewTempVar();
|
|
SetLevel(ItemId, 0);
|
|
|
|
if IsNextText(':') then
|
|
begin
|
|
SetName(CurrToken.Id, '');
|
|
SetKind(CurrToken.Id, KindNONE);
|
|
NameId := NewConst(typeSTRING, CurrToken.Text);
|
|
SetKind(NameId, kindNONE);
|
|
|
|
Call_SCANNER;
|
|
Match(':');
|
|
if IsCurrText('(') then
|
|
begin
|
|
ExprId := NewTempVar();
|
|
SetLevel(ExprId, 0);
|
|
|
|
Gen(OP_ASSIGN, ExprId, Parse_VariableInitialization, ExprId);
|
|
Gen(OP_ASSIGN_SHIFT, 0, K, ExprId);
|
|
end
|
|
else
|
|
begin
|
|
ExprId := Parse_Expression;
|
|
Gen(OP_RECORD_ITEM, result, NameId, ItemId);
|
|
Gen(OP_ASSIGN, ItemId, ExprId, ItemId);
|
|
end;
|
|
if NotMatch(';') then
|
|
break;
|
|
end
|
|
else
|
|
begin
|
|
ExprId := Parse_Expression;
|
|
Gen(OP_ITEM, result, K, ItemId);
|
|
Gen(OP_ASSIGN, ItemId, ExprId, ItemId);
|
|
if NotMatch(',') then
|
|
break;
|
|
end;
|
|
end;
|
|
until false;
|
|
Match(')');
|
|
end
|
|
else
|
|
result := Parse_Expression;
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_LabelDeclaration;
|
|
begin
|
|
DECLARE_SWITCH := true;
|
|
Match('label');
|
|
repeat
|
|
Parse_Label;
|
|
if NotMatch(',') then break;
|
|
until false;
|
|
Match(';');
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_TypeDeclaration(IsExternalUnit: Boolean = false;
|
|
vis: TClassVisibility = cvPublic);
|
|
var
|
|
ok: Boolean;
|
|
TypeID, T, SubId, TypeBaseId: Integer;
|
|
IsPacked: Boolean;
|
|
S, Q: String;
|
|
begin
|
|
TypeParams.Clear;
|
|
DECLARE_SWITCH := true;
|
|
Match('type');
|
|
repeat
|
|
Parse_Attribute;
|
|
|
|
BeginTypeDef(CurrToken.Id);
|
|
TypeId := Parse_Ident;
|
|
SetVisibility(TypeId, vis);
|
|
SetKind(TypeId, KindTYPE);
|
|
SetLevel(TypeId, CurrLevel);
|
|
|
|
if Assigned(OnParseTypeDeclaration) then
|
|
OnParseTypeDeclaration(Owner, GetName(TypeId), TypeId);
|
|
|
|
S := GetFullName(TypeId);
|
|
while IsCurrText('.') do
|
|
begin
|
|
SetKind(TypeId, KindNONE);
|
|
SetName(TypeId, '');
|
|
|
|
Call_SCANNER;
|
|
TypeId := Parse_Ident;
|
|
|
|
S := S + '.' + GetName(TypeId);
|
|
end;
|
|
|
|
if S <> GetFullName(TypeId) then
|
|
begin
|
|
S := ExtractFullOwner(S);
|
|
OuterList.AddValue(S, TypeId);
|
|
end;
|
|
|
|
SetKind(TypeID, KindTYPE);
|
|
if InterfaceOnly then
|
|
Gen(OP_BEGIN_TYPE, TypeId, 0, 0);
|
|
|
|
DECLARE_SWITCH := false;
|
|
Match('=');
|
|
ok := false;
|
|
|
|
if IsCurrText('packed') then
|
|
begin
|
|
Match('packed');
|
|
IsPacked := true;
|
|
end
|
|
else
|
|
IsPacked := false;
|
|
|
|
if IsCurrText('array') then
|
|
begin
|
|
IsPacked := true;
|
|
Parse_ArrayTypeDeclaration(TypeID, IsPacked);
|
|
Parse_PortabilityDirective;
|
|
|
|
EndTypeDef(TypeId);
|
|
|
|
DECLARE_SWITCH := true;
|
|
ok := MatchEx(';');
|
|
end
|
|
else if IsCurrText('record') then
|
|
begin
|
|
DECLARE_SWITCH := true;
|
|
Parse_RecordTypeDeclaration(TypeID, IsPacked);
|
|
Parse_PortabilityDirective;
|
|
|
|
EndTypeDef(TypeId);
|
|
|
|
DECLARE_SWITCH := true;
|
|
ok := MatchEx(';');
|
|
end
|
|
else if IsCurrText('class') then
|
|
begin
|
|
IsPacked := true;
|
|
DECLARE_SWITCH := true;
|
|
Parse_ClassTypeDeclaration(TypeID, IsPacked, IsExternalUnit);
|
|
Parse_PortabilityDirective;
|
|
|
|
EndTypeDef(TypeId);
|
|
|
|
DECLARE_SWITCH := true;
|
|
ok := MatchEx(';');
|
|
end
|
|
else if IsCurrText('interface') then
|
|
begin
|
|
DECLARE_SWITCH := true;
|
|
Parse_InterfaceTypeDeclaration(TypeID);
|
|
Parse_PortabilityDirective;
|
|
|
|
EndTypeDef(TypeId);
|
|
|
|
DECLARE_SWITCH := true;
|
|
ok := MatchEx(';');
|
|
end
|
|
else if IsCurrText('dispinterface') then
|
|
begin
|
|
if not ImportOnly then
|
|
RaiseNotImpl;
|
|
|
|
DECLARE_SWITCH := true;
|
|
Parse_InterfaceTypeDeclaration(TypeID);
|
|
Parse_PortabilityDirective;
|
|
|
|
EndTypeDef(TypeId);
|
|
|
|
DECLARE_SWITCH := true;
|
|
ok := MatchEx(';');
|
|
end
|
|
else if IsCurrText('reference') then
|
|
begin
|
|
RemoveLastIdent(CurrToken.Id);
|
|
DECLARE_SWITCH := true;
|
|
Call_SCANNER;
|
|
Match('to');
|
|
Parse_MethodRefTypeDeclaration(TypeID);
|
|
Parse_PortabilityDirective;
|
|
|
|
DECLARE_SWITCH := true;
|
|
ok := true;
|
|
end
|
|
else if IsCurrText('^') then
|
|
begin
|
|
if IsPacked then
|
|
CreateError(errPACKEDNotAllowedHere, []);
|
|
if TypeParams.Count > 0 then
|
|
RaiseError(errTypeParameterNotAllowed, []);
|
|
|
|
Parse_PointerTypeDeclaration(TypeID);
|
|
Parse_PortabilityDirective;
|
|
|
|
DECLARE_SWITCH := true;
|
|
ok := MatchEx(';');
|
|
end
|
|
else if IsCurrText('(') then
|
|
begin
|
|
if IsPacked then
|
|
CreateError(errPACKEDNotAllowedHere, []);
|
|
if TypeParams.Count > 0 then
|
|
RaiseError(errTypeParameterNotAllowed, []);
|
|
|
|
DECLARE_SWITCH := true;
|
|
Parse_EnumTypeDeclaration(TypeID);
|
|
Parse_PortabilityDirective;
|
|
|
|
DECLARE_SWITCH := true;
|
|
ok := MatchEx(';');
|
|
end
|
|
else if IsCurrText('procedure') or IsCurrText('function') then
|
|
begin
|
|
if IsPacked then
|
|
CreateError(errPACKEDNotAllowedHere, []);
|
|
|
|
DECLARE_SWITCH := true;
|
|
Parse_ProceduralTypeDeclaration(TypeID, SubId);
|
|
|
|
EndTypeDef(TypeId);
|
|
|
|
DECLARE_SWITCH := true;
|
|
if InterfaceOnly then
|
|
begin
|
|
if IsCurrText(';') then
|
|
ok := MatchEx(';');
|
|
end
|
|
else
|
|
ok := MatchEx(';');
|
|
end
|
|
else if IsCurrText('set') then
|
|
begin
|
|
if IsPacked then
|
|
CreateError(errPACKEDNotAllowedHere, []);
|
|
if TypeParams.Count > 0 then
|
|
RaiseError(errTypeParameterNotAllowed, []);
|
|
|
|
DECLARE_SWITCH := true;
|
|
Parse_SetTypeDeclaration(TypeID);
|
|
Parse_PortabilityDirective;
|
|
|
|
DECLARE_SWITCH := true;
|
|
ok := MatchEx(';');
|
|
end
|
|
else if CurrToken.TokenClass = tcIntegerConst then
|
|
begin
|
|
if IsPacked then
|
|
CreateError(errPACKEDNotAllowedHere, []);
|
|
if TypeParams.Count > 0 then
|
|
RaiseError(errTypeParameterNotAllowed, []);
|
|
|
|
Parse_SubrangeTypeDeclaration(TypeID, typeINTEGER, Q, 0);
|
|
Parse_PortabilityDirective;
|
|
|
|
DECLARE_SWITCH := true;
|
|
ok := MatchEx(';');
|
|
end
|
|
else if CurrToken.TokenClass = tcCharConst then
|
|
begin
|
|
if IsPacked then
|
|
CreateError(errPACKEDNotAllowedHere, []);
|
|
if TypeParams.Count > 0 then
|
|
RaiseError(errTypeParameterNotAllowed, []);
|
|
|
|
Parse_SubrangeTypeDeclaration(TypeID, typeCHAR, Q, 0);
|
|
Parse_PortabilityDirective;
|
|
|
|
DECLARE_SWITCH := true;
|
|
ok := MatchEx(';');
|
|
end
|
|
else if CurrToken.TokenClass = tcBooleanConst then
|
|
begin
|
|
if IsPacked then
|
|
CreateError(errPACKEDNotAllowedHere, []);
|
|
if TypeParams.Count > 0 then
|
|
RaiseError(errTypeParameterNotAllowed, []);
|
|
|
|
Parse_SubrangeTypeDeclaration(TypeID, typeBOOLEAN, Q, 0);
|
|
Parse_PortabilityDirective;
|
|
|
|
DECLARE_SWITCH := true;
|
|
ok := MatchEx(';');
|
|
end
|
|
else
|
|
begin
|
|
if IsPacked then
|
|
CreateError(errPACKEDNotAllowedHere, []);
|
|
|
|
if IsCurrText('type') then
|
|
begin
|
|
Call_SCANNER;
|
|
if IsCurrText('of') then
|
|
Call_SCANNER;
|
|
end;
|
|
|
|
if IsCurrText('string') then
|
|
begin
|
|
Call_SCANNER;
|
|
if IsCurrText('[') then
|
|
begin
|
|
{$IFDEF PAXARM}
|
|
Match(';');
|
|
{$ELSE}
|
|
Parse_ShortStringTypeDeclaration(TypeID);
|
|
{$ENDIF}
|
|
end
|
|
else
|
|
begin
|
|
if InterfaceOnly then
|
|
Gen(OP_BEGIN_ALIAS_TYPE, TypeId, 0, 0);
|
|
SetType(TypeId, typeALIAS);
|
|
Gen(OP_ASSIGN_TYPE_ALIAS, TypeId, typeSTRING, 0);
|
|
if Assigned(OnParseAliasTypeDeclaration) then
|
|
OnParseAliasTypeDeclaration(Owner, GetName(TypeId), TypeId, 'string',
|
|
GetName(TypeId) + ' = string;');
|
|
if InterfaceOnly then
|
|
Gen(OP_END_ALIAS_TYPE, TypeId, 0, 0);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
case CurrToken.TokenClass of
|
|
tcSpecial: typeBaseId := typeINTEGER;
|
|
tcIntegerConst: typeBaseId := typeINTEGER;
|
|
tcCharConst: typeBaseId := typeCHAR;
|
|
tcBooleanConst: typeBaseId := typeBOOLEAN;
|
|
tcIdentifier: typeBaseId := GetType(CurrToken.Id);
|
|
else
|
|
TypeBaseId := typeINTEGER;
|
|
end;
|
|
|
|
T := Parse_Expression;
|
|
|
|
if IsCurrText('..') then
|
|
Parse_SubrangeTypeDeclaration(TypeID, TypeBaseId, Q, T)
|
|
else
|
|
begin
|
|
if InterfaceOnly then
|
|
Gen(OP_BEGIN_ALIAS_TYPE, TypeId, 0, 0);
|
|
SetType(TypeId, typeALIAS);
|
|
Gen(OP_ASSIGN_TYPE_ALIAS, TypeId, T, 0);
|
|
if Assigned(OnParseAliasTypeDeclaration) then
|
|
OnParseAliasTypeDeclaration(Owner, GetName(TypeId), TypeId, GetName(T),
|
|
GetName(TypeId) + ' = ' + GetName(T) + ';');
|
|
if InterfaceOnly then
|
|
Gen(OP_END_ALIAS_TYPE, TypeId, 0, 0);
|
|
end;
|
|
end;
|
|
|
|
Parse_PortabilityDirective;
|
|
|
|
DECLARE_SWITCH := true;
|
|
TypeParams.Clear;
|
|
ok := MatchEx(';');
|
|
end;
|
|
|
|
Gen(OP_ADD_TYPEINFO, TypeId, 0, 0);
|
|
|
|
if InterfaceOnly then
|
|
Gen(OP_END_TYPE, TypeId, 0, 0);
|
|
|
|
if CurrToken.TokenClass = tcKeyword then
|
|
Break;
|
|
until not ok;
|
|
end;
|
|
|
|
function TPascalParser.Parse_OrdinalType(var Declaration: String): Integer;
|
|
var
|
|
T: Integer;
|
|
begin
|
|
Declaration := '';
|
|
if IsCurrText('(') then
|
|
begin
|
|
result := NewTempVar;
|
|
Parse_EnumTypeDeclaration(result);
|
|
end
|
|
else if (CurrToken.TokenClass = tcIntegerConst) or IsCurrText('-') then
|
|
begin
|
|
result := NewTempVar;
|
|
Parse_SubrangeTypeDeclaration(result, typeINTEGER, Declaration, 0);
|
|
end
|
|
else if CurrToken.TokenClass = tcCharConst then
|
|
begin
|
|
result := NewTempVar;
|
|
Parse_SubrangeTypeDeclaration(result, typeCHAR, Declaration, 0);
|
|
end
|
|
else if CurrToken.TokenClass = tcBooleanConst then
|
|
begin
|
|
result := NewTempVar;
|
|
Parse_SubrangeTypeDeclaration(result, typeBOOLEAN, Declaration, 0);
|
|
end
|
|
else if IsCurrText('ord') and IsNextText('(') then
|
|
begin
|
|
result := NewTempVar;
|
|
Parse_SubrangeTypeDeclaration(result, typeBYTE, Declaration, 0);
|
|
end
|
|
else if IsCurrText('chr') and IsNextText('(') then
|
|
begin
|
|
result := NewTempVar;
|
|
Parse_SubrangeTypeDeclaration(result, typeCHAR, Declaration, 0);
|
|
end
|
|
else if IsCurrText('low') and IsNextText('(') then
|
|
begin
|
|
result := NewTempVar;
|
|
Parse_SubrangeTypeDeclaration(result, typeBYTE, Declaration, 0);
|
|
end
|
|
else if IsCurrText('high') and IsNextText('(') then
|
|
begin
|
|
result := NewTempVar;
|
|
Parse_SubrangeTypeDeclaration(result, typeBYTE, Declaration, 0);
|
|
end
|
|
else
|
|
begin
|
|
T := Parse_QualId;
|
|
|
|
if IsCurrText('..') then
|
|
begin
|
|
result := NewTempVar;
|
|
Parse_SubrangeTypeDeclaration(result, typeENUM, Declaration, T);
|
|
end
|
|
else
|
|
begin
|
|
result := T;
|
|
Declaration := GetName(T);
|
|
// AddTypeExpRec(result);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TPascalParser.Parse_OpenArrayType(var ElemTypeName: String): Integer;
|
|
begin
|
|
DECLARE_SWITCH := true;
|
|
Match('array');
|
|
DECLARE_SWITCH := false;
|
|
Match('of');
|
|
ElemTypeName := CurrToken.Text;
|
|
if IsCurrText('const') then
|
|
begin
|
|
Call_SCANNER;
|
|
result := H_Dynarray_TVarRec;
|
|
end
|
|
else if IsCurrText('Integer') then
|
|
begin
|
|
Call_SCANNER;
|
|
result := H_Dynarray_Integer;
|
|
end
|
|
{$IFDEF UNIC}
|
|
else if IsCurrText('String') then
|
|
begin
|
|
ElemTypeName := 'UnicodeString';
|
|
Call_SCANNER;
|
|
result := H_Dynarray_UnicodeString;
|
|
end
|
|
else if IsCurrText('Char') then
|
|
begin
|
|
ElemTypeName := 'WideChar';
|
|
Call_SCANNER;
|
|
result := H_Dynarray_AnsiChar;
|
|
end
|
|
{$ELSE}
|
|
else if IsCurrText('String') then
|
|
begin
|
|
ElemTypeName := 'AnsiString';
|
|
Call_SCANNER;
|
|
result := H_Dynarray_AnsiString;
|
|
end
|
|
else if IsCurrText('Char') then
|
|
begin
|
|
ElemTypeName := 'AnsiChar';
|
|
Call_SCANNER;
|
|
result := H_Dynarray_WideChar;
|
|
end
|
|
{$ENDIF}
|
|
else if IsCurrText('Byte') then
|
|
begin
|
|
Call_SCANNER;
|
|
result := H_Dynarray_Byte;
|
|
end
|
|
else if IsCurrText('Word') then
|
|
begin
|
|
Call_SCANNER;
|
|
result := H_Dynarray_Word;
|
|
end
|
|
else if IsCurrText('ShortInt') then
|
|
begin
|
|
Call_SCANNER;
|
|
result := H_Dynarray_ShortInt;
|
|
end
|
|
else if IsCurrText('SmallInt') then
|
|
begin
|
|
Call_SCANNER;
|
|
result := H_Dynarray_SmallInt;
|
|
end
|
|
else if IsCurrText('Cardinal') then
|
|
begin
|
|
Call_SCANNER;
|
|
result := H_Dynarray_Cardinal;
|
|
end
|
|
else if IsCurrText('Int64') then
|
|
begin
|
|
Call_SCANNER;
|
|
result := H_Dynarray_Int64;
|
|
end
|
|
else if IsCurrText('UInt64') then
|
|
begin
|
|
Call_SCANNER;
|
|
result := H_Dynarray_UInt64;
|
|
end
|
|
else if IsCurrText('AnsiChar') then
|
|
begin
|
|
Call_SCANNER;
|
|
result := H_Dynarray_AnsiChar;
|
|
end
|
|
else if IsCurrText('WideChar') then
|
|
begin
|
|
Call_SCANNER;
|
|
result := H_Dynarray_WideChar;
|
|
end
|
|
else if IsCurrText('AnsiString') then
|
|
begin
|
|
Call_SCANNER;
|
|
result := H_Dynarray_AnsiString;
|
|
end
|
|
else if IsCurrText('WideString') then
|
|
begin
|
|
Call_SCANNER;
|
|
result := H_Dynarray_WideString;
|
|
end
|
|
else if IsCurrText('UnicodeString') then
|
|
begin
|
|
Call_SCANNER;
|
|
result := H_Dynarray_UnicodeString;
|
|
end
|
|
else if IsCurrText('ShortString') then
|
|
begin
|
|
Call_SCANNER;
|
|
result := H_Dynarray_ShortString;
|
|
end
|
|
else if IsCurrText('Double') then
|
|
begin
|
|
Call_SCANNER;
|
|
result := H_Dynarray_Double;
|
|
end
|
|
else if IsCurrText('Single') then
|
|
begin
|
|
Call_SCANNER;
|
|
result := H_Dynarray_Single;
|
|
end
|
|
else if IsCurrText('Extended') then
|
|
begin
|
|
Call_SCANNER;
|
|
result := H_Dynarray_Extended;
|
|
end
|
|
else if IsCurrText('Currency') then
|
|
begin
|
|
Call_SCANNER;
|
|
result := H_Dynarray_Currency;
|
|
end
|
|
else if IsCurrText('Boolean') then
|
|
begin
|
|
Call_SCANNER;
|
|
result := H_Dynarray_Boolean;
|
|
end
|
|
else if IsCurrText('ByteBool') then
|
|
begin
|
|
Call_SCANNER;
|
|
result := H_Dynarray_ByteBool;
|
|
end
|
|
else if IsCurrText('WordBool') then
|
|
begin
|
|
Call_SCANNER;
|
|
result := H_Dynarray_WordBool;
|
|
end
|
|
else if IsCurrText('LongBool') then
|
|
begin
|
|
Call_SCANNER;
|
|
result := H_Dynarray_LongBool;
|
|
end
|
|
else if IsCurrText('Variant') then
|
|
begin
|
|
Call_SCANNER;
|
|
result := H_Dynarray_Variant;
|
|
end
|
|
else if IsCurrText('OleVariant') then
|
|
begin
|
|
Call_SCANNER;
|
|
result := H_Dynarray_OleVariant;
|
|
end
|
|
else if IsCurrText('Pointer') then
|
|
begin
|
|
Call_SCANNER;
|
|
result := H_Dynarray_Pointer;
|
|
end
|
|
else
|
|
begin
|
|
result := NewTempVar;
|
|
BeginOpenArrayType(result);
|
|
Gen(OP_CREATE_DYNAMIC_ARRAY_TYPE, result, Parse_Ident, 0);
|
|
EndOpenArrayType(result, ElemTypeName);
|
|
end;
|
|
DECLARE_SWITCH := false;
|
|
end;
|
|
|
|
function TPascalParser.Parse_Type: Integer;
|
|
var
|
|
IsPacked: Boolean;
|
|
SubId: Integer;
|
|
S: String;
|
|
begin
|
|
IsPacked := false;
|
|
|
|
if IsCurrText('packed') then
|
|
begin
|
|
Match('packed');
|
|
IsPacked := true;
|
|
end
|
|
else if IsCurrText('System') then
|
|
begin
|
|
Match('System');
|
|
Match('.');
|
|
end;
|
|
|
|
if IsCurrText('array') then
|
|
begin
|
|
result := NewTempVar;
|
|
DECLARE_SWITCH := true;
|
|
Parse_ArrayTypeDeclaration(result, IsPacked);
|
|
DECLARE_SWITCH := false;
|
|
end
|
|
else if IsCurrText('record') then
|
|
begin
|
|
result := NewTempVar;
|
|
DECLARE_SWITCH := true;
|
|
Parse_RecordTypeDeclaration(result, IsPacked);
|
|
DECLARE_SWITCH := false;
|
|
end
|
|
else if IsCurrText('class') then
|
|
begin
|
|
result := NewTempVar;
|
|
DECLARE_SWITCH := true;
|
|
Parse_ClassTypeDeclaration(result, IsPacked);
|
|
DECLARE_SWITCH := false;
|
|
end
|
|
else if IsCurrText('interface') then
|
|
begin
|
|
result := NewTempVar;
|
|
DECLARE_SWITCH := true;
|
|
Parse_InterfaceTypeDeclaration(result);
|
|
DECLARE_SWITCH := false;
|
|
end
|
|
else if IsCurrText('dispinterface') then
|
|
begin
|
|
result := NewTempVar;
|
|
DECLARE_SWITCH := true;
|
|
Parse_InterfaceTypeDeclaration(result);
|
|
DECLARE_SWITCH := false;
|
|
end
|
|
else if IsCurrText('reference') then
|
|
begin
|
|
RemoveLastIdent(CurrToken.Id);
|
|
result := NewTempVar;
|
|
DECLARE_SWITCH := true;
|
|
Call_SCANNER;
|
|
Match('to');
|
|
Parse_MethodRefTypeDeclaration(result);
|
|
DECLARE_SWITCH := false;
|
|
end
|
|
else if IsCurrText('^') then
|
|
begin
|
|
result := NewTempVar;
|
|
Parse_PointerTypeDeclaration(result);
|
|
DECLARE_SWITCH := false;
|
|
end
|
|
else if IsCurrText('set') then
|
|
begin
|
|
result := NewTempVar;
|
|
Parse_SetTypeDeclaration(result);
|
|
DECLARE_SWITCH := false;
|
|
end
|
|
else if IsCurrText('procedure') or IsCurrText('function') then
|
|
begin
|
|
result := NewTempVar;
|
|
Parse_ProceduralTypeDeclaration(result, SubId);
|
|
DECLARE_SWITCH := false;
|
|
end
|
|
else if IsCurrText('string') then
|
|
begin
|
|
// result := Parse_Ident;
|
|
{$IFDEF PAXARM}
|
|
result := typeUNICSTRING;
|
|
{$ELSE}
|
|
if IsUNIC then
|
|
result := typeUNICSTRING
|
|
else
|
|
result := typeANSISTRING;
|
|
{$ENDIF}
|
|
|
|
Call_SCANNER;
|
|
|
|
if IsCurrText('[') then
|
|
begin
|
|
result := NewTempVar;
|
|
{$IFDEF PAXARM}
|
|
Match(';');
|
|
{$ELSE}
|
|
Parse_ShortStringTypeDeclaration(result);
|
|
{$ENDIF}
|
|
DECLARE_SWITCH := false;
|
|
end;
|
|
end
|
|
else if IsCurrText('double') then
|
|
begin
|
|
result := Parse_Ident;
|
|
end
|
|
else
|
|
begin
|
|
result := Parse_OrdinalType(S);
|
|
end;
|
|
|
|
Gen(OP_ADD_TYPEINFO, result, 0, 0);
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_ArrayTypeDeclaration(ArrayTypeID: Integer; IsPacked: Boolean);
|
|
var
|
|
I, T, RangeTypeId, ElemTypeId: Integer;
|
|
L: TIntegerList;
|
|
RangeList: TStringList;
|
|
Declaration, S: String;
|
|
begin
|
|
L := TIntegerList.Create;
|
|
RangeList := TStringList.Create;
|
|
|
|
try
|
|
Match('array');
|
|
DECLARE_SWITCH := false;
|
|
|
|
if IsCurrText('of') then // dynamic array
|
|
begin
|
|
Match('of');
|
|
BeginDynamicArrayType(ArrayTypeID);
|
|
if IsCurrText('const') then
|
|
begin
|
|
Call_SCANNER;
|
|
Gen(OP_CREATE_DYNAMIC_ARRAY_TYPE, ArrayTypeId, H_TVarRec, 0);
|
|
ElemTypeId := H_TVarRec;
|
|
end
|
|
else
|
|
begin
|
|
ElemTypeId := Parse_Type;
|
|
Gen(OP_CREATE_DYNAMIC_ARRAY_TYPE, ArrayTypeId, ElemTypeId, 0);
|
|
end;
|
|
EndDynamicArrayType(ArrayTypeID);
|
|
if Assigned(OnParseDynArrayTypeDeclaration) then
|
|
begin
|
|
Declaration := 'array of ' + ExtractText(PrevPosition, PrevPosition + PrevLength - 1);
|
|
OnParseDynArrayTypeDeclaration(Owner, GetName(ArrayTypeId), ArrayTypeId,
|
|
GetName(ElemTypeId), Declaration);
|
|
end;
|
|
end
|
|
else // static array
|
|
begin
|
|
|
|
BeginArrayType(ArrayTypeID);
|
|
if IsPacked then
|
|
SetPacked(ArrayTypeID);
|
|
L.Add(ArrayTypeId);
|
|
|
|
Match('[');
|
|
repeat
|
|
T := NewTypeAlias;
|
|
RangeTypeId := Parse_OrdinalType(S);
|
|
Gen(OP_ASSIGN_TYPE_ALIAS, T, RangeTypeId, 0);
|
|
RangeList.Add(S);
|
|
|
|
if IsCurrText(',') then
|
|
begin
|
|
Match(',');
|
|
|
|
ArrayTypeId := NewTempVar;
|
|
BeginArrayType(ArrayTypeID);
|
|
if IsPacked then
|
|
SetPacked(ArrayTypeID);
|
|
L.Add(ArrayTypeId);
|
|
end
|
|
else
|
|
break;
|
|
until false;
|
|
|
|
Match(']');
|
|
Match('of');
|
|
|
|
T := NewTypeAlias;
|
|
ElemTypeId := Parse_Type;
|
|
Gen(OP_ASSIGN_TYPE_ALIAS, T, ElemTypeId, 0);
|
|
|
|
DECLARE_SWITCH := true;
|
|
|
|
for I:=0 to L.Count - 1 do
|
|
begin
|
|
EndArrayType(L[I]);
|
|
end;
|
|
|
|
if Assigned(OnParseArrayTypeDeclaration) then
|
|
begin
|
|
S := GetName(ElemTypeId);
|
|
OnParseArrayTypeDeclaration(Owner, GetName(L[0]), L[0],
|
|
RangeList,
|
|
S);
|
|
end;
|
|
end;
|
|
finally
|
|
FreeAndNil(L);
|
|
FreeAndNil(RangeList);
|
|
end;
|
|
end;
|
|
|
|
function TPascalParser.Parse_RecordConstructorHeading(IsSharedMethod: Boolean;
|
|
RecordTypeId: Integer;
|
|
Vis: TClassVisibility;
|
|
IsExternalUnit: Boolean): Integer;
|
|
var
|
|
DirectiveList: TIntegerList;
|
|
Declaration: String;
|
|
SavedPosition: Integer;
|
|
begin
|
|
SavedPosition := CurrToken.Position;
|
|
DECLARE_SWITCH := true;
|
|
Match('constructor');
|
|
result := Parse_Ident;
|
|
Gen(OP_DECLARE_MEMBER, CurrLevel, result, 0);
|
|
SetVisibility(result, vis);
|
|
BeginStructureConstructor(result, RecordTypeId);
|
|
if Assigned(OnParseBeginSubDeclaration) then
|
|
OnParseBeginSubDeclaration(Owner, GetName(result), result);
|
|
Parse_FormalParameterList(result);
|
|
Match(';');
|
|
|
|
DirectiveList := Parse_DirectiveList(result);
|
|
if (DirectiveList.IndexOf(dirVIRTUAL) >= 0) or
|
|
(DirectiveList.IndexOf(dirDYNAMIC) >= 0) or
|
|
(DirectiveList.IndexOf(dirOVERRIDE) >= 0) then
|
|
begin
|
|
CreateError(errE2379, []);
|
|
// Virtual methods not allowed in record types.
|
|
end;
|
|
|
|
FreeAndNil(DirectiveList);
|
|
SetForward(result, true);
|
|
|
|
if IsCurrText('external') then
|
|
begin
|
|
ParseExternalSub(result);
|
|
SetForward(result, false);
|
|
Exit;
|
|
end;
|
|
|
|
if IsExternalUnit then
|
|
begin
|
|
GenExternalSub(result);
|
|
Exit;
|
|
end;
|
|
|
|
EndSub(result);
|
|
if Assigned(OnParseEndSubDeclaration) then
|
|
begin
|
|
Declaration := ExtractText(SavedPosition, PrevPosition + PrevLength - 1);
|
|
if IsSharedMethod then
|
|
Declaration := 'class ' + Declaration;
|
|
OnParseEndSubDeclaration(Owner, GetName(result), result, Declaration);
|
|
end;
|
|
end;
|
|
|
|
function TPascalParser.Parse_RecordDestructorHeading(IsSharedMethod: Boolean;
|
|
RecordTypeId: Integer;
|
|
Vis: TClassVisibility;
|
|
IsExternalUnit: Boolean): Integer;
|
|
var
|
|
NP: Integer;
|
|
DirectiveList: TIntegerList;
|
|
Declaration: String;
|
|
SavedPosition: Integer;
|
|
begin
|
|
SavedPosition := CurrToken.Position;
|
|
DECLARE_SWITCH := true;
|
|
Match('destructor');
|
|
result := Parse_Ident;
|
|
Gen(OP_DECLARE_MEMBER, CurrLevel, result, 0);
|
|
SetVisibility(result, vis);
|
|
BeginStructureDestructor(result, RecordTypeId);
|
|
if Assigned(OnParseBeginSubDeclaration) then
|
|
OnParseBeginSubDeclaration(Owner, GetName(result), result);
|
|
NP := 0;
|
|
if IsCurrText('(') then
|
|
begin
|
|
Call_SCANNER;
|
|
Match(')');
|
|
end;
|
|
SetCount(result, NP);
|
|
Match(';');
|
|
|
|
DirectiveList := Parse_DirectiveList(result);
|
|
if (DirectiveList.IndexOf(dirVIRTUAL) >= 0) or
|
|
(DirectiveList.IndexOf(dirDYNAMIC) >= 0) or
|
|
(DirectiveList.IndexOf(dirOVERRIDE) >= 0) then
|
|
begin
|
|
CreateError(errE2379, []);
|
|
// Virtual methods not allowed in record types.
|
|
end;
|
|
FreeAndNil(DirectiveList);
|
|
SetForward(result, true);
|
|
|
|
if IsCurrText('external') then
|
|
begin
|
|
ParseExternalSub(result);
|
|
SetForward(result, false);
|
|
Exit;
|
|
end;
|
|
|
|
if IsExternalUnit then
|
|
begin
|
|
GenExternalSub(result);
|
|
Exit;
|
|
end;
|
|
|
|
EndSub(result);
|
|
if Assigned(OnParseEndSubDeclaration) then
|
|
begin
|
|
Declaration := ExtractText(SavedPosition, PrevPosition + PrevLength - 1);
|
|
if IsSharedMethod then
|
|
Declaration := 'class ' + Declaration;
|
|
OnParseEndSubDeclaration(Owner, GetName(result), result, Declaration);
|
|
end;
|
|
end;
|
|
|
|
function TPascalParser.Parse_RecordProcedureHeading(IsSharedMethod: Boolean;
|
|
RecordTypeId: Integer;
|
|
Vis: TClassVisibility;
|
|
IsExternalUnit: Boolean): Integer;
|
|
var
|
|
DirectiveList: TIntegerList;
|
|
Declaration: String;
|
|
SavedPosition: Integer;
|
|
begin
|
|
SavedPosition := CurrToken.Position;
|
|
DECLARE_SWITCH := true;
|
|
Match('procedure');
|
|
result := Parse_Ident;
|
|
Gen(OP_DECLARE_MEMBER, CurrLevel, result, 0);
|
|
|
|
if IsCurrText('.') then
|
|
begin
|
|
Scanner.CurrComment.AllowedDoComment := false;
|
|
Match('.');
|
|
Parse_Ident;
|
|
DECLARE_SWITCH := false;
|
|
Match('=');
|
|
Parse_Ident;
|
|
Match(';');
|
|
Exit;
|
|
end;
|
|
|
|
SetVisibility(result, vis);
|
|
BeginStructureMethod(result, RecordTypeId, false, IsSharedMethod);
|
|
if Assigned(OnParseBeginSubDeclaration) then
|
|
OnParseBeginSubDeclaration(Owner, GetName(result), result);
|
|
Parse_FormalParameterList(result);
|
|
Match(';');
|
|
|
|
DirectiveList := Parse_DirectiveList(result);
|
|
|
|
if DirectiveList.IndexOf(dirABSTRACT) >= 0 then
|
|
begin
|
|
inherited InitSub(result);
|
|
Gen(OP_ERR_ABSTRACT, NewConst(typeSTRING,
|
|
GetName(RecordTypeId) + '.' + GetName(result)), 0, result);
|
|
end
|
|
else if (DirectiveList.IndexOf(dirVIRTUAL) >= 0) or
|
|
(DirectiveList.IndexOf(dirDYNAMIC) >= 0) or
|
|
(DirectiveList.IndexOf(dirOVERRIDE) >= 0) then
|
|
begin
|
|
CreateError(errE2379, []);
|
|
// Virtual methods not allowed in record types.
|
|
end
|
|
else if IsSharedMethod and (DirectiveList.IndexOf(dirSTATIC) = -1) then
|
|
begin
|
|
CreateError(errE2398, []);
|
|
// Class methods in record types must be static.
|
|
end
|
|
else
|
|
SetForward(result, true);
|
|
FreeAndNil(DirectiveList);
|
|
|
|
if IsCurrText('external') then
|
|
begin
|
|
ParseExternalSub(result);
|
|
SetForward(result, false);
|
|
Exit;
|
|
end;
|
|
|
|
if IsExternalUnit then
|
|
begin
|
|
GenExternalSub(result);
|
|
Exit;
|
|
end;
|
|
|
|
EndSub(result);
|
|
if Assigned(OnParseEndSubDeclaration) then
|
|
begin
|
|
Declaration := ExtractText(SavedPosition, PrevPosition + PrevLength - 1);
|
|
if IsSharedMethod then
|
|
Declaration := 'class ' + Declaration;
|
|
OnParseEndSubDeclaration(Owner, GetName(result), result, Declaration);
|
|
end;
|
|
end;
|
|
|
|
function TPascalParser.Parse_RecordFunctionHeading(IsSharedMethod: Boolean;
|
|
RecordTypeId: Integer;
|
|
Vis: TClassVisibility;
|
|
IsExternalUnit: Boolean): Integer;
|
|
var
|
|
TypeID: Integer;
|
|
DirectiveList: TIntegerList;
|
|
Declaration: String;
|
|
SavedPosition: Integer;
|
|
begin
|
|
SavedPosition := CurrToken.Position;
|
|
DECLARE_SWITCH := true;
|
|
Match('function');
|
|
result := Parse_Ident;
|
|
Gen(OP_DECLARE_MEMBER, CurrLevel, result, 0);
|
|
|
|
if IsCurrText('.') then
|
|
begin
|
|
Scanner.CurrComment.AllowedDoComment := false;
|
|
Match('.');
|
|
Parse_Ident;
|
|
DECLARE_SWITCH := false;
|
|
Match('=');
|
|
Parse_Ident;
|
|
Match(';');
|
|
Exit;
|
|
end;
|
|
|
|
SetVisibility(result, vis);
|
|
BeginStructureMethod(result, RecordTypeId, true, IsSharedMethod);
|
|
if Assigned(OnParseBeginSubDeclaration) then
|
|
OnParseBeginSubDeclaration(Owner, GetName(result), result);
|
|
Parse_FormalParameterList(result);
|
|
|
|
DECLARE_SWITCH := false;
|
|
Match(':');
|
|
Parse_Attribute;
|
|
TypeID := Parse_Type;
|
|
Gen(OP_ASSIGN_TYPE, result, TypeID, 0);
|
|
Gen(OP_ASSIGN_TYPE, CurrResultId, TypeID, 0);
|
|
if Assigned(OnParseResultType) then
|
|
OnParseResultType(Owner, GetName(TypeId), TypeId);
|
|
|
|
DECLARE_SWITCH := true;
|
|
Match(';');
|
|
|
|
DirectiveList := Parse_DirectiveList(result);
|
|
if DirectiveList.IndexOf(dirABSTRACT) >= 0 then
|
|
begin
|
|
inherited InitSub(result);
|
|
Gen(OP_ERR_ABSTRACT, NewConst(typeSTRING,
|
|
GetName(RecordTypeId) + '.' + GetName(result)), 0, result);
|
|
end
|
|
else if (DirectiveList.IndexOf(dirVIRTUAL) >= 0) or
|
|
(DirectiveList.IndexOf(dirDYNAMIC) >= 0) or
|
|
(DirectiveList.IndexOf(dirOVERRIDE) >= 0) then
|
|
begin
|
|
CreateError(errE2379, []);
|
|
// Virtual methods not allowed in record types.
|
|
end
|
|
else if IsSharedMethod and (DirectiveList.IndexOf(dirSTATIC) = -1) then
|
|
begin
|
|
CreateError(errE2398, []);
|
|
// Class methods in record types must be static.
|
|
end
|
|
else
|
|
SetForward(result, true);
|
|
|
|
FreeAndNil(DirectiveList);
|
|
|
|
if IsCurrText('external') then
|
|
begin
|
|
ParseExternalSub(result);
|
|
SetForward(result, false);
|
|
Exit;
|
|
end;
|
|
|
|
if IsExternalUnit then
|
|
begin
|
|
GenExternalSub(result);
|
|
Exit;
|
|
end;
|
|
|
|
EndSub(result);
|
|
if Assigned(OnParseEndSubDeclaration) then
|
|
begin
|
|
Declaration := ExtractText(SavedPosition, PrevPosition + PrevLength - 1);
|
|
if IsSharedMethod then
|
|
Declaration := 'class ' + Declaration;
|
|
OnParseEndSubDeclaration(Owner, GetName(result), result, Declaration);
|
|
end;
|
|
end;
|
|
|
|
function TPascalParser.Parse_RecordOperatorHeading(RecordTypeId: Integer;
|
|
Vis: TClassVisibility;
|
|
IsExternalUnit: Boolean): Integer;
|
|
var
|
|
I, TypeID: Integer;
|
|
DirectiveList: TIntegerList;
|
|
Declaration: String;
|
|
SavedPosition: Integer;
|
|
begin
|
|
SavedPosition := CurrToken.Position;
|
|
DECLARE_SWITCH := true;
|
|
RemoveLastIdent(CurrToken.Id);
|
|
Match('operator');
|
|
I := OperatorIndex(CurrToken.Text);
|
|
if I = -1 then
|
|
CreateError(errE2393, []);
|
|
// errE2393 = 'Invalid operator declaration';
|
|
result := Parse_Ident;
|
|
SetName(result, operators.Values[I]);
|
|
Gen(OP_DECLARE_MEMBER, CurrLevel, result, 0);
|
|
|
|
SetVisibility(result, vis);
|
|
BeginStructureOperator(result, RecordTypeId);
|
|
if Assigned(OnParseBeginSubDeclaration) then
|
|
OnParseBeginSubDeclaration(Owner, GetName(result), result);
|
|
Parse_FormalParameterList(result);
|
|
|
|
DECLARE_SWITCH := false;
|
|
Match(':');
|
|
Parse_Attribute;
|
|
TypeID := Parse_Type;
|
|
Gen(OP_ASSIGN_TYPE, result, TypeID, 0);
|
|
Gen(OP_ASSIGN_TYPE, CurrResultId, TypeID, 0);
|
|
if Assigned(OnParseResultType) then
|
|
OnParseResultType(Owner, GetName(TypeId), TypeId);
|
|
|
|
DECLARE_SWITCH := true;
|
|
Match(';');
|
|
DirectiveList := Parse_DirectiveList(result);
|
|
FreeAndNil(DirectiveList);
|
|
|
|
SetForward(result, true);
|
|
SetOverloaded(result);
|
|
|
|
if IsCurrText('external') then
|
|
begin
|
|
ParseExternalSub(result);
|
|
SetForward(result, false);
|
|
Exit;
|
|
end;
|
|
|
|
if IsExternalUnit then
|
|
begin
|
|
GenExternalSub(result);
|
|
Exit;
|
|
end;
|
|
|
|
EndSub(result);
|
|
if Assigned(OnParseEndSubDeclaration) then
|
|
begin
|
|
Declaration := 'class ' + ExtractText(SavedPosition, PrevPosition + PrevLength - 1);
|
|
OnParseEndSubDeclaration(Owner, GetName(result), result, Declaration);
|
|
end;
|
|
end;
|
|
|
|
function TPascalParser.Parse_RecordProperty(RecordTypeId: Integer;
|
|
Vis: TClassVisibility;
|
|
IsExternalUnit: Boolean): Integer;
|
|
var
|
|
TypeID, ReadId, WriteId, ImplementsId: Integer;
|
|
Declaration: String;
|
|
SavedPosition: Integer;
|
|
begin
|
|
DECLARE_SWITCH := true;
|
|
SavedPosition := CurrToken.Position;
|
|
Match('property');
|
|
result := Parse_Ident;
|
|
Gen(OP_DECLARE_MEMBER, CurrLevel, result, 0);
|
|
|
|
SetVisibility(result, vis);
|
|
BeginProperty(result, RecordTypeId);
|
|
ReadId := 0;
|
|
WriteId := 0;
|
|
TypeId := 0;
|
|
|
|
try
|
|
|
|
Parse_FormalParameterList(result, '[');
|
|
|
|
SetReadId(result, ReadId);
|
|
SetWriteId(result, WriteId);
|
|
|
|
if IsCurrText(';') then
|
|
begin
|
|
Match(';');
|
|
Gen(OP_DETERMINE_PROP, result, 0, 0);
|
|
EndProperty(result);
|
|
Exit;
|
|
end;
|
|
|
|
if IsCurrText(':') then
|
|
begin
|
|
DECLARE_SWITCH := false;
|
|
Match(':');
|
|
TypeID := Parse_QualId;
|
|
Gen(OP_ASSIGN_TYPE, result, TypeID, 0);
|
|
end;
|
|
|
|
repeat
|
|
DECLARE_SWITCH := false;
|
|
if IsCurrText('read') and (ReadId = 0) then
|
|
begin
|
|
RemoveLastIdent(CurrToken.Id);
|
|
Call_SCANNER;
|
|
ReadId := Parse_QualId;
|
|
ReadId := Lookup(GetName(ReadId), RecordTypeId);
|
|
if ReadId = 0 then
|
|
RaiseError(errUndeclaredIdentifier, [CurrToken.Text]);
|
|
SetReadId(result, ReadId);
|
|
end
|
|
else if IsCurrText('write') and (WriteId = 0) then
|
|
begin
|
|
RemoveLastIdent(CurrToken.Id);
|
|
Call_SCANNER;
|
|
WriteId := Parse_QualId;
|
|
WriteId := Lookup(GetName(WriteId), RecordTypeId);
|
|
if WriteId = 0 then
|
|
RaiseError(errUndeclaredIdentifier, [CurrToken.Text]);
|
|
SetWriteId(result, WriteId);
|
|
end
|
|
else if IsCurrText('implements') then
|
|
begin
|
|
RemoveLastIdent(CurrToken.Id);
|
|
DECLARE_SWITCH := false;
|
|
Call_SCANNER;
|
|
if not StrEql(GetName(result), CurrToken.Text) then
|
|
DiscardLastStRecord;
|
|
ImplementsId := Parse_Ident;
|
|
Gen(OP_IMPLEMENTS, result, ImplementsId, 0);
|
|
end
|
|
else if IsCurrText('stored') then
|
|
begin
|
|
DECLARE_SWITCH := false;
|
|
if not StrEql(GetName(result), CurrToken.Text) then
|
|
DiscardLastStRecord;
|
|
Call_SCANNER;
|
|
Parse_Expression;
|
|
end
|
|
else if IsCurrText('index') then
|
|
begin
|
|
DECLARE_SWITCH := false;
|
|
if not StrEql(GetName(result), CurrToken.Text) then
|
|
DiscardLastStRecord;
|
|
Call_SCANNER;
|
|
Parse_Expression;
|
|
end
|
|
else if IsCurrText('default') then
|
|
begin
|
|
if not StrEql(GetName(result), CurrToken.Text) then
|
|
DiscardLastStRecord;
|
|
Call_SCANNER;
|
|
if IsCurrText(';') then
|
|
SetDefault(result, true)
|
|
else
|
|
Parse_Expression;
|
|
end
|
|
else if IsCurrText('nodefault') then
|
|
begin
|
|
if not StrEql(GetName(result), CurrToken.Text) then
|
|
DiscardLastStRecord;
|
|
Call_SCANNER;
|
|
end
|
|
else
|
|
break;
|
|
until false;
|
|
|
|
if IsNextText('default') then
|
|
begin
|
|
Call_SCANNER;
|
|
Match('default');
|
|
SetDefault(result, true);
|
|
end;
|
|
|
|
if ReadId + WriteId = 0 then
|
|
RaiseError(errSyntaxError, []);
|
|
|
|
if ReadId > 0 then
|
|
TKernel(kernel).Code.used_private_members.Add(ReadId);
|
|
if WriteId > 0 then
|
|
TKernel(kernel).Code.used_private_members.Add(WriteId);
|
|
|
|
Match(';');
|
|
EndProperty(result);
|
|
finally
|
|
if Assigned(OnParsePropertyDeclaration) then
|
|
begin
|
|
Declaration := ExtractText(SavedPosition, PrevPosition + PrevLength - 1);
|
|
OnParsePropertyDeclaration(Owner, GetName(result), result,
|
|
GetName(TypeId), Declaration);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_RecordVariantPart(VarLevel: Integer;
|
|
CurrVarCnt: Int64;
|
|
vis: TClassVisibility);
|
|
var
|
|
id, I, TypeId: Integer;
|
|
V, VarCnt: Int64;
|
|
L: TIntegerList;
|
|
S, Declaration: String;
|
|
SavedPosition: Integer;
|
|
begin
|
|
|
|
L := TIntegerList.Create;
|
|
|
|
try
|
|
VarCnt := 0;
|
|
|
|
if IsNext2Text(':') then
|
|
begin
|
|
DECLARE_SWITCH := true;
|
|
Match('case');
|
|
DECLARE_SWITCH := false;
|
|
id := Parse_Ident;
|
|
Match(':');
|
|
TypeId := Parse_Ident;
|
|
SetKind(Id, KindTYPE_FIELD);
|
|
Gen(OP_ASSIGN_TYPE, id, TypeId, 0);
|
|
end
|
|
else
|
|
begin
|
|
DECLARE_SWITCH := false;
|
|
Match('case');
|
|
TypeId := Parse_Ident;
|
|
Gen(OP_EVAL, 0, 0, TypeId);
|
|
end;
|
|
|
|
DECLARE_SWITCH := false;
|
|
Match('of');
|
|
|
|
repeat
|
|
Inc(VarCnt);
|
|
|
|
if IsEOF then
|
|
Break;
|
|
if IsCurrText('end') then
|
|
Break;
|
|
if IsCurrText(')') then
|
|
begin
|
|
Break;
|
|
end;
|
|
|
|
// RecVariant
|
|
|
|
// ConstList
|
|
repeat
|
|
if IsEOF then
|
|
Break;
|
|
if IsCurrText('end') then
|
|
Break;
|
|
|
|
Parse_Expression;
|
|
|
|
if NotMatch(',') then
|
|
break;
|
|
until false;
|
|
|
|
Match(':');
|
|
|
|
// FieldList
|
|
DECLARE_SWITCH := true;
|
|
|
|
Match('(');
|
|
if not IsCurrText(')') then
|
|
begin
|
|
if IsCurrText('case') then
|
|
begin
|
|
case VarLevel of
|
|
1: V := VarCnt;
|
|
2: V := VarCnt * 100 + CurrVarCnt;
|
|
3: V := VarCnt * 10000 + CurrVarCnt;
|
|
4: V := VarCnt * 1000000 + CurrVarCnt;
|
|
5: V := VarCnt * 100000000 + CurrVarCnt;
|
|
6: V := VarCnt * 10000000000 + CurrVarCnt;
|
|
7: V := VarCnt * 1000000000000 + CurrVarCnt;
|
|
else
|
|
begin
|
|
V := 0;
|
|
RaiseError(errTooManyNestedCaseBlocks, []);
|
|
end;
|
|
end;
|
|
|
|
Parse_RecordVariantPart(VarLevel + 1, V, vis);
|
|
end
|
|
else
|
|
begin
|
|
|
|
repeat
|
|
|
|
L.Clear;
|
|
repeat // parse ident list
|
|
L.Add(Parse_Ident);
|
|
if NotMatch(',') then
|
|
break;
|
|
until false;
|
|
|
|
DECLARE_SWITCH := false;
|
|
Match(':');
|
|
|
|
SavedPosition := CurrToken.Position;
|
|
TypeID := Parse_Type;
|
|
S := ExtractText(SavedPosition, PrevPosition + PrevLength - 1);
|
|
|
|
case VarLevel of
|
|
1: V := VarCnt;
|
|
2: V := VarCnt * 100 + CurrVarCnt;
|
|
3: V := VarCnt * 10000 + CurrVarCnt;
|
|
4: V := VarCnt * 1000000 + CurrVarCnt;
|
|
5: V := VarCnt * 100000000 + CurrVarCnt;
|
|
6: V := VarCnt * 10000000000 + CurrVarCnt;
|
|
7: V := VarCnt * 1000000000000 + CurrVarCnt;
|
|
else
|
|
begin
|
|
V := 0;
|
|
RaiseError(errTooManyNestedCaseBlocks, []);
|
|
end;
|
|
end;
|
|
|
|
for I:=0 to L.Count - 1 do
|
|
begin
|
|
SetKind(L[I], KindTYPE_FIELD);
|
|
SetVarCount(L[I], V);
|
|
SetVisibility(L[I], vis);
|
|
Gen(OP_ASSIGN_TYPE, L[I], TypeID, 0);
|
|
|
|
if Assigned(OnParseVariantRecordFieldDeclaration) then
|
|
begin
|
|
Declaration := GetName(L[I]) + ' = ' + S + ';';
|
|
OnParseVariantRecordFieldDeclaration(Owner, GetName(L[I]), L[I],
|
|
GetName(TypeId), V, Declaration);
|
|
end;
|
|
end;
|
|
|
|
if IsCurrText(';') then
|
|
begin
|
|
DECLARE_SWITCH := true;
|
|
Match(';');
|
|
|
|
if IsCurrText(')') then
|
|
break;
|
|
|
|
if IsCurrText('case') then
|
|
begin
|
|
Parse_RecordVariantPart(VarLevel + 1, V, vis);
|
|
break;
|
|
end;
|
|
|
|
end
|
|
else
|
|
break;
|
|
|
|
until false;
|
|
end;
|
|
|
|
DECLARE_SWITCH := true;
|
|
end;
|
|
|
|
DECLARE_SWITCH := false;
|
|
|
|
Match(')');
|
|
if IsCurrText(';') then
|
|
Match(';');
|
|
|
|
until false;
|
|
finally
|
|
FreeAndNil(L);
|
|
end;
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_RecordHelperItem;
|
|
begin
|
|
if IsCurrText('const') then
|
|
Parse_ConstantDeclaration;
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_RecordTypeDeclaration(RecordTypeID: Integer; IsPacked: Boolean;
|
|
IsExternalUnit: Boolean = false);
|
|
var
|
|
vis: TClassVisibility;
|
|
|
|
var
|
|
L: TIntegerList;
|
|
I, TypeID, Id, TrueRecordId: Integer;
|
|
b: Boolean;
|
|
Declaration: String;
|
|
SavedPosition: Integer;
|
|
begin
|
|
SavedPosition := CurrToken.Position;
|
|
|
|
TrueRecordId := 0;
|
|
vis := cvPublic;
|
|
|
|
if IsNextText('helper') then
|
|
begin
|
|
Match('record');
|
|
DECLARE_SWITCH := false;
|
|
RemoveLastIdent(CurrToken.Id);
|
|
Match('helper');
|
|
Match('for');
|
|
TrueRecordId := Parse_QualId;
|
|
BeginHelperType(RecordTypeId, TrueRecordId);
|
|
|
|
if Assigned(OnParseBeginRecordHelperTypeDeclaration) then
|
|
begin
|
|
Declaration := ExtractText(SavedPosition, PrevPosition + PrevLength - 1);
|
|
Declaration := GetName(RecordTypeId) + ' = ' + Declaration;
|
|
if Assigned(OnParseBeginClassHelperTypeDeclaration) then
|
|
begin
|
|
OnParseBeginRecordHelperTypeDeclaration(Owner, GetName(RecordTypeId), RecordTypeId,
|
|
GetName(TrueRecordId),
|
|
Declaration);
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
BeginRecordType(RecordTypeID);
|
|
if IsPacked then
|
|
SetPacked(RecordTypeID);
|
|
Match('record');
|
|
|
|
if Assigned(OnParseBeginRecordTypeDeclaration) then
|
|
begin
|
|
Declaration := ExtractText(SavedPosition, PrevPosition + PrevLength - 1);
|
|
Declaration := GetName(RecordTypeId) + ' = ' + Declaration;
|
|
OnParseBeginRecordTypeDeclaration(Owner, GetName(RecordTypeId), RecordTypeId, Declaration);
|
|
end;
|
|
end;
|
|
|
|
b := false;
|
|
L := TIntegerList.Create;
|
|
try
|
|
repeat
|
|
if IsEOF then
|
|
Break;
|
|
|
|
if IsCurrText('end') then
|
|
Break;
|
|
|
|
if IsCurrText('case') then
|
|
|
|
begin
|
|
Parse_RecordVariantPart(1, 0, vis);
|
|
break;
|
|
end
|
|
else
|
|
begin
|
|
repeat
|
|
if IsCurrText('strict') then
|
|
begin
|
|
RemoveLastIdent(CurrToken.Id);
|
|
Call_SCANNER;
|
|
if IsCurrText('protected') then
|
|
begin
|
|
Call_SCANNER;
|
|
vis := cvStrictProtected;
|
|
end
|
|
else
|
|
begin
|
|
Match('private');
|
|
vis := cvStrictPrivate;
|
|
end;
|
|
b := false;
|
|
end
|
|
else if IsCurrText('private') then
|
|
begin
|
|
Call_SCANNER;
|
|
vis := cvPrivate;
|
|
b := false;
|
|
end
|
|
else if IsCurrText('protected') then
|
|
begin
|
|
Call_SCANNER;
|
|
vis := cvProtected;
|
|
b := false;
|
|
end
|
|
else if IsCurrText('public') then
|
|
begin
|
|
Call_SCANNER;
|
|
vis := cvPublic;
|
|
b := false;
|
|
end
|
|
else if IsCurrText('published') then
|
|
begin
|
|
Call_SCANNER;
|
|
vis := cvPublished;
|
|
b := false;
|
|
end
|
|
else
|
|
break;
|
|
until false;
|
|
|
|
if IsCurrText('end') then
|
|
Break;
|
|
Parse_Attribute;
|
|
|
|
if IsCurrText('case') then
|
|
begin
|
|
Parse_RecordVariantPart(1, 0, vis);
|
|
break;
|
|
end
|
|
else if IsCurrText('constructor') then
|
|
begin
|
|
Parse_RecordConstructorHeading(false, RecordTypeId, vis, IsExternalUnit);
|
|
b := true;
|
|
end
|
|
else if IsCurrText('destructor') then
|
|
begin
|
|
Parse_RecordDestructorHeading(false, RecordTypeId, vis, IsExternalUnit);
|
|
b := true;
|
|
end
|
|
else if IsCurrText('procedure') then
|
|
begin
|
|
Parse_RecordProcedureHeading(false, RecordTypeId, vis, IsExternalUnit);
|
|
b := true;
|
|
end
|
|
else if IsCurrText('function') then
|
|
begin
|
|
Parse_RecordFunctionHeading(false, RecordTypeId, vis, IsExternalUnit);
|
|
b := true;
|
|
end
|
|
else if IsCurrText('var') or IsCurrText('threadvar') then
|
|
begin
|
|
if IsCurrText('threadvar') then
|
|
Call_SCANNER
|
|
else
|
|
Match('var');
|
|
|
|
repeat
|
|
Parse_Attribute;
|
|
|
|
L.Clear;
|
|
repeat // parse ident list
|
|
Id := Parse_Ident;
|
|
Gen(OP_DECLARE_MEMBER, CurrLevel, Id, 0);
|
|
L.Add(Id);
|
|
if NotMatch(',') then
|
|
break;
|
|
until false;
|
|
|
|
DECLARE_SWITCH := false;
|
|
Match(':');
|
|
|
|
TypeID := Parse_Type;
|
|
|
|
for I:=0 to L.Count - 1 do
|
|
begin
|
|
SetKind(L[I], KindTYPE_FIELD);
|
|
SetVisibility(L[I], vis);
|
|
Gen(OP_ASSIGN_TYPE, L[I], TypeID, 0);
|
|
end;
|
|
|
|
DECLARE_SWITCH := true;
|
|
|
|
Parse_PortabilityDirective;
|
|
|
|
if IsCurrText(';') then
|
|
Match(';');
|
|
|
|
if CurrToken.TokenClass <> tcIdentifier then
|
|
if not IsCurrText('[') then
|
|
break;
|
|
until false;
|
|
end
|
|
else if IsCurrText('class') then
|
|
begin
|
|
b := true;
|
|
Call_SCANNER;
|
|
if IsCurrText('constructor') then
|
|
Parse_RecordConstructorHeading(true, RecordTypeId, vis, IsExternalUnit)
|
|
else if IsCurrText('destructor') then
|
|
Parse_RecordDestructorHeading(true, RecordTypeId, vis, IsExternalUnit)
|
|
else if IsCurrText('procedure') then
|
|
Parse_RecordProcedureHeading(true, RecordTypeId, vis, IsExternalUnit)
|
|
else if IsCurrText('function') then
|
|
Parse_RecordFunctionHeading(true, RecordTypeId, vis, IsExternalUnit)
|
|
else if IsCurrText('operator') then
|
|
Parse_RecordOperatorHeading(RecordTypeId, vis, IsExternalUnit)
|
|
else if IsCurrText('property') then
|
|
Parse_RecordProperty(RecordTypeId, vis, IsExternalUnit)
|
|
else if IsCurrText('var') or IsCurrText('threadvar') then
|
|
Parse_VariableDeclaration(vis);
|
|
end
|
|
else if IsCurrText('property') then
|
|
begin
|
|
Parse_RecordProperty(RecordTypeId, vis, IsExternalUnit);
|
|
b := true;
|
|
end
|
|
else if IsCurrText('type') then
|
|
begin
|
|
Parse_TypeDeclaration(false, vis);
|
|
b := true;
|
|
end
|
|
else if IsCurrText('const') then
|
|
begin
|
|
Parse_ConstantDeclaration(vis);
|
|
b := true;
|
|
end
|
|
else
|
|
begin
|
|
if IsCurrText('threadvar') then
|
|
Call_SCANNER
|
|
else if IsCurrText('var') then
|
|
Call_SCANNER;
|
|
|
|
if b then
|
|
CreateError(errFieldDefinitionNotAllowedAfter, []);
|
|
|
|
L.Clear;
|
|
repeat // parse ident list
|
|
Id := Parse_Ident;
|
|
SetVisibility(Id, Vis);
|
|
Gen(OP_DECLARE_MEMBER, CurrLevel, Id, 0);
|
|
L.Add(Id);
|
|
if NotMatch(',') then
|
|
break;
|
|
until false;
|
|
|
|
DECLARE_SWITCH := false;
|
|
Match(':');
|
|
|
|
SavedPosition := CurrToken.Position;
|
|
|
|
TypeID := Parse_Type;
|
|
|
|
for I:=0 to L.Count - 1 do
|
|
begin
|
|
SetKind(L[I], KindTYPE_FIELD);
|
|
Gen(OP_ASSIGN_TYPE, L[I], TypeID, 0);
|
|
|
|
if Assigned(OnParseFieldDeclaration) then
|
|
begin
|
|
Declaration := GetName(L[I]) + ':' +
|
|
ExtractText(SavedPosition, PrevPosition + PrevLength - 1);
|
|
OnParseFieldDeclaration(Owner, GetName(L[I]), L[I], GetName(TypeId),
|
|
Declaration);
|
|
end;
|
|
end;
|
|
|
|
DECLARE_SWITCH := true;
|
|
|
|
Parse_PortabilityDirective;
|
|
|
|
if IsCurrText(';') then
|
|
Match(';');
|
|
end;
|
|
|
|
if IsCurrText('case') then
|
|
begin
|
|
Parse_RecordVariantPart(1, 0, vis);
|
|
break;
|
|
end;
|
|
end;
|
|
|
|
until false;
|
|
finally
|
|
FreeAndNil(L);
|
|
end;
|
|
|
|
if TrueRecordId > 0 then
|
|
begin
|
|
EndHelperType(RecordTypeId);
|
|
if Assigned(OnParseEndRecordHelperTypeDeclaration) then
|
|
OnParseEndRecordHelperTypeDeclaration(Owner, GetName(RecordTypeId), RecordTypeId);
|
|
end
|
|
else
|
|
begin
|
|
EndRecordType(RecordTypeId);
|
|
if Assigned(OnParseEndRecordTypeDeclaration) then
|
|
OnParseEndRecordTypeDeclaration(Owner, GetName(RecordTypeId), RecordTypeId);
|
|
end;
|
|
|
|
Match('end');
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_Message(SubId: Integer);
|
|
begin
|
|
DECLARE_SWITCH := false;
|
|
Call_SCANNER;
|
|
if CurrToken.TokenClass = tcIntegerConst then
|
|
begin
|
|
Gen(OP_ADD_MESSAGE, SubId, CurrToken.Id, 0);
|
|
end
|
|
else if CurrToken.TokenClass = tcIdentifier then
|
|
begin
|
|
Gen(OP_ADD_MESSAGE, SubId, CurrToken.Id, 0);
|
|
end
|
|
else
|
|
begin
|
|
RaiseError(errIncompatibleTypesNoArgs, []);
|
|
end;
|
|
ReadToken;
|
|
end;
|
|
|
|
function TPascalParser.Parse_ClassConstructorHeading(IsSharedMethod: Boolean;
|
|
ClassTypeId: Integer;
|
|
vis: TClassVisibility;
|
|
IsExternalUnit: Boolean): Integer;
|
|
var
|
|
DirectiveList: TIntegerList;
|
|
Declaration: String;
|
|
SavedPosition: Integer;
|
|
begin
|
|
SavedPosition := CurrToken.Position;
|
|
DECLARE_SWITCH := true;
|
|
Match('constructor');
|
|
result := Parse_Ident;
|
|
Gen(OP_DECLARE_MEMBER, CurrLevel, result, 0);
|
|
SetVisibility(result, vis);
|
|
BeginClassConstructor(result, ClassTypeId);
|
|
if Assigned(OnParseBeginSubDeclaration) then
|
|
OnParseBeginSubDeclaration(Owner, GetName(result), result);
|
|
|
|
GetSymbolRec(result).IsSharedMethod := IsSharedMethod;
|
|
|
|
Parse_FormalParameterList(result);
|
|
Match(';');
|
|
CheckRedeclaredSub(result);
|
|
|
|
DirectiveList := Parse_DirectiveList(result);
|
|
try
|
|
if not ImportOnly then
|
|
if CountAtLevel(GetName(result), GetLevel(result), KindCONSTRUCTOR, IsSharedMethod) > 1 then
|
|
if DirectiveList.IndexOf(dirOVERLOAD) = -1 then
|
|
CreateError(errOverloadExpected, [GetName(result)]);
|
|
|
|
if (DirectiveList.IndexOf(dirSTATIC) >= 0) and
|
|
(
|
|
(DirectiveList.IndexOf(dirVIRTUAL) >= 0) or
|
|
(DirectiveList.IndexOf(dirDYNAMIC) >= 0) or
|
|
(DirectiveList.IndexOf(dirOVERRIDE) >= 0)
|
|
) then
|
|
begin
|
|
CreateError(errE2376, []);
|
|
//STATIC can only be used on non-virtual class methods.
|
|
end;
|
|
|
|
finally
|
|
FreeAndNil(DirectiveList);
|
|
end;
|
|
SetForward(result, true);
|
|
|
|
if IsCurrText('external') then
|
|
begin
|
|
ParseExternalSub(result);
|
|
SetForward(result, false);
|
|
Exit;
|
|
end;
|
|
|
|
if IsExternalUnit then
|
|
begin
|
|
GenExternalSub(result);
|
|
Exit;
|
|
end;
|
|
|
|
EndSub(result);
|
|
if Assigned(OnParseEndSubDeclaration) then
|
|
begin
|
|
Declaration := ExtractText(SavedPosition, PrevPosition + PrevLength - 1);
|
|
if IsSharedMethod then
|
|
Declaration := 'class ' + Declaration;
|
|
OnParseEndSubDeclaration(Owner, GetName(result), result, Declaration);
|
|
end;
|
|
end;
|
|
|
|
function TPascalParser.Parse_ClassDestructorHeading(IsSharedMethod: Boolean;
|
|
ClassTypeId: Integer;
|
|
vis: TClassVisibility;
|
|
IsExternalUnit: Boolean): Integer;
|
|
var
|
|
NP: Integer;
|
|
DirectiveList: TIntegerList;
|
|
Declaration: String;
|
|
SavedPosition: Integer;
|
|
begin
|
|
SavedPosition := CurrToken.Position;
|
|
DECLARE_SWITCH := true;
|
|
Match('destructor');
|
|
result := Parse_Ident;
|
|
Gen(OP_DECLARE_MEMBER, CurrLevel, result, 0);
|
|
SetVisibility(result, vis);
|
|
BeginClassDestructor(result, ClassTypeId);
|
|
if Assigned(OnParseBeginSubDeclaration) then
|
|
OnParseBeginSubDeclaration(Owner, GetName(result), result);
|
|
|
|
GetSymbolRec(result).IsSharedMethod := IsSharedMethod;
|
|
|
|
NP := 0;
|
|
if IsCurrText('(') then
|
|
begin
|
|
Call_SCANNER;
|
|
Match(')');
|
|
end;
|
|
SetCount(result, NP);
|
|
Match(';');
|
|
CheckRedeclaredSub(result);
|
|
|
|
DirectiveList := Parse_DirectiveList(result);
|
|
try
|
|
if not ImportOnly then
|
|
begin
|
|
if not IsSharedMethod then
|
|
if DirectiveList.IndexOf(dirOVERRIDE) = -1 then
|
|
Match('override');
|
|
if CountAtLevel(GetName(result), GetLevel(result), KindDESTRUCTOR, IsSharedMethod) > 1 then
|
|
if DirectiveList.IndexOf(dirOVERLOAD) = -1 then
|
|
CreateError(errOverloadExpected, [GetName(result)]);
|
|
end;
|
|
finally
|
|
FreeAndNil(DirectiveList);
|
|
end;
|
|
|
|
SetForward(result, true);
|
|
|
|
if IsCurrText('external') then
|
|
begin
|
|
ParseExternalSub(result);
|
|
SetForward(result, false);
|
|
Exit;
|
|
end;
|
|
|
|
if IsExternalUnit then
|
|
begin
|
|
GenExternalSub(result);
|
|
Exit;
|
|
end;
|
|
|
|
EndSub(result);
|
|
if Assigned(OnParseEndSubDeclaration) then
|
|
begin
|
|
Declaration := ExtractText(SavedPosition, PrevPosition + PrevLength - 1);
|
|
if IsSharedMethod then
|
|
Declaration := 'class ' + Declaration;
|
|
OnParseEndSubDeclaration(Owner, GetName(result), result, Declaration);
|
|
end;
|
|
end;
|
|
|
|
function TPascalParser.Parse_ClassProcedureHeading(IsSharedMethod: Boolean;
|
|
ClassTypeId: Integer;
|
|
vis: TClassVisibility;
|
|
IsExternalUnit: Boolean): Integer;
|
|
var
|
|
DirectiveList: TIntegerList;
|
|
Declaration: String;
|
|
SavedPosition: Integer;
|
|
begin
|
|
SavedPosition := CurrToken.Position;
|
|
DECLARE_SWITCH := true;
|
|
BeginTypeExt(ClassTypeId);
|
|
Match('procedure');
|
|
result := Parse_Ident;
|
|
Gen(OP_DECLARE_MEMBER, CurrLevel, result, 0);
|
|
|
|
if IsCurrText('.') then
|
|
begin
|
|
Scanner.CurrComment.AllowedDoComment := false;
|
|
Match('.');
|
|
Parse_Ident;
|
|
DECLARE_SWITCH := false;
|
|
Match('=');
|
|
Parse_Ident;
|
|
Match(';');
|
|
Exit;
|
|
end;
|
|
|
|
SetVisibility(result, vis);
|
|
BeginClassMethod(result, ClassTypeId, false, IsSharedMethod, false);
|
|
if Assigned(OnParseBeginSubDeclaration) then
|
|
OnParseBeginSubDeclaration(Owner, GetName(result), result);
|
|
Parse_FormalParameterList(result);
|
|
EndTypeExt(ClassTypeId);
|
|
Match(';');
|
|
|
|
CheckRedeclaredSub(result);
|
|
|
|
if IsCurrText('message') then
|
|
Parse_Message(result);
|
|
|
|
DirectiveList := Parse_DirectiveList(result);
|
|
try
|
|
if DirectiveList.IndexOf(dirABSTRACT) >= 0 then
|
|
begin
|
|
inherited InitSub(result);
|
|
Gen(OP_ERR_ABSTRACT, NewConst(typeSTRING,
|
|
GetName(ClassTypeId) + '.' + GetName(result)), 0, result);
|
|
end
|
|
else if (DirectiveList.IndexOf(dirSTATIC) >= 0) and
|
|
(
|
|
(IsSharedMethod = false) or
|
|
(DirectiveList.IndexOf(dirVIRTUAL) >= 0) or
|
|
(DirectiveList.IndexOf(dirDYNAMIC) >= 0) or
|
|
(DirectiveList.IndexOf(dirOVERRIDE) >= 0)
|
|
) then
|
|
begin
|
|
CreateError(errE2376, []);
|
|
//STATIC can only be used on non-virtual class methods.
|
|
end
|
|
else if DirectiveList.IndexOf(dirOVERRIDE) >= 0 then
|
|
begin
|
|
SetForward(result, true);
|
|
end
|
|
else
|
|
SetForward(result, true);
|
|
|
|
if CountAtLevel(GetName(result), GetLevel(result)) > 1 then
|
|
if DirectiveList.IndexOf(dirOVERLOAD) = -1 then
|
|
if not ImportOnly then
|
|
CreateError(errOverloadExpected, [GetName(result)]);
|
|
|
|
finally
|
|
FreeAndNil(DirectiveList);
|
|
end;
|
|
|
|
if IsCurrText('external') then
|
|
begin
|
|
ParseExternalSub(result);
|
|
SetForward(result, false);
|
|
Exit;
|
|
end;
|
|
|
|
if IsExternalUnit then
|
|
begin
|
|
GenExternalSub(result);
|
|
Exit;
|
|
end;
|
|
|
|
EndSub(result);
|
|
if Assigned(OnParseEndSubDeclaration) then
|
|
begin
|
|
Declaration := ExtractText(SavedPosition, PrevPosition + PrevLength - 1);
|
|
if IsSharedMethod then
|
|
Declaration := 'class ' + Declaration;
|
|
OnParseEndSubDeclaration(Owner, GetName(result), result, Declaration);
|
|
end;
|
|
end;
|
|
|
|
function TPascalParser.Parse_ClassFunctionHeading(IsSharedMethod: Boolean;
|
|
ClassTypeId: Integer;
|
|
vis: TClassVisibility;
|
|
IsExternalUnit: Boolean): Integer;
|
|
var
|
|
TypeID: Integer;
|
|
DirectiveList: TIntegerList;
|
|
Declaration: String;
|
|
SavedPosition: Integer;
|
|
begin
|
|
SavedPosition := CurrToken.Position;
|
|
DECLARE_SWITCH := true;
|
|
Match('function');
|
|
result := Parse_Ident;
|
|
Gen(OP_DECLARE_MEMBER, CurrLevel, result, 0);
|
|
|
|
if IsCurrText('.') then
|
|
begin
|
|
Scanner.CurrComment.AllowedDoComment := false;
|
|
Match('.');
|
|
Parse_Ident;
|
|
DECLARE_SWITCH := false;
|
|
Match('=');
|
|
Parse_Ident;
|
|
Match(';');
|
|
Exit;
|
|
end;
|
|
|
|
SetVisibility(result, vis);
|
|
BeginClassMethod(result, ClassTypeId, true, IsSharedMethod, false);
|
|
if Assigned(OnParseBeginSubDeclaration) then
|
|
OnParseBeginSubDeclaration(Owner, GetName(result), result);
|
|
Parse_FormalParameterList(result);
|
|
|
|
DECLARE_SWITCH := false;
|
|
Match(':');
|
|
Parse_Attribute;
|
|
TypeID := Parse_Type;
|
|
Gen(OP_ASSIGN_TYPE, result, TypeID, 0);
|
|
Gen(OP_ASSIGN_TYPE, CurrResultId, TypeID, 0);
|
|
if Assigned(OnParseResultType) then
|
|
OnParseResultType(Owner, GetName(TypeId), TypeId);
|
|
|
|
DECLARE_SWITCH := true;
|
|
Match(';');
|
|
CheckRedeclaredSub(result);
|
|
|
|
if IsCurrText('message') then
|
|
Parse_Message(result);
|
|
|
|
DirectiveList := Parse_DirectiveList(result);
|
|
try
|
|
|
|
if DirectiveList.IndexOf(dirABSTRACT) >= 0 then
|
|
begin
|
|
inherited InitSub(result);
|
|
Gen(OP_ERR_ABSTRACT, NewConst(typeSTRING,
|
|
GetName(ClassTypeId) + '.' + GetName(result)), 0, result);
|
|
end
|
|
else if (DirectiveList.IndexOf(dirSTATIC) >= 0) and
|
|
(
|
|
(IsSharedMethod = false) or
|
|
(DirectiveList.IndexOf(dirVIRTUAL) >= 0) or
|
|
(DirectiveList.IndexOf(dirDYNAMIC) >= 0) or
|
|
(DirectiveList.IndexOf(dirOVERRIDE) >= 0)
|
|
) then
|
|
begin
|
|
CreateError(errE2376, []);
|
|
//STATIC can only be used on non-virtual class methods.
|
|
end
|
|
else if DirectiveList.IndexOf(dirOVERRIDE) >= 0 then
|
|
begin
|
|
SetForward(result, true);
|
|
end
|
|
else
|
|
SetForward(result, true);
|
|
|
|
if CountAtLevel(GetName(result), GetLevel(result)) > 1 then
|
|
if DirectiveList.IndexOf(dirOVERLOAD) = -1 then
|
|
if not ImportOnly then
|
|
CreateError(errOverloadExpected, [GetName(result)]);
|
|
|
|
finally
|
|
FreeAndNil(DirectiveList);
|
|
end;
|
|
|
|
if IsCurrText('external') then
|
|
begin
|
|
ParseExternalSub(result);
|
|
SetForward(result, false);
|
|
Exit;
|
|
end;
|
|
|
|
if IsExternalUnit then
|
|
begin
|
|
GenExternalSub(result);
|
|
Exit;
|
|
end;
|
|
|
|
EndSub(result);
|
|
if Assigned(OnParseEndSubDeclaration) then
|
|
begin
|
|
Declaration := ExtractText(SavedPosition, PrevPosition + PrevLength - 1);
|
|
if IsSharedMethod then
|
|
Declaration := 'class ' + Declaration;
|
|
OnParseEndSubDeclaration(Owner, GetName(result), result, Declaration);
|
|
end;
|
|
end;
|
|
|
|
function TPascalParser.Parse_ClassProperty(IsShared: Boolean;
|
|
ClassTypeId: Integer;
|
|
vis: TClassVisibility;
|
|
IsExternalUnit: Boolean): Integer;
|
|
var
|
|
ReadId, WriteId, ImplementsId, TypeID, K: Integer;
|
|
StrType, StrDefault, Declaration: String;
|
|
SavedPosition: Integer;
|
|
begin
|
|
RemoveKeywords;
|
|
|
|
SavedPosition := CurrToken.Position;
|
|
ReadId := 0;
|
|
WriteId := 0;
|
|
|
|
DECLARE_SWITCH := true;
|
|
Match('property');
|
|
result := Parse_Ident;
|
|
|
|
StrType := '';
|
|
StrDefault := '';
|
|
|
|
try
|
|
Gen(OP_DECLARE_MEMBER, CurrLevel, result, 0);
|
|
SetVisibility(result, vis);
|
|
BeginProperty(result, ClassTypeId);
|
|
|
|
Parse_FormalParameterList(result, '[');
|
|
|
|
if IsCurrText(';') then
|
|
begin
|
|
Gen(OP_DETERMINE_PROP, result, 0, 0);
|
|
EndProperty(result);
|
|
Exit;
|
|
end
|
|
else if IsCurrText('default') then
|
|
begin
|
|
Call_SCANNER;
|
|
StrDefault := CurrToken.Text;
|
|
if not IsCurrText(';') then
|
|
Parse_Expression;
|
|
Gen(OP_DETERMINE_PROP, result, 0, 0);
|
|
EndProperty(result);
|
|
Exit;
|
|
end
|
|
else if IsCurrText('nodefault') then
|
|
begin
|
|
Call_SCANNER;
|
|
Gen(OP_DETERMINE_PROP, result, 0, 0);
|
|
EndProperty(result);
|
|
Exit;
|
|
end;
|
|
|
|
if IsCurrText(':') then
|
|
begin
|
|
DECLARE_SWITCH := false;
|
|
Match(':');
|
|
TypeID := Parse_QualId;
|
|
StrType := GetName(TypeId);
|
|
Gen(OP_ASSIGN_TYPE, result, TypeID, 0);
|
|
end;
|
|
|
|
repeat
|
|
DECLARE_SWITCH := false;
|
|
if IsCurrText('read') and (ReadId = 0) then
|
|
begin
|
|
RemoveLastIdent(CurrToken.Id);
|
|
Call_SCANNER;
|
|
ReadId := Parse_QualId;
|
|
Gen(OP_SET_READ_ID, result, ReadId, 0);
|
|
SetReadId(result, ReadId);
|
|
|
|
if IsCurrText(';') then
|
|
if IsNextText('default') then
|
|
Call_SCANNER;
|
|
end
|
|
else if IsCurrText('write') and (WriteId = 0) then
|
|
begin
|
|
RemoveLastIdent(CurrToken.Id);
|
|
Call_SCANNER;
|
|
WriteId := Parse_QualId;
|
|
Gen(OP_SET_WRITE_ID, result, WriteId, 0);
|
|
SetWriteId(result, WriteId);
|
|
|
|
if IsCurrText(';') then
|
|
if IsNextText('default') then
|
|
Call_SCANNER;
|
|
end
|
|
else if IsCurrText('implements') then
|
|
begin
|
|
RemoveLastIdent(CurrToken.Id);
|
|
DECLARE_SWITCH := false;
|
|
Call_SCANNER;
|
|
if not StrEql(GetName(result), CurrToken.Text) then
|
|
DiscardLastStRecord;
|
|
repeat
|
|
ImplementsId := Parse_QualId;
|
|
Gen(OP_IMPLEMENTS, result, ImplementsId, 0);
|
|
if NotMatch(',') then
|
|
break;
|
|
until false;
|
|
end
|
|
else if IsCurrText('stored') then
|
|
begin
|
|
DECLARE_SWITCH := false;
|
|
if not StrEql(GetName(result), CurrToken.Text) then
|
|
DiscardLastStRecord;
|
|
Call_SCANNER;
|
|
Parse_Expression;
|
|
end
|
|
else if IsCurrText('index') then
|
|
begin
|
|
DECLARE_SWITCH := false;
|
|
if not StrEql(GetName(result), CurrToken.Text) then
|
|
DiscardLastStRecord;
|
|
Call_SCANNER;
|
|
Parse_Expression;
|
|
end
|
|
else if IsCurrText('default') then
|
|
begin
|
|
if not StrEql(GetName(result), CurrToken.Text) then
|
|
DiscardLastStRecord;
|
|
Call_SCANNER;
|
|
if IsCurrText(';') then
|
|
SetDefault(result, true)
|
|
else
|
|
Parse_Expression;
|
|
end
|
|
else if IsCurrText('nodefault') then
|
|
begin
|
|
if not StrEql(GetName(result), CurrToken.Text) then
|
|
DiscardLastStRecord;
|
|
Call_SCANNER;
|
|
end
|
|
else
|
|
break;
|
|
until false;
|
|
|
|
if IsNextText('default') then
|
|
begin
|
|
Call_SCANNER;
|
|
Match('default');
|
|
StrDefault := CurrToken.Text;
|
|
SetDefault(result, true);
|
|
end;
|
|
|
|
if ReadId > 0 then
|
|
TKernel(kernel).Code.used_private_members.Add(ReadId);
|
|
if WriteId > 0 then
|
|
TKernel(kernel).Code.used_private_members.Add(WriteId);
|
|
|
|
EndProperty(result);
|
|
finally
|
|
RestoreKeywords;
|
|
if Assigned(OnParsePropertyDeclaration) then
|
|
begin
|
|
Declaration := ExtractText(SavedPosition,
|
|
CurrToken.Position + CurrToken.Length - 1);
|
|
if IsShared then
|
|
Declaration := 'class ' + Declaration;
|
|
|
|
if StrType = '' then
|
|
if GetSymbolRec(result).Vis in [cvPublic, cvProtected] then
|
|
begin
|
|
if ReadId > 0 then
|
|
begin
|
|
TypeId := GetSymbolRec(ReadId).TypeID;
|
|
StrType := GetName(TypeId);
|
|
end;
|
|
|
|
if StrType = '' then
|
|
if WriteId > 0 then
|
|
begin
|
|
if GetKind(WriteId) = KindSUB then
|
|
begin
|
|
K := GetCount(result);
|
|
K := GetParamId(WriteId, K);
|
|
TypeId := GetSymbolRec(K).TypeID;
|
|
StrType := GetName(TypeId);
|
|
end
|
|
else
|
|
begin
|
|
TypeId := GetSymbolRec(WriteId).TypeID;
|
|
StrType := GetName(TypeId);
|
|
end;
|
|
end;
|
|
|
|
if StrType = '' then
|
|
if StrDefault <> '' then
|
|
begin
|
|
if StrEql(StrDefault, 'true') or StrEql(StrDefault, 'false') then
|
|
StrType := 'Boolean';
|
|
end;
|
|
end;
|
|
OnParsePropertyDeclaration(Owner, GetName(result), result, StrType,
|
|
Declaration);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_ClassTypeDeclaration(ClassTypeID: Integer; IsPacked: Boolean;
|
|
IsExternalUnit: Boolean = false);
|
|
var
|
|
vis: TClassVisibility;
|
|
|
|
var
|
|
L: TIntegerList;
|
|
I, TypeID, AncestorId, RefTypeId, Id: Integer;
|
|
b: Boolean;
|
|
Declaration: String;
|
|
TrueClassId: Integer;
|
|
SavedPosition: Integer;
|
|
begin
|
|
SavedPosition := CurrToken.Position;
|
|
|
|
if IsNextText('of') then
|
|
begin
|
|
DECLARE_SWITCH := false;
|
|
BeginClassReferenceType(ClassTypeID);
|
|
Match('class');
|
|
Match('of');
|
|
RefTypeId := Parse_QualId;
|
|
Gen(OP_CREATE_CLASSREF_TYPE, ClassTypeId, RefTypeId, 0);
|
|
EndClassReferenceType(ClassTypeID);
|
|
if Assigned(OnParseClassReferenceTypeDeclaration) then
|
|
begin
|
|
Declaration := ExtractText(SavedPosition, CurrToken.Position + CurrToken.Length - 1);
|
|
OnParseClassReferenceTypeDeclaration(Owner,
|
|
GetName(ClassTypeId), ClassTypeId, GetName(RefTypeId), Declaration);
|
|
end;
|
|
Exit;
|
|
end
|
|
else if IsNextText('helper') then
|
|
begin
|
|
Match('class');
|
|
DECLARE_SWITCH := false;
|
|
RemoveLastIdent(CurrToken.Id);
|
|
Match('helper');
|
|
Match('for');
|
|
TrueClassId := Parse_QualId;
|
|
BeginHelperType(ClassTypeId, TrueClassId);
|
|
end
|
|
else
|
|
begin
|
|
BeginClassType(ClassTypeID);
|
|
TrueClassId := 0;
|
|
|
|
if IsPacked then
|
|
SetPacked(ClassTypeID);
|
|
|
|
Match('class');
|
|
|
|
if IsCurrText(';') then // forward declaration
|
|
begin
|
|
SetForward(ClassTypeId, true);
|
|
EndClassType(ClassTypeId, true);
|
|
if Assigned(OnParseForwardTypeDeclaration) then
|
|
OnParseForwardTypeDeclaration(Owner, GetName(ClassTypeId), ClassTypeId);
|
|
Exit;
|
|
end;
|
|
|
|
if IsCurrText('abstract') then
|
|
begin
|
|
RemoveLastEvalInstruction('abstract');
|
|
SetAbstract(ClassTypeId, true);
|
|
Call_SCANNER;
|
|
end
|
|
else if IsCurrText('sealed') then
|
|
begin
|
|
SetFinal(ClassTypeId, true);
|
|
Call_SCANNER;
|
|
end;
|
|
end;
|
|
|
|
if TrueClassId > 0 then
|
|
begin
|
|
if Assigned(OnParseBeginClassHelperTypeDeclaration) then
|
|
begin
|
|
OnParseBeginClassHelperTypeDeclaration(Owner, GetName(ClassTypeId), ClassTypeId,
|
|
GetName(TrueClassId),
|
|
Declaration);
|
|
end;
|
|
end
|
|
else if Assigned(OnParseBeginClassTypeDeclaration) then
|
|
begin
|
|
Declaration := ExtractText(SavedPosition, PrevPosition + PrevLength - 1);
|
|
Declaration := GetName(ClassTypeId) + ' = ' + Declaration;
|
|
OnParseBeginClassTypeDeclaration(Owner, GetName(ClassTypeId), ClassTypeId, Declaration);
|
|
end;
|
|
|
|
if IsCurrText('(') then
|
|
begin
|
|
DECLARE_SWITCH := false;
|
|
Match('(');
|
|
AncestorId := Parse_QualId;
|
|
Gen(OP_ADD_ANCESTOR, ClassTypeId, AncestorId, 0);
|
|
if Assigned(OnParseAncestorTypeDeclaration) then
|
|
OnParseAncestorTypeDeclaration(Owner, GetName(AncestorId), AncestorId);
|
|
|
|
if StrEql(GetName(ClassTypeId), GetName(AncestorId)) then
|
|
RaiseError(errRedeclaredIdentifier, [GetName(AncestorId)]);
|
|
|
|
if IsCurrText(',') then
|
|
begin
|
|
Call_SCANNER;
|
|
repeat
|
|
AncestorId := Parse_QualId;
|
|
Gen(OP_ADD_INTERFACE, ClassTypeId, AncestorId, 0);
|
|
if Assigned(OnParseUsedInterface) then
|
|
OnParseUsedInterface(Owner, GetName(AncestorId), AncestorId);
|
|
if NotMatch(',') then
|
|
break;
|
|
until false;
|
|
end;
|
|
|
|
DECLARE_SWITCH := true;
|
|
Match(')')
|
|
end
|
|
else
|
|
if Assigned(OnParseAncestorTypeDeclaration) then
|
|
OnParseAncestorTypeDeclaration(Owner, GetName(H_TObject), H_TObject);
|
|
|
|
|
|
if IsCurrText(';') then
|
|
begin
|
|
if TrueClassId > 0 then
|
|
begin
|
|
EndHelperType(ClassTypeId);
|
|
|
|
if Assigned(OnParseEndClassHelperTypeDeclaration) then
|
|
OnParseEndClassHelperTypeDeclaration(Owner, GetName(ClassTypeId), ClassTypeId);
|
|
end
|
|
else
|
|
begin
|
|
EndClassType(ClassTypeId);
|
|
|
|
if Assigned(OnParseEndClassTypeDeclaration) then
|
|
OnParseEndClassTypeDeclaration(Owner, GetName(ClassTypeId), ClassTypeId);
|
|
|
|
if FindConstructorId(ClassTypeId) = 0 then
|
|
GenDefaultConstructor(ClassTypeId);
|
|
if FindDestructorId(ClassTypeId) = 0 then
|
|
GenDefaultDestructor(ClassTypeId);
|
|
end;
|
|
Exit;
|
|
end;
|
|
|
|
vis := cvPublished;
|
|
|
|
b := false;
|
|
|
|
L := TIntegerList.Create;
|
|
try
|
|
repeat
|
|
if IsEOF then
|
|
Break;
|
|
if IsCurrText('end') then
|
|
Break;
|
|
|
|
repeat
|
|
if IsCurrText('strict') then
|
|
begin
|
|
RemoveLastIdent(CurrToken.Id);
|
|
Call_SCANNER;
|
|
if IsCurrText('protected') then
|
|
begin
|
|
Call_SCANNER;
|
|
vis := cvStrictProtected;
|
|
end
|
|
else
|
|
begin
|
|
Match('private');
|
|
vis := cvStrictPrivate;
|
|
end;
|
|
b := false;
|
|
end
|
|
else if IsCurrText('private') then
|
|
begin
|
|
Call_SCANNER;
|
|
vis := cvPrivate;
|
|
b := false;
|
|
end
|
|
else if IsCurrText('protected') then
|
|
begin
|
|
Call_SCANNER;
|
|
vis := cvProtected;
|
|
b := false;
|
|
end
|
|
else if IsCurrText('public') then
|
|
begin
|
|
Call_SCANNER;
|
|
vis := cvPublic;
|
|
b := false;
|
|
end
|
|
else if IsCurrText('published') then
|
|
begin
|
|
Call_SCANNER;
|
|
vis := cvPublished;
|
|
b := false;
|
|
end
|
|
else
|
|
break;
|
|
|
|
until false;
|
|
|
|
if IsCurrText('end') then
|
|
Break;
|
|
|
|
Parse_Attribute;
|
|
|
|
if IsCurrText('constructor') then
|
|
begin
|
|
Parse_ClassConstructorHeading(false, ClassTypeId, vis, IsExternalUnit);
|
|
b := true;
|
|
end
|
|
else if IsCurrText('destructor') then
|
|
begin
|
|
Parse_ClassDestructorHeading(false, ClassTypeId, vis, IsExternalUnit);
|
|
b := true;
|
|
end
|
|
else if IsCurrText('procedure') then
|
|
begin
|
|
Parse_ClassProcedureHeading(false, ClassTypeId, vis, IsExternalUnit);
|
|
b := true;
|
|
end
|
|
else if IsCurrText('function') then
|
|
begin
|
|
Parse_ClassFunctionHeading(false, ClassTypeId, vis, IsExternalUnit);
|
|
b := true;
|
|
end
|
|
else if IsCurrText('var') or IsCurrText('threadvar') then
|
|
begin
|
|
if IsCurrText('threadvar') then
|
|
Call_SCANNER
|
|
else
|
|
Match('var');
|
|
|
|
repeat
|
|
Parse_Attribute;
|
|
|
|
L.Clear;
|
|
repeat // parse ident list
|
|
Id := Parse_Ident;
|
|
Gen(OP_DECLARE_MEMBER, CurrLevel, Id, 0);
|
|
L.Add(Id);
|
|
if NotMatch(',') then
|
|
break;
|
|
until false;
|
|
|
|
DECLARE_SWITCH := false;
|
|
Match(':');
|
|
|
|
TypeID := Parse_Type;
|
|
|
|
for I:=0 to L.Count - 1 do
|
|
begin
|
|
SetKind(L[I], KindTYPE_FIELD);
|
|
SetVisibility(L[I], vis);
|
|
Gen(OP_ASSIGN_TYPE, L[I], TypeID, 0);
|
|
end;
|
|
|
|
DECLARE_SWITCH := true;
|
|
|
|
Parse_PortabilityDirective;
|
|
|
|
if IsCurrText(';') then
|
|
Match(';');
|
|
|
|
if CurrToken.TokenClass <> tcIdentifier then
|
|
if not IsCurrText('[') then
|
|
break;
|
|
until false;
|
|
end
|
|
else if IsCurrText('class') then
|
|
begin
|
|
b := true;
|
|
Call_SCANNER;
|
|
if IsCurrText('constructor') then
|
|
Parse_ClassConstructorHeading(true, ClassTypeId, vis, IsExternalUnit)
|
|
else if IsCurrText('destructor') then
|
|
Parse_ClassDestructorHeading(true, ClassTypeId, vis, IsExternalUnit)
|
|
else if IsCurrText('procedure') then
|
|
Parse_ClassProcedureHeading(true, ClassTypeId, vis, IsExternalUnit)
|
|
else if IsCurrText('function') then
|
|
Parse_ClassFunctionHeading(true, ClassTypeId, vis, IsExternalUnit)
|
|
else if IsCurrText('property') then
|
|
Parse_ClassProperty(true, ClassTypeId, vis, IsExternalUnit)
|
|
else if IsCurrText('var') or IsCurrText('threadvar') then
|
|
begin
|
|
if vis = cvPublished then
|
|
Parse_VariableDeclaration(cvPublic)
|
|
else
|
|
Parse_VariableDeclaration(vis);
|
|
end;
|
|
end
|
|
else if IsCurrText('property') then
|
|
begin
|
|
Parse_ClassProperty(false, ClassTypeId, vis, IsExternalUnit);
|
|
b := true;
|
|
end
|
|
else if IsCurrText('type') then
|
|
begin
|
|
Parse_TypeDeclaration(false, vis);
|
|
b := true;
|
|
end
|
|
else if IsCurrText('const') then
|
|
begin
|
|
if vis = cvPublished then
|
|
Parse_ConstantDeclaration(cvPublic)
|
|
else
|
|
Parse_ConstantDeclaration(vis);
|
|
b := true;
|
|
end
|
|
else
|
|
begin
|
|
if IsCurrText('var') then
|
|
Call_SCANNER
|
|
else if IsCurrText('threadvar') then
|
|
Call_SCANNER;
|
|
|
|
if b then
|
|
CreateError(errFieldDefinitionNotAllowedAfter, []);
|
|
|
|
Parse_Attribute;
|
|
|
|
L.Clear;
|
|
repeat // parse ident list
|
|
Id := Parse_Ident;
|
|
Gen(OP_DECLARE_MEMBER, CurrLevel, Id, 0);
|
|
L.Add(Id);
|
|
if NotMatch(',') then
|
|
break;
|
|
until false;
|
|
|
|
DECLARE_SWITCH := false;
|
|
Match(':');
|
|
|
|
SavedPosition := CurrToken.Position;
|
|
|
|
TypeID := Parse_Type;
|
|
|
|
for I:=0 to L.Count - 1 do
|
|
begin
|
|
SetKind(L[I], KindTYPE_FIELD);
|
|
SetVisibility(L[I], vis);
|
|
Gen(OP_ASSIGN_TYPE, L[I], TypeID, 0);
|
|
|
|
if Assigned(OnParseFieldDeclaration) then
|
|
begin
|
|
Declaration := GetName(L[I]) + ':' +
|
|
ExtractText(SavedPosition, CurrToken.Position + CurrToken.Length - 1);
|
|
OnParseFieldDeclaration(Owner, GetName(L[I]), L[I], GetName(TypeId),
|
|
Declaration);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
DECLARE_SWITCH := true;
|
|
|
|
Parse_PortabilityDirective;
|
|
|
|
if IsCurrText(';') then
|
|
Match(';');
|
|
until false;
|
|
finally
|
|
FreeAndNil(L);
|
|
end;
|
|
|
|
if TrueClassId > 0 then
|
|
begin
|
|
EndHelperType(ClassTypeId);
|
|
|
|
if Assigned(OnParseEndClassHelperTypeDeclaration) then
|
|
OnParseEndClassHelperTypeDeclaration(Owner, GetName(ClassTypeId), ClassTypeId);
|
|
end
|
|
else
|
|
begin
|
|
EndClassType(ClassTypeId);
|
|
|
|
if Assigned(OnParseEndClassTypeDeclaration) then
|
|
OnParseEndClassTypeDeclaration(Owner, GetName(ClassTypeId), ClassTypeId);
|
|
|
|
if FindConstructorId(ClassTypeId) = 0 then
|
|
GenDefaultConstructor(ClassTypeId);
|
|
if FindDestructorId(ClassTypeId) = 0 then
|
|
GenDefaultDestructor(ClassTypeId);
|
|
end;
|
|
|
|
Match('end');
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_MethodRefTypeDeclaration(TypeID: Integer);
|
|
|
|
var
|
|
NegativeMethodIndex: Integer;
|
|
|
|
function Parse_ProcedureHeading: Integer;
|
|
var
|
|
DirectiveList: TIntegerList;
|
|
Declaration: String;
|
|
SavedPosition: Integer;
|
|
begin
|
|
SavedPosition := CurrToken.Position;
|
|
|
|
Dec(NegativeMethodIndex);
|
|
|
|
DECLARE_SWITCH := true;
|
|
Match('procedure');
|
|
result := NewTempVar();
|
|
SetName(result, ANONYMOUS_METHOD_NAME);
|
|
BeginInterfaceMethod(result, TypeId, false);
|
|
if Assigned(OnParseBeginSubDeclaration) then
|
|
OnParseBeginSubDeclaration(Owner, GetName(result), result);
|
|
|
|
Parse_FormalParameterList(result);
|
|
Gen(OP_ADD_METHOD_INDEX, result, NegativeMethodIndex, 0);
|
|
|
|
DECLARE_SWITCH := true;
|
|
EndTypeDef(TypeId);
|
|
Match(';');
|
|
|
|
DirectiveList := Parse_DirectiveList(result);
|
|
if DirectiveList.IndexOf(dirABSTRACT) >= 0 then
|
|
CreateError(errUnknownDirective, ['abstract']);
|
|
EndSub(result);
|
|
FreeAndNil(DirectiveList);
|
|
|
|
if Assigned(OnParseEndSubDeclaration) then
|
|
begin
|
|
Declaration := ExtractText(SavedPosition, PrevPosition + PrevLength - 1);
|
|
OnParseEndSubDeclaration(Owner, GetName(result), result, Declaration);
|
|
end;
|
|
end;
|
|
|
|
function Parse_FunctionHeading: Integer;
|
|
var
|
|
ResTypeID: Integer;
|
|
DirectiveList: TIntegerList;
|
|
Declaration: String;
|
|
SavedPosition: Integer;
|
|
begin
|
|
SavedPosition := CurrToken.Position;
|
|
|
|
Dec(NegativeMethodIndex);
|
|
|
|
DECLARE_SWITCH := true;
|
|
Match('function');
|
|
result := NewTempVar();
|
|
SetName(result, ANONYMOUS_METHOD_NAME);
|
|
BeginInterfaceMethod(result, TypeId, true);
|
|
if Assigned(OnParseBeginSubDeclaration) then
|
|
OnParseBeginSubDeclaration(Owner, GetName(result), result);
|
|
Parse_FormalParameterList(result);
|
|
|
|
DECLARE_SWITCH := false;
|
|
Match(':');
|
|
Parse_Attribute;
|
|
ResTypeID := Parse_Type;
|
|
Gen(OP_ASSIGN_TYPE, result, ResTypeID, 0);
|
|
Gen(OP_ASSIGN_TYPE, CurrResultId, ResTypeID, 0);
|
|
Gen(OP_ADD_METHOD_INDEX, result, NegativeMethodIndex, 0);
|
|
if Assigned(OnParseResultType) then
|
|
OnParseResultType(Owner, GetName(ResTypeId), TypeId);
|
|
|
|
DECLARE_SWITCH := true;
|
|
EndTypeDef(TypeId);
|
|
Match(';');
|
|
|
|
DirectiveList := Parse_DirectiveList(result);
|
|
if DirectiveList.IndexOf(dirABSTRACT) >= 0 then
|
|
CreateError(errUnknownDirective, ['abstract']);
|
|
EndSub(result);
|
|
FreeAndNil(DirectiveList);
|
|
|
|
if Assigned(OnParseEndSubDeclaration) then
|
|
begin
|
|
Declaration := ExtractText(SavedPosition, PrevPosition + PrevLength - 1);
|
|
OnParseEndSubDeclaration(Owner, GetName(result), result, Declaration);
|
|
end;
|
|
end;
|
|
|
|
var
|
|
SavedPosition: Integer;
|
|
Declaration: String;
|
|
begin
|
|
SavedPosition := CurrToken.Position;
|
|
|
|
NegativeMethodIndex := 0;
|
|
|
|
BeginMethodRefType(TypeID);
|
|
|
|
if IsCurrText('procedure') then
|
|
begin
|
|
Parse_ProcedureHeading;
|
|
end
|
|
else if IsCurrText('function') then
|
|
begin
|
|
Parse_FunctionHeading;
|
|
end
|
|
else
|
|
Match('procedure');
|
|
|
|
EndMethodRefType(TypeId);
|
|
|
|
if Assigned(OnParseMethodReferenceTypeDeclaration) then
|
|
begin
|
|
Declaration := ExtractText(SavedPosition, PrevPosition +
|
|
PrevLength - 1);
|
|
OnParseMethodReferenceTypeDeclaration(Owner, GetName(TypeId), TypeId,
|
|
Declaration);
|
|
end;
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_InterfaceTypeDeclaration(IntfTypeID: Integer);
|
|
|
|
const
|
|
IsPacked = true;
|
|
|
|
var
|
|
NegativeMethodIndex: Integer;
|
|
|
|
function Parse_ProcedureHeading: Integer;
|
|
var
|
|
DirectiveList: TIntegerList;
|
|
Declaration: String;
|
|
SavedPosition: Integer;
|
|
begin
|
|
SavedPosition := CurrToken.Position;
|
|
|
|
Dec(NegativeMethodIndex);
|
|
|
|
DECLARE_SWITCH := true;
|
|
Match('procedure');
|
|
result := Parse_Ident;
|
|
BeginInterfaceMethod(result, IntfTypeId, false);
|
|
if Assigned(OnParseBeginSubDeclaration) then
|
|
OnParseBeginSubDeclaration(Owner, GetName(result), result);
|
|
|
|
Parse_FormalParameterList(result);
|
|
Gen(OP_ADD_METHOD_INDEX, result, NegativeMethodIndex, 0);
|
|
|
|
DECLARE_SWITCH := true;
|
|
Match(';');
|
|
|
|
if IsCurrText('dispid') then
|
|
begin
|
|
Call_SCANNER;
|
|
Parse_Expression;
|
|
end;
|
|
|
|
DirectiveList := Parse_DirectiveList(result);
|
|
if DirectiveList.IndexOf(dirABSTRACT) >= 0 then
|
|
CreateError(errUnknownDirective, ['abstract']);
|
|
EndSub(result);
|
|
if Assigned(OnParseEndSubDeclaration) then
|
|
begin
|
|
Declaration := ExtractText(SavedPosition, PrevPosition + PrevLength - 1);
|
|
OnParseEndSubDeclaration(Owner, GetName(result), result, Declaration);
|
|
end;
|
|
|
|
FreeAndNil(DirectiveList);
|
|
end;
|
|
|
|
function Parse_FunctionHeading: Integer;
|
|
var
|
|
TypeID: Integer;
|
|
DirectiveList: TIntegerList;
|
|
Declaration: String;
|
|
SavedPosition: Integer;
|
|
begin
|
|
SavedPosition := CurrToken.Position;
|
|
Dec(NegativeMethodIndex);
|
|
|
|
DECLARE_SWITCH := true;
|
|
Match('function');
|
|
result := Parse_Ident;
|
|
BeginInterfaceMethod(result, IntfTypeId, true);
|
|
if Assigned(OnParseBeginSubDeclaration) then
|
|
OnParseBeginSubDeclaration(Owner, GetName(result), result);
|
|
Parse_FormalParameterList(result);
|
|
|
|
DECLARE_SWITCH := false;
|
|
Match(':');
|
|
Parse_Attribute;
|
|
TypeID := Parse_Type;
|
|
Gen(OP_ASSIGN_TYPE, result, TypeID, 0);
|
|
Gen(OP_ASSIGN_TYPE, CurrResultId, TypeID, 0);
|
|
Gen(OP_ADD_METHOD_INDEX, result, NegativeMethodIndex, 0);
|
|
if Assigned(OnParseResultType) then
|
|
OnParseResultType(Owner, GetName(TypeId), TypeId);
|
|
|
|
DECLARE_SWITCH := true;
|
|
Match(';');
|
|
|
|
if IsCurrText('dispid') then
|
|
begin
|
|
Call_SCANNER;
|
|
Parse_Expression;
|
|
end;
|
|
|
|
DirectiveList := Parse_DirectiveList(result);
|
|
if DirectiveList.IndexOf(dirABSTRACT) >= 0 then
|
|
CreateError(errUnknownDirective, ['abstract']);
|
|
EndSub(result);
|
|
if Assigned(OnParseEndSubDeclaration) then
|
|
begin
|
|
Declaration := ExtractText(SavedPosition, PrevPosition + PrevLength - 1);
|
|
OnParseEndSubDeclaration(Owner, GetName(result), result, Declaration);
|
|
end;
|
|
FreeAndNil(DirectiveList);
|
|
end;
|
|
|
|
function Parse_Property: Integer;
|
|
var
|
|
TypeID, ReadId, WriteId: Integer;
|
|
Declaration: String;
|
|
SavedPosition: Integer;
|
|
begin
|
|
DECLARE_SWITCH := true;
|
|
SavedPosition := CurrToken.Position;
|
|
Match('property');
|
|
result := Parse_Ident;
|
|
BeginProperty(result, IntfTypeId);
|
|
|
|
ReadId := 0;
|
|
WriteId := 0;
|
|
TypeId := 0;
|
|
|
|
try
|
|
SetVisibility(result, cvPublic);
|
|
Parse_FormalParameterList(result, '[');
|
|
|
|
DECLARE_SWITCH := false;
|
|
Match(':');
|
|
TypeID := Parse_QualId;
|
|
Gen(OP_ASSIGN_TYPE, result, TypeID, 0);
|
|
|
|
if IsCurrText('readonly') then
|
|
begin
|
|
Call_SCANNER;
|
|
end
|
|
else if IsCurrText('writeonly') then
|
|
begin
|
|
Call_SCANNER;
|
|
end;
|
|
|
|
if IsCurrText('dispid') then
|
|
begin
|
|
Call_SCANNER;
|
|
Parse_Expression;
|
|
if IsNextText('default') then
|
|
begin
|
|
Match(';');
|
|
Call_SCANNER;
|
|
SetDefault(result, true);
|
|
end;
|
|
EndProperty(result);
|
|
Exit;
|
|
end;
|
|
|
|
repeat
|
|
if IsCurrText('read') and (ReadId = 0) then
|
|
begin
|
|
RemoveLastIdent(CurrToken.Id);
|
|
Call_SCANNER;
|
|
ReadId := Parse_QualId;
|
|
ReadId := Lookup(GetName(ReadId), IntfTypeId);
|
|
if ReadId = 0 then
|
|
RaiseError(errUndeclaredIdentifier, [CurrToken.Text]);
|
|
SetReadId(result, ReadId);
|
|
end
|
|
else if IsCurrText('write') and (WriteId = 0) then
|
|
begin
|
|
RemoveLastIdent(CurrToken.Id);
|
|
Call_SCANNER;
|
|
WriteId := Parse_QualId;
|
|
WriteId := Lookup(GetName(WriteId), IntfTypeId);
|
|
if WriteId = 0 then
|
|
RaiseError(errUndeclaredIdentifier, [CurrToken.Text]);
|
|
SetWriteId(result, WriteId);
|
|
end
|
|
else
|
|
break;
|
|
until false;
|
|
|
|
if IsCurrText(';') then
|
|
Call_SCANNER
|
|
else
|
|
RaiseError(errTokenExpected, [';', CurrToken.Text]);
|
|
|
|
if IsCurrText('default') then
|
|
begin
|
|
Call_SCANNER;
|
|
SetDefault(result, true);
|
|
end;
|
|
|
|
if ReadId + WriteId = 0 then
|
|
RaiseError(errSyntaxError, []);
|
|
|
|
EndProperty(result);
|
|
finally
|
|
if Assigned(OnParsePropertyDeclaration) then
|
|
begin
|
|
Declaration := ExtractText(SavedPosition, PrevPosition +
|
|
PrevLength - 1);
|
|
OnParsePropertyDeclaration(Owner, GetName(result), result, GetName(TypeId),
|
|
Declaration);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
L: TIntegerList;
|
|
I, AncestorId: Integer;
|
|
S: String;
|
|
IntfList: TIntegerList;
|
|
begin
|
|
IntfList := TIntegerList.Create;
|
|
try
|
|
NegativeMethodIndex := 0;
|
|
|
|
BeginInterfaceType(IntfTypeID);
|
|
SetPacked(IntfTypeID);
|
|
|
|
if IsCurrText('dispinterface') then
|
|
Call_SCANNER
|
|
else
|
|
Match('interface');
|
|
|
|
if IsCurrText(';') then // forward declaration
|
|
begin
|
|
SetForward(IntfTypeId, true);
|
|
EndInterfaceType(IntfTypeId, true);
|
|
if Assigned(OnParseForwardTypeDeclaration) then
|
|
OnParseForwardTypeDeclaration(Owner, GetName(IntfTypeId), IntfTypeId);
|
|
Exit;
|
|
end;
|
|
|
|
if IsCurrText('(') then
|
|
begin
|
|
DECLARE_SWITCH := false;
|
|
Match('(');
|
|
|
|
repeat
|
|
AncestorId := Parse_Ident;
|
|
IntfList.Add(AncestorId);
|
|
Gen(OP_ADD_INTERFACE, IntfTypeId, AncestorId, 0);
|
|
if NotMatch(',') then
|
|
break;
|
|
until false;
|
|
|
|
DECLARE_SWITCH := true;
|
|
Match(')');
|
|
end
|
|
else
|
|
begin
|
|
Gen(OP_ADD_INTERFACE, IntfTypeId, H_IUnknown, 0);
|
|
IntfList.Add(H_IUnknown);
|
|
end;
|
|
|
|
if IsCurrText('[') then
|
|
begin
|
|
Match('[');
|
|
if CurrToken.TokenClass = tcPCharConst then
|
|
begin
|
|
I := Parse_PCharLiteral;
|
|
S := GetValue(I);
|
|
SetGuid(IntfTypeId, S);
|
|
end
|
|
else
|
|
begin
|
|
I := Parse_Ident;
|
|
S := GetValue(I);
|
|
// SetGuid(IntfTypeId, S);
|
|
if ImportOnly then
|
|
GetSymbolRec(IntfTypeId).NoGUID := true;
|
|
end;
|
|
Match(']');
|
|
end
|
|
else
|
|
begin
|
|
if ImportOnly then
|
|
GetSymbolRec(IntfTypeId).NoGUID := true;
|
|
SetNewGuid(IntfTypeId);
|
|
end;
|
|
|
|
if Assigned(OnParseBeginInterfaceTypeDeclaration) then
|
|
OnParseBeginInterfaceTypeDeclaration(Owner, GetName(IntfTypeId), IntfTypeId);
|
|
if Assigned(OnParseAncestorTypeDeclaration) then
|
|
begin
|
|
AncestorId := IntfList[0];
|
|
OnParseAncestorTypeDeclaration(Owner, GetName(AncestorId), AncestorId);
|
|
end;
|
|
if Assigned(OnParseUsedInterface) then
|
|
for I := 1 to IntfList.Count - 1 do
|
|
begin
|
|
AncestorId := IntfList[I];
|
|
OnParseUsedInterface(Owner, GetName(AncestorId), AncestorId);
|
|
end;
|
|
|
|
L := TIntegerList.Create;
|
|
try
|
|
repeat
|
|
if IsEOF then
|
|
Break;
|
|
if IsCurrText('end') then
|
|
Break;
|
|
|
|
repeat
|
|
if IsCurrText('private') then
|
|
begin
|
|
CreateError(errKeywordNotAllowedInInterfaceDeclaration, [CurrToken.Text]);
|
|
Call_SCANNER;
|
|
end
|
|
else if IsCurrText('protected') then
|
|
begin
|
|
CreateError(errKeywordNotAllowedInInterfaceDeclaration, [CurrToken.Text]);
|
|
Call_SCANNER;
|
|
end
|
|
else if IsCurrText('public') then
|
|
begin
|
|
CreateError(errKeywordNotAllowedInInterfaceDeclaration, [CurrToken.Text]);
|
|
Call_SCANNER;
|
|
end
|
|
else if IsCurrText('published') then
|
|
begin
|
|
CreateError(errKeywordNotAllowedInInterfaceDeclaration, [CurrToken.Text]);
|
|
Call_SCANNER;
|
|
end
|
|
else
|
|
break;
|
|
|
|
until false;
|
|
|
|
if IsCurrText('end') then
|
|
Break;
|
|
|
|
if IsCurrText('procedure') then
|
|
begin
|
|
Parse_ProcedureHeading;
|
|
end
|
|
else if IsCurrText('function') then
|
|
begin
|
|
Parse_FunctionHeading;
|
|
end
|
|
else if IsCurrText('property') then
|
|
begin
|
|
Parse_Property;
|
|
end
|
|
else if IsCurrText('[') then
|
|
Parse_Attribute
|
|
else
|
|
Match('end');
|
|
|
|
DECLARE_SWITCH := true;
|
|
|
|
if IsCurrText(';') then
|
|
Match(';');
|
|
until false;
|
|
finally
|
|
FreeAndNil(L);
|
|
end;
|
|
|
|
EndInterfaceType(IntfTypeId);
|
|
if Assigned(OnParseEndInterfaceTypeDeclaration) then
|
|
OnParseEndInterfaceTypeDeclaration(Owner, GetName(IntfTypeId), IntfTypeId);
|
|
|
|
Match('end');
|
|
finally
|
|
FreeAndNil(IntfList);
|
|
end;
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_PointerTypeDeclaration(TypeID: Integer);
|
|
var
|
|
RefTypeId: Integer;
|
|
Declaration: String;
|
|
SavedPosition: Integer;
|
|
begin
|
|
SavedPosition := CurrToken.Position;
|
|
DECLARE_SWITCH := false;
|
|
Match('^');
|
|
BeginPointerType(TypeID);
|
|
RefTypeId := Parse_QualId;
|
|
Gen(OP_CREATE_POINTER_TYPE, TypeId, RefTypeId, 0);
|
|
EndPointerType(TypeID);
|
|
if Assigned(OnParsePointerTypeDeclaration) then
|
|
begin
|
|
Declaration := GetName(TypeId) + '=' +
|
|
ExtractText(SavedPosition, CurrToken.Position + CurrToken.Length - 1);
|
|
OnParsePointerTypeDeclaration(Owner,
|
|
GetName(TypeId), TypeId, GetName(RefTypeId), Declaration);
|
|
end;
|
|
end;
|
|
|
|
{$IFNDEF PAXARM}
|
|
procedure TPascalParser.Parse_ShortStringTypeDeclaration(TypeID: Integer);
|
|
var
|
|
ExprId: Integer;
|
|
Declaration: String;
|
|
SavedPosition: Integer;
|
|
begin
|
|
SavedPosition := CurrToken.Position;
|
|
DECLARE_SWITCH := false;
|
|
Match('[');
|
|
BeginShortStringType(TypeID);
|
|
ExprId := Parse_ConstantExpression;
|
|
Gen(OP_CREATE_SHORTSTRING_TYPE, TypeId, ExprId, 0);
|
|
EndShortStringType(TypeID);
|
|
Match(']');
|
|
if Assigned(OnParseShortStringTypeDeclaration) then
|
|
begin
|
|
Declaration := 'String' + ExtractText(SavedPosition, PrevPosition + PrevLength - 1);
|
|
OnParseShortStringTypeDeclaration(Owner, GetName(TypeId), TypeId, GetValue(ExprId),
|
|
Declaration);
|
|
end;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
procedure TPascalParser.Parse_ProceduralTypeDeclaration(TypeID: Integer;
|
|
var SubId: Integer);
|
|
var
|
|
IsFunc: Boolean;
|
|
SubTypeId: Integer;
|
|
Declaration: String;
|
|
SavedPosition: Integer;
|
|
begin
|
|
SavedPosition := CurrToken.Position;
|
|
if IsCurrText('function') then
|
|
begin
|
|
Match('function');
|
|
IsFunc := true;
|
|
end
|
|
else
|
|
begin
|
|
Match('procedure');
|
|
IsFunc := false;
|
|
end;
|
|
SubTypeId := typeVOID;
|
|
SubId := NewTempVar;
|
|
BeginProceduralType(TypeID, SubId);
|
|
if Assigned(OnParseBeginSubDeclaration) then
|
|
OnParseBeginSubDeclaration(Owner, GetName(SubId), SubId);
|
|
Parse_FormalParameterList(SubId);
|
|
DECLARE_SWITCH := false;
|
|
if IsFunc then
|
|
begin
|
|
Match(':');
|
|
DECLARE_SWITCH := true;
|
|
SubTypeID := Parse_Type;
|
|
if Assigned(OnParseResultType) then
|
|
OnParseResultType(Owner, GetName(SubTypeID), SubTypeID);
|
|
end;
|
|
Gen(OP_ASSIGN_TYPE, SubId, SubTypeID, 0);
|
|
Gen(OP_ASSIGN_TYPE, CurrResultId, SubTypeID, 0);
|
|
EndProceduralType(TypeID);
|
|
|
|
if Assigned(OnParseEndSubDeclaration) then
|
|
begin
|
|
Declaration := ExtractText(SavedPosition, PrevPosition + PrevLength - 1);
|
|
end;
|
|
|
|
if IsCurrText('of') then
|
|
begin
|
|
Match('of');
|
|
Match('object');
|
|
SetType(TypeId, typeEVENT);
|
|
end;
|
|
|
|
DECLARE_SWITCH := true;
|
|
|
|
if IsCurrText('stdcall') then
|
|
begin
|
|
RemoveLastIdent(CurrToken.Id);
|
|
Call_SCANNER;
|
|
SetCallConvention(SubId, ccSTDCALL);
|
|
end
|
|
else if IsCurrText('safecall') then
|
|
begin
|
|
RemoveLastIdent(CurrToken.Id);
|
|
Call_SCANNER;
|
|
SetCallConvention(SubId, ccSTDCALL);
|
|
end
|
|
else if IsCurrText('register') then
|
|
begin
|
|
RemoveLastIdent(CurrToken.Id);
|
|
Call_SCANNER;
|
|
SetCallConvention(SubId, ccSTDCALL);
|
|
end
|
|
else if IsCurrText('cdecl') then
|
|
begin
|
|
RemoveLastIdent(CurrToken.Id);
|
|
Call_SCANNER;
|
|
SetCallConvention(SubId, ccSTDCALL);
|
|
end
|
|
else if IsCurrText('msfastcall') then
|
|
begin
|
|
RemoveLastIdent(CurrToken.Id);
|
|
Call_SCANNER;
|
|
SetCallConvention(SubId, ccSTDCALL);
|
|
end
|
|
else if IsCurrText('pascal') then
|
|
begin
|
|
RemoveLastIdent(CurrToken.Id);
|
|
Call_SCANNER;
|
|
SetCallConvention(SubId, ccSTDCALL);
|
|
end
|
|
//--------------
|
|
else if IsNextText('stdcall') then
|
|
begin
|
|
Call_SCANNER;
|
|
RemoveLastIdent(CurrToken.Id);
|
|
SetCallConvention(SubId, ccSTDCALL);
|
|
Call_SCANNER;
|
|
end
|
|
else if IsNextText('safecall') then
|
|
begin
|
|
Call_SCANNER;
|
|
RemoveLastIdent(CurrToken.Id);
|
|
SetCallConvention(SubId, ccSAFECALL);
|
|
Call_SCANNER;
|
|
end
|
|
else if IsNextText('register') then
|
|
begin
|
|
Call_SCANNER;
|
|
RemoveLastIdent(CurrToken.Id);
|
|
SetCallConvention(SubId, ccREGISTER);
|
|
Call_SCANNER;
|
|
end
|
|
else if IsNextText('cdecl') then
|
|
begin
|
|
Call_SCANNER;
|
|
RemoveLastIdent(CurrToken.Id);
|
|
SetCallConvention(SubId, ccCDECL);
|
|
Call_SCANNER;
|
|
end
|
|
else if IsNextText('msfastcall') then
|
|
begin
|
|
Call_SCANNER;
|
|
RemoveLastIdent(CurrToken.Id);
|
|
SetCallConvention(SubId, ccMSFASTCALL);
|
|
Call_SCANNER;
|
|
end
|
|
else if IsNextText('pascal') then
|
|
begin
|
|
Call_SCANNER;
|
|
RemoveLastIdent(CurrToken.Id);
|
|
SetCallConvention(SubId, ccPASCAL);
|
|
Call_SCANNER;
|
|
end;
|
|
|
|
if Assigned(OnParseEndSubDeclaration) then
|
|
begin
|
|
OnParseEndSubDeclaration(Owner, GetName(SubId), SubId, Declaration);
|
|
end;
|
|
|
|
if GetType(TypeId) = typePROC then
|
|
begin
|
|
if Assigned(OnParseProceduralTypeDeclaration) then
|
|
begin
|
|
Declaration := ExtractText(SavedPosition, CurrToken.Position +
|
|
CurrToken.Length - 1);
|
|
OnParseProceduralTypeDeclaration(Owner, GetName(TypeId), TypeId,
|
|
Declaration);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
if Assigned(OnParseEventTypeDeclaration) then
|
|
begin
|
|
Declaration := ExtractText(SavedPosition, CurrToken.Position +
|
|
CurrToken.Length - 1);
|
|
OnParseEventTypeDeclaration(Owner, GetName(TypeId), TypeId,
|
|
Declaration);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_SetTypeDeclaration(TypeID: Integer);
|
|
var
|
|
TypeBaseId: Integer;
|
|
Declaration: String;
|
|
SavedPosition: Integer;
|
|
begin
|
|
SavedPosition := CurrToken.Position;
|
|
DECLARE_SWITCH := false;
|
|
Match('set');
|
|
Match('of');
|
|
TypeBaseId := Parse_OrdinalType(Declaration);
|
|
BeginSetType(TypeID, TypeBaseId);
|
|
EndSetType(TypeID);
|
|
if Assigned(OnParseSetTypeDeclaration) then
|
|
begin
|
|
Declaration := GetName(TypeId) + '=' +
|
|
ExtractText(SavedPosition, CurrToken.Position + CurrToken.Length - 1);
|
|
OnParseSetTypeDeclaration(Owner, GetName(TypeId), TypeId, GetName(TypeBaseId),
|
|
Declaration);
|
|
end;
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_EnumTypeDeclaration(TypeID: Integer);
|
|
var
|
|
ID, TempID, L, K: Integer;
|
|
Declaration: String;
|
|
SavedPosition: Integer;
|
|
begin
|
|
L := CurrLevel;
|
|
|
|
BeginEnumType(TypeID, TypeINTEGER);
|
|
if Assigned(OnParseBeginEnumTypeDeclaration) then
|
|
OnParseBeginEnumTypeDeclaration(Owner, GetName(TypeId), TypeId);
|
|
|
|
DECLARE_SWITCH := true;
|
|
Match('(');
|
|
|
|
TempID := NewConst(TypeID, 0);
|
|
|
|
K := 0;
|
|
|
|
repeat
|
|
SavedPosition := CurrToken.Position;
|
|
|
|
ID := Parse_EnumIdent;
|
|
|
|
Inc(K);
|
|
|
|
SetLevel(ID, L);
|
|
|
|
if IsCurrText('=') then
|
|
begin
|
|
DECLARE_SWITCH := false;
|
|
Match('=');
|
|
Gen(OP_ASSIGN_ENUM, ID, Parse_ConstantExpression, ID);
|
|
Gen(OP_ASSIGN_ENUM, TempID, ID, TempID);
|
|
Gen(OP_INC, TempID, NewConst(typeINTEGER, 1), tempID);
|
|
DECLARE_SWITCH := true;
|
|
end
|
|
else
|
|
begin
|
|
Gen(OP_ASSIGN_ENUM, ID, TempID, ID);
|
|
Gen(OP_INC, TempID, NewConst(typeINTEGER, 1), tempID);
|
|
end;
|
|
|
|
if Assigned(OnParseEnumName) then
|
|
begin
|
|
Declaration := ExtractText(SavedPosition, PrevPosition + PrevLength - 1);
|
|
OnParseEnumName(Owner, GetName(ID), ID, K - 1, Declaration);
|
|
end;
|
|
|
|
if NotMatch(',') then
|
|
Break;
|
|
until false;
|
|
Match(')');
|
|
EndEnumType(TypeID, K);
|
|
if Assigned(OnParseEndEnumTypeDeclaration) then
|
|
OnParseEndEnumTypeDeclaration(Owner, GetName(TypeId), TypeId);
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_SubrangeTypeDeclaration(TypeID, TypeBaseId: Integer;
|
|
var Declaration: String;
|
|
Expr1ID: Integer = 0);
|
|
var
|
|
ID1, ID2, ExprId1, ExprId2: Integer;
|
|
SavedPosition: Integer;
|
|
begin
|
|
SavedPosition := Scanner.FindPosition([Ord('='), Ord('['), Ord(':'), Ord(',')]) + 1;
|
|
|
|
BeginSubrangeType(TypeID, TypeBaseID);
|
|
|
|
ID1 := NewConst(TypeBaseId);
|
|
ID2 := NewConst(TypeBaseId);
|
|
|
|
if Expr1ID = 0 then
|
|
begin
|
|
ExprId1 := Parse_ConstantExpression;
|
|
Gen(OP_ASSIGN_CONST, ID1, ExprId1, ID1);
|
|
end
|
|
else
|
|
begin
|
|
Gen(OP_ASSIGN_CONST, ID1, Expr1ID, ID1);
|
|
end;
|
|
|
|
Match('..');
|
|
ExprId2 := Parse_ConstantExpression;
|
|
Gen(OP_ASSIGN_CONST, ID2, ExprId2, ID2);
|
|
|
|
Gen(OP_CHECK_SUBRANGE_TYPE, ID1, ID2, 0);
|
|
|
|
EndSubrangeType(TypeID);
|
|
|
|
Declaration := GetName(TypeId) + ' = ' + ExtractText(SavedPosition, PrevPosition + PrevLength - 1);
|
|
if Assigned(OnParseSubrangeTypeDeclaration) then
|
|
OnParseSubrangeTypeDeclaration(Owner, GetName(TypeId), TypeId, Declaration);
|
|
end;
|
|
|
|
function TPascalParser.Parse_FormalParameterList(SubId: Integer;
|
|
bracket: Char = '('): Integer;
|
|
var
|
|
L: TIntegerList;
|
|
I, ID, TypeId, ExprId: Integer;
|
|
ByRef, IsConst, HasDefaultParameters, IsOpenArray, IsOut: Boolean;
|
|
Declaration, DefaultValue, ParamMod, StrType: String;
|
|
SavedPosition: Integer;
|
|
begin
|
|
result := 0;
|
|
if Assigned(OnParseBeginFormalParameterList) then
|
|
OnParseBeginFormalParameterList(Owner);
|
|
|
|
BeginCollectSig(SubId);
|
|
try
|
|
DECLARE_SWITCH := true;
|
|
if IsCurrText('(') then
|
|
Call_SCANNER
|
|
else if IsCurrText('[') then
|
|
Call_SCANNER
|
|
else
|
|
begin
|
|
if IsCurrText(':') then
|
|
Sig := '( ) : ' + GetNextText
|
|
else
|
|
Sig := '( ) ;';
|
|
Exit;
|
|
end;
|
|
|
|
HasDefaultParameters := false;
|
|
|
|
if not IsCurrText(')') then
|
|
begin
|
|
L := TIntegerList.Create;
|
|
|
|
StrType := '';
|
|
|
|
try
|
|
|
|
repeat
|
|
ByRef := false;
|
|
IsConst := false;
|
|
IsOut := false;
|
|
|
|
Parse_Attribute;
|
|
|
|
ParamMod := '';
|
|
if IsCurrText('var') then
|
|
begin
|
|
ParamMod := 'var';
|
|
Match('var');
|
|
ByRef := true;
|
|
end
|
|
else if IsCurrText('out') then
|
|
begin
|
|
ParamMod := 'out';
|
|
Match('out');
|
|
ByRef := true;
|
|
IsOut := true;
|
|
end
|
|
else if IsCurrText('const') then
|
|
begin
|
|
ParamMod := 'const';
|
|
Match('const');
|
|
IsConst := true;
|
|
end;
|
|
|
|
Parse_Attribute;
|
|
|
|
L.Clear;
|
|
repeat
|
|
Inc(result);
|
|
ID := Parse_FormalParameter;
|
|
Gen(OP_DECLARE_LOCAL_VAR, SubId, ID, 0);
|
|
L.Add(ID);
|
|
if NotMatch(',') then
|
|
break;
|
|
until false;
|
|
DECLARE_SWITCH := false;
|
|
|
|
IsOpenArray := false;
|
|
if ByRef or IsConst then
|
|
begin
|
|
if IsCurrText(':') then
|
|
begin
|
|
Match(':');
|
|
IsOpenArray := IsCurrText('array');
|
|
if IsOpenArray then
|
|
TypeId := Parse_OpenArrayType(StrType)
|
|
else
|
|
begin
|
|
TypeId := Parse_Type;
|
|
StrType := GetName(TypeId);
|
|
end;
|
|
end
|
|
else
|
|
TypeId := typePVOID;
|
|
end
|
|
else
|
|
begin
|
|
Match(':');
|
|
IsOpenArray := IsCurrText('array');
|
|
if IsOpenArray then
|
|
TypeId := Parse_OpenArrayType(StrType)
|
|
else
|
|
begin
|
|
TypeId := Parse_Type;
|
|
StrType := GetName(TypeId);
|
|
end;
|
|
end;
|
|
|
|
DECLARE_SWITCH := true;
|
|
|
|
for I:=0 to L.Count - 1 do
|
|
begin
|
|
if ByRef then if not IsOpenArray then
|
|
SetByRef(L[I]);
|
|
|
|
if IsOut then
|
|
GetSymbolRec(L[I]).IsOut := true;
|
|
|
|
if IsConst then
|
|
SetIsConst(L[I]);
|
|
|
|
if IsOpenArray then
|
|
begin
|
|
SetOpenArray(L[I], true);
|
|
end;
|
|
|
|
Gen(OP_ASSIGN_TYPE, L[I], TypeID, 0);
|
|
end;
|
|
|
|
DefaultValue := '';
|
|
|
|
if IsCurrText('=') then
|
|
begin
|
|
// if L.Count > 1 then
|
|
// CreateError(errParameterNotAllowedHere, [GetName(L[1])]);
|
|
DECLARE_SWITCH := false;
|
|
CollectSig := false;
|
|
Sig := RemoveCh('=', Sig);
|
|
|
|
Match('=');
|
|
|
|
SavedPosition := CurrToken.Position;
|
|
if ImportOnly then
|
|
ExprId := Parse_Expression
|
|
else
|
|
ExprId := Parse_ConstantExpression;
|
|
DefaultValue := ExtractText(SavedPosition, PrevPosition + PrevLength - 1);
|
|
|
|
for I := 0 to L.Count - 1 do
|
|
begin
|
|
Gen(OP_ASSIGN_CONST, L[I], ExprId, L[I]);
|
|
SetOptional(L[I]);
|
|
end;
|
|
CollectSig := true;
|
|
Sig := Sig + CurrToken.Text;
|
|
|
|
DECLARE_SWITCH := true;
|
|
HasDefaultParameters := true;
|
|
end
|
|
else
|
|
begin
|
|
if HasDefaultParameters then
|
|
CreateError(errDefaultValueRequired, [GetName(L[0])]);
|
|
end;
|
|
|
|
if Assigned(OnParseFormalParameterDeclaration) then
|
|
begin
|
|
if IsOpenArray then
|
|
StrType := 'ARRAY OF ' + StrType;
|
|
|
|
for I := 0 to L.Count - 1 do
|
|
begin
|
|
if DefaultValue = '' then
|
|
Declaration := GetName(L[I]) + ' : ' + StrType + ';'
|
|
else
|
|
Declaration := GetName(L[I]) + ' : ' +
|
|
StrType + '=' + DefaultValue + ';';
|
|
|
|
if ParamMod <> '' then
|
|
Declaration := ParamMod + ' ' + Declaration;
|
|
|
|
OnParseFormalParameterDeclaration(Owner,
|
|
GetName(L[I]), L[I], StrType, DefaultValue, Declaration);
|
|
end;
|
|
end;
|
|
|
|
if NotMatch(';') then
|
|
Break;
|
|
until false;
|
|
|
|
finally
|
|
FreeAndNil(L);
|
|
end;
|
|
end;
|
|
|
|
if bracket = '(' then
|
|
Match(')')
|
|
else if bracket = '[' then
|
|
Match(']');
|
|
|
|
if IsCurrText(':') then
|
|
Sig := Sig + ' ' + GetNextText;
|
|
finally
|
|
SetCount(SubId, result);
|
|
EndCollectSig(SubId);
|
|
|
|
if Assigned(OnParseEndFormalParameterList) then
|
|
OnParseEndFormalParameterList(Owner);
|
|
end;
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_SubBlock;
|
|
begin
|
|
if GetName(CurrSelfId) = '' then
|
|
begin
|
|
Gen(OP_STMT, 0, 0, 0);
|
|
Parse_Block;
|
|
end
|
|
else
|
|
begin
|
|
Gen(OP_STMT, 0, 0, 0);
|
|
DECLARE_SWITCH := true;
|
|
Parse_DeclarationPart;
|
|
|
|
Gen(OP_BEGIN_WITH, CurrSelfId, 0, 0);
|
|
WithStack.Push(CurrSelfId);
|
|
Parse_CompoundStmt;
|
|
Gen(OP_END_WITH, WithStack.Top, 0, 0);
|
|
WithStack.Pop;
|
|
end;
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_ProcedureDeclaration(IsSharedMethod: Boolean = false);
|
|
var
|
|
SubId, ForwardId: Integer;
|
|
DirectiveList: TIntegerList;
|
|
NotDeclared, WaitOverload: Boolean;
|
|
K: Integer;
|
|
begin
|
|
DECLARE_SWITCH := true;
|
|
K := 0;
|
|
BeginMethodDef;
|
|
try
|
|
|
|
NotDeclared := false;
|
|
WaitOverload := false;
|
|
|
|
if IsSharedMethod then
|
|
begin
|
|
ForwardId := ReadType;
|
|
|
|
if ForwardId = 0 then
|
|
CreateError(errUndeclaredIdentifier, [CurrToken.Text]);
|
|
|
|
Call_SCANNER;
|
|
DECLARE_SWITCH := true;
|
|
Scanner.CurrComment.AllowedDoComment := false;
|
|
Match('.');
|
|
SubId := Parse_Ident;
|
|
BeginClassMethod(SubId, ForwardId, false, true, true);
|
|
end
|
|
else
|
|
begin
|
|
ForwardId := ReadType;
|
|
|
|
if (ForwardId > 0) and (GetKind(ForwardId) = KindTYPE) then
|
|
begin
|
|
Call_SCANNER;
|
|
|
|
while GetNext2Text = '.' do
|
|
begin
|
|
Inc(K);
|
|
levelStack.Push(ForwardId);
|
|
ReadToken;
|
|
ForwardId := Lookup(CurrToken.Text, CurrLevel);
|
|
if ForwardId = 0 then
|
|
RaiseError(errUndeclaredIdentifier, [CurrToken.Text]);
|
|
ReadToken;
|
|
end;
|
|
|
|
DECLARE_SWITCH := true;
|
|
Scanner.CurrComment.AllowedDoComment := false;
|
|
Match('.');
|
|
SubId := Parse_Ident;
|
|
if Lookup(GetName(SubId), ForwardId) = 0 then
|
|
NotDeclared := true;
|
|
BeginClassMethod(SubId, ForwardId, false, false, true);
|
|
end
|
|
else
|
|
begin
|
|
if ForwardId > 0 then
|
|
if GetKind(ForwardId) in KindSUBS then
|
|
if not GetSymbolRec(ForwardId).IsForward then
|
|
if GetSymbolRec(ForwardId).Host = false then
|
|
if GetSymbolRec(ForwardId).OverCount = 0 then
|
|
RaiseError(errRedeclaredIdentifier, [CurrToken.Text])
|
|
else
|
|
WaitOverload := true;
|
|
|
|
SubId := NewVar(CurrToken.Text);
|
|
SetPosition(SubId, CurrToken.Position - 1);
|
|
CurrToken.Id := SubId;
|
|
Parse_Ident;
|
|
BeginSub(SubId);
|
|
end;
|
|
end;
|
|
|
|
Parse_FormalParameterList(SubId);
|
|
SetName(CurrResultId, '');
|
|
SetKind(CurrResultId, KindNONE);
|
|
SetType(SubId, TypeVOID);
|
|
SetType(CurrResultId, TypeVOID);
|
|
|
|
Match(';');
|
|
|
|
if NotDeclared then
|
|
CreateError(errUndeclaredIdentifier, [GetName(SubId)]);
|
|
|
|
DirectiveList := Parse_DirectiveList(SubId);
|
|
try
|
|
if DirectiveList.IndexOf(dirFORWARD) >= 0 then
|
|
begin
|
|
SetForward(SubId, true);
|
|
EndSub(SubId);
|
|
Exit;
|
|
end;
|
|
if WaitOverload then
|
|
begin
|
|
if DirectiveList.IndexOf(dirOVERLOAD) = -1 then
|
|
CreateError(errOverloadExpected, [GetName(SubId)]);
|
|
end;
|
|
finally
|
|
FreeAndNil(DirectiveList);
|
|
end;
|
|
|
|
if IsCurrText('external') then
|
|
begin
|
|
ParseExternalSub(SubId);
|
|
Exit;
|
|
end;
|
|
|
|
InitSub(SubId);
|
|
|
|
if ForwardId > 0 then
|
|
if not GetSymbolRec(ForwardId).IsForward then
|
|
CheckRedeclaredSub(SubId);
|
|
|
|
Parse_SubBlock;
|
|
EndSub(SubId);
|
|
|
|
EndMethodDef(SubId);
|
|
|
|
Match(';');
|
|
|
|
finally
|
|
while K > 0 do
|
|
begin
|
|
Dec(K);
|
|
levelStack.Pop;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TPascalParser.Parse_AnonymousFunction: Integer;
|
|
begin
|
|
result := Parse_AnonymousRoutine(true);
|
|
end;
|
|
|
|
function TPascalParser.Parse_AnonymousProcedure: Integer;
|
|
begin
|
|
result := Parse_AnonymousRoutine(false);
|
|
end;
|
|
|
|
function TPascalParser.Parse_AnonymousRoutine(IsFunc: Boolean): Integer;
|
|
var
|
|
I, Id, RefId, ClassId, SubId, ResTypeId: Integer;
|
|
ClsName, ObjName: String;
|
|
begin
|
|
NewAnonymousNames(ClsName, ObjName);
|
|
GenComment('BEGIN OF ANONYMOUS CLASS ' + ClsName);
|
|
|
|
TypeParams.Clear;
|
|
|
|
ClassId := NewTempVar;
|
|
SetName(ClassId, ClsName);
|
|
BeginClassType(ClassId);
|
|
SetPacked(ClassId);
|
|
SetAncestorId(ClassId, H_TInterfacedObject);
|
|
// Gen(OP_ADD_INTERFACE, ClassId, 0, 0); // 0 - anonymous
|
|
|
|
GenDefaultConstructor(ClassId);
|
|
GenDefaultDestructor(ClassId);
|
|
|
|
DECLARE_SWITCH := true;
|
|
if IsFunc then
|
|
Match('function')
|
|
else
|
|
Match('procedure');
|
|
|
|
DECLARE_SWITCH := false;
|
|
|
|
SubId := NewTempVar;
|
|
SetName(SubId, ANONYMOUS_METHOD_NAME);
|
|
BeginClassMethod(SubId,
|
|
ClassId,
|
|
IsFunc, // has result
|
|
false, // is shared
|
|
true); // is implementation
|
|
|
|
Parse_FormalParameterList(SubId);
|
|
DECLARE_SWITCH := false;
|
|
if IsFunc then
|
|
begin
|
|
Match(':');
|
|
Parse_Attribute;
|
|
ResTypeId := Parse_Type;
|
|
Gen(OP_ASSIGN_TYPE, SubId, ResTypeId, 0);
|
|
Gen(OP_ASSIGN_TYPE, CurrResultId, ResTypeId, 0);
|
|
end;
|
|
|
|
DECLARE_SWITCH := true;
|
|
|
|
AnonymStack.Push(SubId);
|
|
try
|
|
InitSub(SubId);
|
|
Parse_SubBlock;
|
|
|
|
EndSub(SubId);
|
|
|
|
for I := 0 to AnonymStack.Top.BindList.Count - 1 do
|
|
begin
|
|
Id := NewTempVar;
|
|
SetName(Id, GetName(AnonymStack.Top.BindList[I]));
|
|
SetLevel(Id, ClassId);
|
|
SetKind(Id, KindTYPE_FIELD);
|
|
SetVisibility(Id, cvPublic);
|
|
Gen(OP_ASSIGN_THE_SAME_TYPE, Id, AnonymStack.Top.BindList[I], 0);
|
|
end;
|
|
|
|
EndClassType(ClassId);
|
|
GenComment('END OF ANONYMOUS CLASS ' + ClsName);
|
|
Gen(OP_ADD_TYPEINFO, ClassId, 0, 0);
|
|
|
|
result := NewTempVar;
|
|
Gen(OP_DECLARE_LOCAL_VAR, CurrSubId, result, 0);
|
|
SetName(result, ObjName);
|
|
SetType(result, ClassId);
|
|
|
|
RefId := NewField('Create', result);
|
|
Gen(OP_FIELD, ClassId, RefId, RefId);
|
|
Gen(OP_ASSIGN, result, RefId, result);
|
|
|
|
for I := 0 to AnonymStack.Top.BindList.Count - 1 do
|
|
begin
|
|
RefId := NewField(GetName(AnonymStack.Top.BindList[I]), result);
|
|
Gen(OP_FIELD, result, RefId, RefId);
|
|
Gen(OP_ASSIGN, RefId, AnonymStack.Top.BindList[I], RefId);
|
|
end;
|
|
finally
|
|
AnonymStack.Pop;
|
|
end;
|
|
Gen(OP_ADD_INTERFACE, ClassId, 0, 0); // 0 - anonymous
|
|
end;
|
|
|
|
function TPascalParser.Parse_LambdaExpression: Integer;
|
|
var
|
|
I, Id, RefId, ClassId, SubId: Integer;
|
|
ClsName, ObjName: String;
|
|
begin
|
|
NewAnonymousNames(ClsName, ObjName);
|
|
GenComment('BEGIN OF ANONYMOUS CLASS ' + ClsName);
|
|
|
|
TypeParams.Clear;
|
|
|
|
ClassId := NewTempVar;
|
|
SetName(ClassId, ClsName);
|
|
BeginClassType(ClassId);
|
|
SetPacked(ClassId);
|
|
SetAncestorId(ClassId, H_TInterfacedObject);
|
|
|
|
GenDefaultConstructor(ClassId);
|
|
GenDefaultDestructor(ClassId);
|
|
|
|
SubId := NewTempVar;
|
|
Gen(OP_ASSIGN_LAMBDA_TYPES, SubId, 0, 0);
|
|
|
|
SetName(SubId, ANONYMOUS_METHOD_NAME);
|
|
BeginClassMethod(SubId,
|
|
ClassId,
|
|
true, // has result
|
|
false, // is shared
|
|
true); // is implementation
|
|
|
|
DECLARE_SWITCH := true;
|
|
Match('lambda');
|
|
|
|
Parse_LambdaParameters(SubId);
|
|
DECLARE_SWITCH := false;
|
|
|
|
Match('=>');
|
|
|
|
AnonymStack.Push(SubId);
|
|
try
|
|
InitSub(SubId);
|
|
Gen(OP_BEGIN_WITH, CurrSelfId, 0, 0);
|
|
WithStack.Push(CurrSelfId);
|
|
Id := CurrResultId;
|
|
Gen(OP_ASSIGN, Id, Parse_Expression, Id);
|
|
Gen(OP_END_WITH, WithStack.Top, 0, 0);
|
|
WithStack.Pop;
|
|
EndSub(SubId);
|
|
|
|
for I := 0 to AnonymStack.Top.BindList.Count - 1 do
|
|
begin
|
|
Id := NewTempVar;
|
|
SetName(Id, GetName(AnonymStack.Top.BindList[I]));
|
|
SetLevel(Id, ClassId);
|
|
SetKind(Id, KindTYPE_FIELD);
|
|
SetVisibility(Id, cvPublic);
|
|
Gen(OP_ASSIGN_THE_SAME_TYPE, Id, AnonymStack.Top.BindList[I], 0);
|
|
end;
|
|
|
|
EndClassType(ClassId);
|
|
GenComment('END OF ANONYMOUS CLASS ' + ClsName);
|
|
Gen(OP_ADD_TYPEINFO, ClassId, 0, 0);
|
|
|
|
result := NewTempVar;
|
|
Gen(OP_DECLARE_LOCAL_VAR, CurrSubId, result, 0);
|
|
SetName(result, ObjName);
|
|
SetType(result, ClassId);
|
|
|
|
RefId := NewField('Create', result);
|
|
Gen(OP_FIELD, ClassId, RefId, RefId);
|
|
Gen(OP_ASSIGN, result, RefId, result);
|
|
|
|
for I := 0 to AnonymStack.Top.BindList.Count - 1 do
|
|
begin
|
|
RefId := NewField(GetName(AnonymStack.Top.BindList[I]), result);
|
|
Gen(OP_FIELD, result, RefId, RefId);
|
|
Gen(OP_ASSIGN, RefId, AnonymStack.Top.BindList[I], RefId);
|
|
end;
|
|
finally
|
|
AnonymStack.Pop;
|
|
end;
|
|
|
|
Gen(OP_ASSIGN_LAMBDA_TYPES, SubId, ClassId, result);
|
|
end;
|
|
|
|
function TPascalParser.Parse_LambdaParameters(SubId: Integer) : Integer;
|
|
var
|
|
ID: Integer;
|
|
begin
|
|
result := 0;
|
|
|
|
if not IsCurrText('(') then
|
|
repeat
|
|
Inc(result);
|
|
ID := Parse_FormalParameter;
|
|
Gen(OP_DECLARE_LOCAL_VAR, SubId, ID, 0);
|
|
SetCount(SubId, result);
|
|
if NotMatch(',') then
|
|
Exit;
|
|
until false;
|
|
|
|
Match('(');
|
|
if IsCurrText(')') then
|
|
begin
|
|
Match(')');
|
|
SetCount(SubId, result);
|
|
Exit;
|
|
end;
|
|
|
|
repeat
|
|
Inc(result);
|
|
ID := Parse_FormalParameter;
|
|
Gen(OP_DECLARE_LOCAL_VAR, SubId, ID, 0);
|
|
if NotMatch(',') then
|
|
break;
|
|
until false;
|
|
|
|
Match(')');
|
|
SetCount(SubId, result);
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_FunctionDeclaration(IsSharedMethod: Boolean = false);
|
|
var
|
|
SubId, TypeId, ForwardId: Integer;
|
|
DirectiveList: TIntegerList;
|
|
L: TIntegerList;
|
|
NotDeclared, WaitOverload: Boolean;
|
|
K: Integer;
|
|
begin
|
|
DECLARE_SWITCH := true;
|
|
K := 0;
|
|
BeginMethodDef;
|
|
try
|
|
|
|
NotDeclared := false;
|
|
WaitOverload := false;
|
|
|
|
if IsSharedMethod then
|
|
begin
|
|
ForwardId := ReadType;
|
|
|
|
if ForwardId = 0 then
|
|
CreateError(errUndeclaredIdentifier, [CurrToken.Text]);
|
|
|
|
Call_SCANNER;
|
|
DECLARE_SWITCH := true;
|
|
Scanner.CurrComment.AllowedDoComment := false;
|
|
Match('.');
|
|
SubId := Parse_Ident;
|
|
BeginClassMethod(SubId, ForwardId, true, true, true);
|
|
end
|
|
else
|
|
begin
|
|
ForwardId := ReadType;
|
|
|
|
if (ForwardId > 0) and (GetKind(ForwardId) = KindTYPE) then
|
|
begin
|
|
Call_SCANNER;
|
|
|
|
while GetNext2Text = '.' do
|
|
begin
|
|
Inc(K);
|
|
levelStack.Push(ForwardId);
|
|
ReadToken;
|
|
ForwardId := Lookup(CurrToken.Text, CurrLevel);
|
|
if ForwardId = 0 then
|
|
RaiseError(errUndeclaredIdentifier, [CurrToken.Text]);
|
|
ReadToken;
|
|
end;
|
|
|
|
DECLARE_SWITCH := true;
|
|
Scanner.CurrComment.AllowedDoComment := false;
|
|
Match('.');
|
|
SubId := Parse_Ident;
|
|
if Lookup(GetName(SubId), ForwardId) = 0 then
|
|
NotDeclared := true;
|
|
BeginClassMethod(SubId, ForwardId, true, false, true);
|
|
end
|
|
else
|
|
begin
|
|
if ForwardId > 0 then
|
|
if GetKind(ForwardId) in KindSUBS then
|
|
if not GetSymbolRec(ForwardId).IsForward then
|
|
if GetSymbolRec(ForwardId).OverCount = 0 then
|
|
RaiseError(errRedeclaredIdentifier, [CurrToken.Text])
|
|
else
|
|
WaitOverload := true;
|
|
|
|
SubId := NewVar(CurrToken.Text);
|
|
SetPosition(SubId, CurrToken.Position - 1);
|
|
Parse_Ident;
|
|
BeginSub(SubId);
|
|
end;
|
|
end;
|
|
|
|
Parse_FormalParameterList(SubId);
|
|
DECLARE_SWITCH := false;
|
|
|
|
if IsCurrText(';') then
|
|
begin
|
|
L := LookupForwardDeclarations(SubId);
|
|
if L = nil then
|
|
RaiseError(errUnsatisfiedForwardOrExternalDeclaration, [GetName(SubId)])
|
|
else
|
|
FreeAndNil(L);
|
|
end
|
|
else
|
|
begin
|
|
Match(':');
|
|
Parse_Attribute;
|
|
TypeID := Parse_Type;
|
|
Gen(OP_ASSIGN_TYPE, SubId, TypeID, 0);
|
|
Gen(OP_ASSIGN_TYPE, CurrResultId, TypeID, 0);
|
|
end;
|
|
|
|
DECLARE_SWITCH := true;
|
|
|
|
if IsCurrText(';') then
|
|
Match(';');
|
|
|
|
if NotDeclared then
|
|
CreateError(errUndeclaredIdentifier, [GetName(SubId)]);
|
|
|
|
DirectiveList := Parse_DirectiveList(SubId);
|
|
try
|
|
if DirectiveList.IndexOf(dirFORWARD) >= 0 then
|
|
begin
|
|
SetForward(SubId, true);
|
|
EndSub(SubId);
|
|
Exit;
|
|
end;
|
|
if WaitOverload then
|
|
if DirectiveList.IndexOf(dirOVERLOAD) = -1 then
|
|
CreateError(errOverloadExpected, [GetName(SubId)]);
|
|
finally
|
|
FreeAndNil(DirectiveList);
|
|
end;
|
|
|
|
if IsCurrText('external') then
|
|
begin
|
|
ParseExternalSub(SubId);
|
|
Exit;
|
|
end;
|
|
|
|
InitSub(SubId);
|
|
|
|
if ForwardId > 0 then
|
|
if not GetSymbolRec(ForwardId).IsForward then
|
|
CheckRedeclaredSub(SubId);
|
|
|
|
if InitFuncResult then
|
|
Gen(OP_CALL_DEFAULT_CONSTRUCTOR, CurrResultId, 0, 0);
|
|
|
|
Parse_SubBlock;
|
|
EndSub(SubId);
|
|
|
|
EndMethodDef(SubId);
|
|
Match(';');
|
|
|
|
finally
|
|
|
|
while K > 0 do
|
|
begin
|
|
Dec(K);
|
|
levelStack.Pop;
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_OperatorDeclaration;
|
|
var
|
|
I, SubId, TypeId, ForwardId: Integer;
|
|
L: TIntegerList;
|
|
NotDeclared: Boolean;
|
|
begin
|
|
NotDeclared := false;
|
|
|
|
ReadToken;
|
|
ForwardId := Lookup(CurrToken.Text, CurrLevel);
|
|
if ForwardId = 0 then
|
|
CreateError(errUndeclaredIdentifier, [CurrToken.Text]);
|
|
|
|
Call_SCANNER;
|
|
DECLARE_SWITCH := true;
|
|
Match('.');
|
|
I := OperatorIndex(CurrToken.Text);
|
|
if I = -1 then
|
|
CreateError(errE2393, []);
|
|
// errE2393 = 'Invalid operator declaration';
|
|
SubId := Parse_Ident;
|
|
SetName(SubId, operators.Values[I]);
|
|
BeginStructureOperator(SubId, ForwardId);
|
|
|
|
Parse_FormalParameterList(SubId);
|
|
DECLARE_SWITCH := false;
|
|
|
|
if IsCurrText(';') then
|
|
begin
|
|
L := LookupForwardDeclarations(SubId);
|
|
if L = nil then
|
|
RaiseError(errUnsatisfiedForwardOrExternalDeclaration, [GetName(SubId)])
|
|
else
|
|
FreeAndNil(L);
|
|
end
|
|
else
|
|
begin
|
|
Match(':');
|
|
Parse_Attribute;
|
|
TypeID := Parse_Type;
|
|
Gen(OP_ASSIGN_TYPE, SubId, TypeID, 0);
|
|
Gen(OP_ASSIGN_TYPE, CurrResultId, TypeID, 0);
|
|
end;
|
|
|
|
DECLARE_SWITCH := true;
|
|
Match(';');
|
|
|
|
if NotDeclared then
|
|
CreateError(errUndeclaredIdentifier, [GetName(SubId)]);
|
|
|
|
if IsCurrText('external') then
|
|
begin
|
|
ParseExternalSub(SubId);
|
|
Exit;
|
|
end;
|
|
|
|
InitSub(SubId);
|
|
|
|
if ForwardId > 0 then
|
|
if not GetSymbolRec(ForwardId).IsForward then
|
|
if not StrEql(GetName(SubId), pascal_Implicit) then
|
|
if not StrEql(GetName(SubId), pascal_Explicit) then
|
|
CheckRedeclaredSub(SubId);
|
|
|
|
Parse_SubBlock;
|
|
EndSub(SubId);
|
|
Match(';');
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_ConstructorDeclaration;
|
|
var
|
|
ClassTypeId, SubId, L: Integer;
|
|
DirectiveList: TIntegerList;
|
|
OldSubId: Integer;
|
|
K, ForwardId: Integer;
|
|
begin
|
|
DECLARE_SWITCH := true;
|
|
K := 0;
|
|
ClassTypeId := 0;
|
|
BeginMethodDef;
|
|
try
|
|
ForwardId := ReadType;
|
|
|
|
if (ForwardId > 0) and (GetKind(ForwardId) = KindTYPE) then
|
|
begin
|
|
Call_SCANNER;
|
|
|
|
while GetNext2Text = '.' do
|
|
begin
|
|
Inc(K);
|
|
levelStack.Push(ForwardId);
|
|
ReadToken;
|
|
ForwardId := Lookup(CurrToken.Text, CurrLevel);
|
|
if ForwardId = 0 then
|
|
RaiseError(errUndeclaredIdentifier, [CurrToken.Text]);
|
|
ReadToken;
|
|
end;
|
|
|
|
ClassTypeId := ForwardId;
|
|
DECLARE_SWITCH := true;
|
|
Match('.');
|
|
SubId := Parse_Ident;
|
|
if GetSymbolRec(ClassTypeId).FinalTypeId = typeRECORD then
|
|
BeginStructureConstructor(SubId, ClassTypeId)
|
|
else
|
|
BeginClassConstructor(SubId, ClassTypeId);
|
|
end
|
|
else
|
|
RaiseError(errUndeclaredIdentifier, [CurrToken.Text]);
|
|
|
|
Parse_FormalParameterList(SubId);
|
|
|
|
Inc(EXECUTABLE_SWITCH);
|
|
Match(';');
|
|
|
|
DirectiveList := Parse_DirectiveList(SubId);
|
|
if DirectiveList.IndexOf(dirFORWARD) >= 0 then
|
|
begin
|
|
SetForward(SubId, true);
|
|
EndSub(SubId);
|
|
FreeAndNil(DirectiveList);
|
|
|
|
Dec(EXECUTABLE_SWITCH);
|
|
Exit;
|
|
end;
|
|
FreeAndNil(DirectiveList);
|
|
|
|
OldSubId := SubId;
|
|
InitSub(SubId);
|
|
|
|
if OldSubId = SubId then
|
|
RaiseError(errUndeclaredIdentifier, [GetName(OldSubId)]);
|
|
|
|
if GetSymbolRec(ClassTypeId).FinalTypeId = typeRECORD then
|
|
begin
|
|
Parse_SubBlock;
|
|
end
|
|
else
|
|
begin
|
|
|
|
WasInherited := false;
|
|
|
|
Gen(OP_SAVE_EDX, 0, 0, 0);
|
|
L := NewLabel;
|
|
Gen(OP_GO_DL, L, 0, 0);
|
|
Gen(OP_CREATE_OBJECT, ClassTypeId, 0, CurrSelfId);
|
|
SetLabelHere(L);
|
|
|
|
Parse_SubBlock;
|
|
|
|
// if not WasInherited then
|
|
// CreateError(errTheCallOfInheritedConstructorIsMandatory, []);
|
|
|
|
Gen(OP_RESTORE_EDX, 0, 0, 0);
|
|
L := NewLabel;
|
|
Gen(OP_GO_DL, L, 0, 0);
|
|
Gen(OP_ON_AFTER_OBJECT_CREATION, CurrSelfId, 0, 0);
|
|
SetLabelHere(L);
|
|
end;
|
|
|
|
EndSub(SubId);
|
|
|
|
Dec(EXECUTABLE_SWITCH);
|
|
|
|
EndMethodDef(SubId);
|
|
Match(';');
|
|
|
|
finally
|
|
|
|
while K > 0 do
|
|
begin
|
|
Dec(K);
|
|
levelStack.Pop;
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_DestructorDeclaration;
|
|
var
|
|
ClassTypeId, SubId, NP: Integer;
|
|
DirectiveList: TIntegerList;
|
|
OldSubId: Integer;
|
|
K: Integer;
|
|
begin
|
|
DECLARE_SWITCH := true;
|
|
K := 0;
|
|
BeginMethodDef;
|
|
try
|
|
|
|
ClassTypeId := ReadType;
|
|
|
|
if (ClassTypeId > 0) and (GetKind(ClassTypeId) = KindTYPE) then
|
|
begin
|
|
Call_SCANNER;
|
|
|
|
while GetNext2Text = '.' do
|
|
begin
|
|
Inc(K);
|
|
levelStack.Push(ClassTypeId);
|
|
ReadToken;
|
|
ClassTypeId := Lookup(CurrToken.Text, CurrLevel);
|
|
if ClassTypeId = 0 then
|
|
RaiseError(errUndeclaredIdentifier, [CurrToken.Text]);
|
|
ReadToken;
|
|
end;
|
|
|
|
DECLARE_SWITCH := true;
|
|
Match('.');
|
|
SubId := Parse_Ident;
|
|
BeginClassDestructor(SubId, ClassTypeId);
|
|
end
|
|
else
|
|
RaiseError(errUndeclaredIdentifier, [CurrToken.Text]);
|
|
|
|
NP := 0;
|
|
if IsCurrText('(') then
|
|
begin
|
|
Call_SCANNER;
|
|
Match(')');
|
|
end;
|
|
|
|
SetCount(SubId, NP);
|
|
|
|
Inc(EXECUTABLE_SWITCH);
|
|
Match(';');
|
|
|
|
DirectiveList := Parse_DirectiveList(SubId);
|
|
if DirectiveList.IndexOf(dirFORWARD) >= 0 then
|
|
begin
|
|
SetForward(SubId, true);
|
|
EndSub(SubId);
|
|
FreeAndNil(DirectiveList);
|
|
|
|
Dec(EXECUTABLE_SWITCH);
|
|
Exit;
|
|
end;
|
|
FreeAndNil(DirectiveList);
|
|
|
|
OldSubId := SubId;
|
|
InitSub(SubId);
|
|
|
|
if OldSubId = SubId then
|
|
RaiseError(errUndeclaredIdentifier, [GetName(OldSubId)]);
|
|
|
|
Parse_SubBlock;
|
|
EndSub(SubId);
|
|
|
|
Dec(EXECUTABLE_SWITCH);
|
|
EndMethodDef(SubId);
|
|
Match(';');
|
|
|
|
finally
|
|
|
|
while K > 0 do
|
|
begin
|
|
Dec(K);
|
|
levelStack.Pop;
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
// STATEMENTS
|
|
|
|
procedure TPascalParser.Parse_CompoundStmt;
|
|
begin
|
|
Inc(EXECUTABLE_SWITCH);
|
|
DECLARE_SWITCH := false;
|
|
Match('begin');
|
|
Parse_StmtList;
|
|
Match('end');
|
|
Dec(EXECUTABLE_SWITCH);
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_StmtList;
|
|
begin
|
|
DECLARE_SWITCH := false;
|
|
repeat
|
|
if IsEOF then
|
|
break;
|
|
if IsCurrText('end') then
|
|
break;
|
|
if IsCurrText('finalization') then
|
|
break;
|
|
Parse_Statement;
|
|
if NotMatch(';') then break;
|
|
until false;
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_AssignmentStmt;
|
|
var
|
|
I, LeftID, RightId, SizeId, SubId, L, ID1, ID2: Integer;
|
|
R: TCodeRec;
|
|
Lst: TIntegerList;
|
|
// SignProp: Boolean;
|
|
K1: Integer;
|
|
begin
|
|
if IsCurrText('inherited') then
|
|
begin
|
|
Call_SCANNER;
|
|
LeftId := NewTempVar;
|
|
if IsCurrText(';') or IsCurrText('else') then
|
|
begin
|
|
SubId := CurrLevel;
|
|
L := NewTempVar;
|
|
SetName(L, GetName(SubId));
|
|
Gen(OP_EVAL, 0, 0, L);
|
|
Gen(OP_EVAL_INHERITED, L, 0, LeftId);
|
|
for I:=0 to GetCount(SubId) - 1 do
|
|
Gen(OP_PUSH, GetParamId(SubId, I), I, LeftId);
|
|
Gen(OP_CALL_INHERITED, LeftID, 0, 0);
|
|
end
|
|
else
|
|
begin
|
|
L := Parse_Ident;
|
|
|
|
if IsCurrText('[') then
|
|
begin
|
|
// SignProp := true;
|
|
RemoveInstruction(OP_EVAL, -1, -1, L);
|
|
end
|
|
else
|
|
begin
|
|
RemoveInstruction(OP_EVAL, -1, -1, L);
|
|
// SignProp := false;
|
|
end;
|
|
|
|
Gen(OP_EVAL_INHERITED, L, 0, LeftId);
|
|
if IsCurrText('(') or IsCurrText('[') then
|
|
Gen(OP_CALL_INHERITED, LeftID, Parse_ArgumentList(LeftId), 0)
|
|
else
|
|
Gen(OP_CALL_INHERITED, LeftID, 0, 0);
|
|
|
|
// if SignProp then
|
|
if IsCurrText(':=') then
|
|
begin
|
|
K1 := CodeCard;
|
|
Call_SCANNER;
|
|
Gen(OP_PUSH, Parse_Expression, GetCodeRec(K1).Arg2, LeftId);
|
|
GetCodeRec(K1).Arg2 := GetCodeRec(K1).Arg2 + 1;
|
|
Gen(OP_CALL, LeftId, GetCodeRec(K1).Arg2, 0);
|
|
GetCodeRec(K1).Op := OP_NOP;
|
|
Exit;
|
|
end;
|
|
|
|
end;
|
|
if GetKind(CurrSubId) = kindCONSTRUCTOR then
|
|
begin
|
|
Gen(OP_RESTORE_EDX, 0, 0, 0);
|
|
|
|
L := NewLabel;
|
|
Gen(OP_GO_DL, L, 0, 0);
|
|
Gen(OP_ONCREATE_OBJECT, CurrSelfId, 0, 0);
|
|
SetLabelHere(L);
|
|
|
|
Gen(OP_SAVE_EDX, 0, 0, 0);
|
|
|
|
WasInherited := true;
|
|
end;
|
|
Exit;
|
|
end
|
|
else if IsCurrText('Include') and (not InScope('Include')) then
|
|
begin
|
|
RemoveInstruction(OP_EVAL, -1, -1, -1);
|
|
Call_SCANNER;
|
|
Match('(');
|
|
ID1 := Parse_Expression;
|
|
Match(',');
|
|
ID2 := Parse_Expression;
|
|
Match(')');
|
|
Gen(OP_SET_INCLUDE, ID1, ID2, 0);
|
|
Exit;
|
|
end
|
|
else if IsCurrText('Exclude') and (not InScope('Exclude')) then
|
|
begin
|
|
RemoveInstruction(OP_EVAL, -1, -1, -1);
|
|
Call_SCANNER;
|
|
Match('(');
|
|
ID1 := Parse_Expression;
|
|
Match(',');
|
|
ID2 := Parse_Expression;
|
|
Match(')');
|
|
Gen(OP_SET_EXCLUDE, ID1, ID2, 0);
|
|
Exit;
|
|
end
|
|
else if IsCurrText('inc') and (not InScope('inc')) then
|
|
begin
|
|
Call_SCANNER;
|
|
if not IsCurrText('(') then
|
|
RaiseError(errTokenExpected, ['(', CurrToken.Text]);
|
|
Push_SCANNER;
|
|
Call_SCANNER;
|
|
ID1 := Parse_Designator;
|
|
Pop_SCANNER;
|
|
Call_SCANNER;
|
|
ID2 := Parse_Designator;
|
|
if IsCurrText(',') then
|
|
begin
|
|
Call_SCANNER;
|
|
Gen(OP_INC, ID2, Parse_Expression, ID1);
|
|
end
|
|
else
|
|
Gen(OP_INC, ID2, NewConst(typeINTEGER, 1), ID1);
|
|
Match(')');
|
|
|
|
Exit;
|
|
end
|
|
else if IsCurrText('dec') and (not InScope('dec')) then
|
|
begin
|
|
Call_SCANNER;
|
|
if not IsCurrText('(') then
|
|
RaiseError(errTokenExpected, ['(', CurrToken.Text]);
|
|
Push_SCANNER;
|
|
Call_SCANNER;
|
|
ID1 := Parse_Designator;
|
|
Pop_SCANNER;
|
|
Call_SCANNER;
|
|
ID2 := Parse_Designator;
|
|
if IsCurrText(',') then
|
|
begin
|
|
Call_SCANNER;
|
|
Gen(OP_DEC, ID2, Parse_Expression, ID1);
|
|
end
|
|
else
|
|
Gen(OP_DEC, ID2, NewConst(typeINTEGER, 1), ID1);
|
|
Match(')');
|
|
|
|
Exit;
|
|
end
|
|
else if IsCurrText('SetLength') and (not InScope('SetLength')) then
|
|
begin
|
|
Lst := TIntegerList.Create;
|
|
try
|
|
Call_SCANNER;
|
|
Match('(');
|
|
LeftID := Parse_Designator;
|
|
|
|
Call_SCANNER;
|
|
repeat
|
|
Lst.Add(Parse_Expression);
|
|
if NotMatch(',') then
|
|
break;
|
|
until false;
|
|
|
|
if Lst.Count = 1 then
|
|
Gen(OP_SET_LENGTH, LeftID, Lst[0], 0)
|
|
else
|
|
begin
|
|
for I := 0 to Lst.Count - 1 do
|
|
Gen(OP_PUSH_LENGTH, Lst[I], 0, 0);
|
|
Gen(OP_SET_LENGTH_EX, LeftID, Lst.Count, 0);
|
|
end;
|
|
|
|
Match(')');
|
|
finally
|
|
FreeAndNil(Lst);
|
|
end;
|
|
Exit;
|
|
end
|
|
else if IsCurrText('str') and (not InScope('str')) then
|
|
begin
|
|
LeftID := NewTempVar;
|
|
|
|
Call_SCANNER;
|
|
Match('(');
|
|
|
|
try
|
|
|
|
Gen(OP_PUSH, Parse_Expression, 3, LeftID);
|
|
|
|
if IsCurrText(':') then
|
|
begin
|
|
Call_SCANNER;
|
|
Gen(OP_PUSH, Parse_Expression, 2, LeftID);
|
|
end
|
|
else
|
|
Gen(OP_PUSH, NewConst(typeINTEGER, 0), 2, LeftID);
|
|
|
|
if IsCurrText(':') then
|
|
begin
|
|
Call_SCANNER;
|
|
Gen(OP_PUSH, Parse_Expression, 1, LeftID);
|
|
end
|
|
else
|
|
Gen(OP_PUSH, NewConst(typeINTEGER, 0), 1, LeftID);
|
|
|
|
Match(',');
|
|
Gen(OP_PUSH, Parse_Expression, 0, LeftID);
|
|
|
|
finally
|
|
Gen(OP_STR, LeftID, 0, 0);
|
|
end;
|
|
|
|
Match(')');
|
|
Exit;
|
|
end
|
|
else if IsCurrText('new') and (not InScope('new')) then
|
|
begin
|
|
SetCompletionTarget('new');
|
|
|
|
Call_SCANNER;
|
|
|
|
Match('(');
|
|
LeftId := Parse_Designator;
|
|
SizeId := NewTempVar;
|
|
SubId := NewTempVar;
|
|
SetName(SubId, 'GetMem');
|
|
SetKind(SubId, kindNONE);
|
|
Gen(OP_EVAL, 0, 0, SubId);
|
|
Gen(OP_SIZEOF, LeftId, 0, SizeId);
|
|
Gen(OP_PUSH, LeftId, 0, SubId);
|
|
Gen(OP_PUSH, SizeId, 1, SubId);
|
|
Gen(OP_CALL, SubId, 0, 0);
|
|
Match(')');
|
|
Exit;
|
|
end
|
|
else if IsCurrText('dispose') and (not InScope('dispose')) then
|
|
begin
|
|
SetCompletionTarget('Dispose');
|
|
|
|
Call_SCANNER;
|
|
Match('(');
|
|
LeftId := Parse_Designator;
|
|
SizeId := NewTempVar;
|
|
SubId := NewTempVar;
|
|
SetName(SubId, 'FreeMem');
|
|
SetKind(SubId, kindNONE);
|
|
Gen(OP_EVAL, 0, 0, SubId);
|
|
Gen(OP_SIZEOF, LeftId, 0, SizeId);
|
|
Gen(OP_PUSH, LeftId, 0, SubId);
|
|
Gen(OP_PUSH, SizeId, 1, SubId);
|
|
Gen(OP_CALL, SubId, 0, 0);
|
|
Match(')');
|
|
Exit;
|
|
end
|
|
else if IsCurrText('pause') and (not InScope('pause')) then
|
|
begin
|
|
Call_SCANNER;
|
|
if IsCurrText('(') then
|
|
begin
|
|
Match('(');
|
|
Match(')');
|
|
end;
|
|
L := NewLabel;
|
|
Gen(OP_PAUSE, L, 0, 0);
|
|
SetLabelHere(L);
|
|
Exit;
|
|
end
|
|
else if IsCurrText('halt') or IsCurrText('abort') then
|
|
begin
|
|
Call_SCANNER;
|
|
if IsCurrText('(') then
|
|
begin
|
|
Match('(');
|
|
if not IsCurrText(')') then
|
|
begin
|
|
Gen(OP_HALT, Parse_ConstantExpression, 0, 0);
|
|
end
|
|
else
|
|
Gen(OP_HALT, NewConst(typeINTEGER, 0), 0, 0);
|
|
Match(')');
|
|
end
|
|
else
|
|
Gen(OP_HALT, NewConst(typeINTEGER, 0), 0, 0);
|
|
Exit;
|
|
end;
|
|
|
|
if IsCurrText('(') then
|
|
LeftID := Parse_Factor
|
|
else
|
|
LeftID := Parse_SimpleExpression;
|
|
|
|
if IsEOF then
|
|
Exit;
|
|
|
|
if IsCurrText(';') or (CurrToken.TokenClass = tcKeyword) then
|
|
begin
|
|
R := LastCodeRec;
|
|
if R.Op = OP_CALL then
|
|
begin
|
|
SetKind(R.Res, KindNONE);
|
|
R.Res := 0;
|
|
end
|
|
else if GetKind(LeftId) = kindCONST then
|
|
RaiseError(errIdentifierExpectedNoArgs, [])
|
|
else
|
|
begin
|
|
{$IFDEF CPP_SYN}
|
|
if (R.Arg1 = LeftId) and (R.Op = OP_ASSIGN) then
|
|
begin
|
|
if (LastCodeRec2.Op = OP_PLUS) or (LastCodeRec2.Op = OP_MINUS) then
|
|
Exit;
|
|
end
|
|
else if R.Op = OP_POSTFIX_EXPRESSION then
|
|
Exit;
|
|
{$ENDIF}
|
|
Gen(OP_CALL, LeftID, 0, 0);
|
|
end;
|
|
Exit;
|
|
end;
|
|
|
|
Gen(OP_LVALUE, LeftId, 0, 0);
|
|
|
|
if IsCurrText(':=') then
|
|
begin
|
|
Call_SCANNER;
|
|
RightId := Parse_Expression;
|
|
Gen(OP_ASSIGN, LeftID, RightId, LeftID);
|
|
end
|
|
{$IFDEF CPP_SYN}
|
|
else if IsCurrText('+=') then
|
|
begin
|
|
Call_SCANNER;
|
|
ID1 := NewTempVar;
|
|
Gen(OP_PLUS, LeftId, Parse_Expression, ID1);
|
|
Gen(OP_ASSIGN, LeftId, ID1, LeftId);
|
|
end
|
|
else if IsCurrText('-=') then
|
|
begin
|
|
Call_SCANNER;
|
|
ID1 := NewTempVar;
|
|
Gen(OP_MINUS, LeftId, Parse_Expression, ID1);
|
|
Gen(OP_ASSIGN, LeftId, ID1, LeftId);
|
|
end
|
|
else if IsCurrText('*=') then
|
|
begin
|
|
Call_SCANNER;
|
|
ID1 := NewTempVar;
|
|
Gen(OP_MULT, LeftId, Parse_Expression, ID1);
|
|
Gen(OP_ASSIGN, LeftId, ID1, LeftId);
|
|
end
|
|
else if IsCurrText('/=') then
|
|
begin
|
|
Call_SCANNER;
|
|
ID1 := NewTempVar;
|
|
Gen(OP_DIV, LeftId, Parse_Expression, ID1);
|
|
Gen(OP_ASSIGN, LeftId, ID1, LeftId);
|
|
end
|
|
else if IsCurrText('~=') then
|
|
begin
|
|
Call_SCANNER;
|
|
ID1 := NewTempVar;
|
|
Gen(OP_IDIV, LeftId, Parse_Expression, ID1);
|
|
Gen(OP_ASSIGN, LeftId, ID1, LeftId);
|
|
end
|
|
else if IsCurrText('%=') then
|
|
begin
|
|
Call_SCANNER;
|
|
ID1 := NewTempVar;
|
|
Gen(OP_MOD, LeftId, Parse_Expression, ID1);
|
|
Gen(OP_ASSIGN, LeftId, ID1, LeftId);
|
|
end
|
|
else if IsCurrText('^=') then
|
|
begin
|
|
Call_SCANNER;
|
|
ID1 := NewTempVar;
|
|
Gen(OP_XOR, LeftId, Parse_Expression, ID1);
|
|
Gen(OP_ASSIGN, LeftId, ID1, LeftId);
|
|
end
|
|
else if IsCurrText('|=') then
|
|
begin
|
|
Call_SCANNER;
|
|
ID1 := NewTempVar;
|
|
Gen(OP_OR, LeftId, Parse_Expression, ID1);
|
|
Gen(OP_ASSIGN, LeftId, ID1, LeftId);
|
|
end
|
|
else if IsCurrText('&=') then
|
|
begin
|
|
Call_SCANNER;
|
|
ID1 := NewTempVar;
|
|
Gen(OP_AND, LeftId, Parse_Expression, ID1);
|
|
Gen(OP_ASSIGN, LeftId, ID1, LeftId);
|
|
end
|
|
{$ENDIF}
|
|
else if IsCurrText('(') then
|
|
begin
|
|
R := Gen(OP_CALL, LeftID, Parse_ArgumentList(LeftId), 0);
|
|
|
|
if IsCurrText(':=') then
|
|
begin
|
|
R.Res := NewTempVar;
|
|
Call_SCANNER;
|
|
Gen(OP_ASSIGN, R.Res, Parse_Expression, R.Res);
|
|
end
|
|
else if IsCurrText('(') then
|
|
begin
|
|
R.Res := NewTempVar;
|
|
Gen(OP_CALL, R.Res, Parse_ArgumentList(R.Res), 0);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
Gen(OP_CALL, LeftID, 0, 0);
|
|
end;
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_CaseStmt;
|
|
var
|
|
lg, lf, lt, lc, id, expr1_id, cond_id: Integer;
|
|
begin
|
|
Match('case');
|
|
lg := NewLabel;
|
|
cond_id := NewTempVar;
|
|
id := NewTempVar;
|
|
Gen(OP_ASSIGN, Id, Parse_Expression, id);
|
|
Match('of');
|
|
repeat
|
|
// Parse case selector
|
|
lt := NewLabel;
|
|
lf := NewLabel;
|
|
repeat
|
|
lc := NewLabel;
|
|
expr1_id := Parse_ConstantExpression;
|
|
|
|
if IsCurrText('..') then
|
|
begin
|
|
Gen(OP_GE, id, expr1_id, cond_id);
|
|
Gen(OP_GO_FALSE, lc, cond_id, 0);
|
|
Match('..');
|
|
Gen(OP_LE, id, Parse_ConstantExpression, cond_id);
|
|
Gen(OP_GO_FALSE, lc, cond_id, 0);
|
|
end
|
|
else
|
|
Gen(OP_EQ, id, expr1_id, cond_id);
|
|
Gen(OP_GO_TRUE, lt, cond_id, 0);
|
|
SetLabelHere(lc);
|
|
|
|
if NotMatch(',') then
|
|
break;
|
|
until false;
|
|
Gen(OP_GO, lf, 0, 0);
|
|
SetLabelHere(lt);
|
|
Match(':');
|
|
if IsCurrText(';') then
|
|
begin
|
|
end
|
|
else
|
|
Parse_Statement;
|
|
Gen(OP_GO, lg, 0, 0);
|
|
SetLabelHere(lf);
|
|
// end of case selector
|
|
if NotMatch(';') then
|
|
Break;
|
|
if IsCurrText('else') then
|
|
break;
|
|
if IsCurrText('end') then
|
|
break;
|
|
until false;
|
|
if IsCurrText('else') then
|
|
begin
|
|
Match('else');
|
|
Parse_StmtList;
|
|
end;
|
|
if IsCurrText(';') then
|
|
Match(';');
|
|
Match('end');
|
|
SetLabelHere(lg);
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_IfStmt;
|
|
var
|
|
lf, lg: Integer;
|
|
begin
|
|
Match('if');
|
|
lf := NewLabel;
|
|
Gen(OP_GO_FALSE, lf, Parse_Expression, 0);
|
|
Match('then');
|
|
if not IsCurrText('else') then
|
|
Parse_Statement;
|
|
if IsCurrText('else') then
|
|
begin
|
|
Gen(OP_NOP, 0, 0, 0);
|
|
lg := NewLabel();
|
|
Gen(OP_GO, lg, 0, 0);
|
|
SetLabelHere(lf);
|
|
Match('else');
|
|
Parse_Statement;
|
|
SetLabelHere(lg);
|
|
end
|
|
else
|
|
SetLabelHere(lf);
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_GotoStmt;
|
|
begin
|
|
Match('goto');
|
|
Gen(OP_GO, Parse_Label, 0, 0);
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_BreakStmt;
|
|
begin
|
|
if BreakStack.Count = 0 then
|
|
RaiseError(errBreakOrContinueOutsideOfLoop, []);
|
|
Match('break');
|
|
if IsCurrText('(') then
|
|
begin
|
|
Match('(');
|
|
Match(')');
|
|
end;
|
|
if not SupportedSEH then
|
|
Gen(OP_GO, BreakStack.TopLabel, 0, 0)
|
|
else
|
|
begin
|
|
if IsTryContext(BreakStack.Top) then
|
|
Gen(OP_EXIT, BreakStack.TopLabel, Integer(emBreak), CurrLevel)
|
|
else
|
|
Gen(OP_GO, BreakStack.TopLabel, 0, 0);
|
|
end;
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_ContinueStmt;
|
|
begin
|
|
if ContinueStack.Count = 0 then
|
|
RaiseError(errBreakOrContinueOutsideOfLoop, []);
|
|
Match('continue');
|
|
if IsCurrText('(') then
|
|
begin
|
|
Match('(');
|
|
Match(')');
|
|
end;
|
|
if not SupportedSEH then
|
|
Gen(OP_GO, ContinueStack.TopLabel, 0, 0)
|
|
else
|
|
begin
|
|
if IsTryContext(ContinueStack.Top) then
|
|
Gen(OP_EXIT, ContinueStack.TopLabel, Integer(emContinue), CurrLevel)
|
|
else
|
|
Gen(OP_GO, ContinueStack.TopLabel, 0, 0);
|
|
end;
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_ExitStmt;
|
|
begin
|
|
Match('exit');
|
|
if IsCurrText('(') then
|
|
begin
|
|
Match('(');
|
|
Match(')');
|
|
end;
|
|
if not SupportedSEH then
|
|
Gen(OP_GO, SkipLabelStack.Top, 0, CurrLevel)
|
|
else
|
|
Gen(OP_EXIT, SkipLabelStack.Top, 0, CurrLevel);
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_WhileStmt;
|
|
var
|
|
lf, lg, l_loop: Integer;
|
|
begin
|
|
Match('while');
|
|
lf := NewLabel;
|
|
lg := NewLabel;
|
|
SetLabelHere(lg);
|
|
l_loop := lg;
|
|
Gen(OP_GO_FALSE, lf, Parse_Expression, 0);
|
|
Match('do');
|
|
|
|
Parse_LoopStmt(lf, lg, l_loop);
|
|
|
|
Gen(OP_GO, lg, 0, 0);
|
|
SetLabelHere(lf);
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_RepeatStmt;
|
|
var
|
|
lf, lg, l_loop: Integer;
|
|
begin
|
|
Match('repeat');
|
|
lf := NewLabel;
|
|
lg := NewLabel;
|
|
SetLabelHere(lf);
|
|
l_loop := lf;
|
|
repeat
|
|
if IsCurrText('until') then
|
|
Break;
|
|
if IsEOF then
|
|
Break;
|
|
|
|
Parse_LoopStmt(lg, lf, l_loop);
|
|
|
|
if NotMatch(';') then
|
|
Break;
|
|
|
|
until false;
|
|
Match('until');
|
|
Gen(OP_GO_FALSE, lf, Parse_Expression, 0);
|
|
SetLabelHere(lg);
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_ForStmt;
|
|
var
|
|
id, expr1_id, expr2_id, limit_cond_id1, limit_cond_id2: Integer;
|
|
i, compound: Boolean;
|
|
lf, lg, lc, l_loop: Integer;
|
|
|
|
element_id, collection_id, enumerator_id, bool_id: Integer;
|
|
begin
|
|
l_loop := NewLabel;
|
|
SetLabelHere(l_loop);
|
|
Match('for');
|
|
if IsNextText('in') then
|
|
begin
|
|
Inc(ForInCounter);
|
|
lf := NewLabel;
|
|
lg := NewLabel;
|
|
lc := NewLabel;
|
|
enumerator_id := NewTempVar;
|
|
bool_id := NewTempVar;
|
|
element_id := Parse_Ident;
|
|
Match('in');
|
|
collection_id := Parse_Expression;
|
|
Match('do');
|
|
Gen(OP_LOCK_VARRAY, collection_id, ForInCounter, 0);
|
|
Gen(OP_GET_ENUMERATOR, collection_id, ForInCounter, enumerator_id);
|
|
SetLabelHere(lg);
|
|
Gen(OP_CURRENT, enumerator_id, ForInCounter, element_id);
|
|
|
|
compound := Parse_LoopStmt(lf, lc, l_loop);
|
|
|
|
SetLabelHere(lc, ForInCounter);
|
|
if not compound then
|
|
GenPause;
|
|
Gen(OP_MOVE_NEXT, element_id, ForInCounter, bool_id);
|
|
Gen(OP_GO_FALSE, lf, bool_id, 0);
|
|
Gen(OP_GO, lg, 0, 0);
|
|
SetLabelHere(lf, 0, ForInCounter);
|
|
Gen(OP_UNLOCK_VARRAY, collection_id, ForInCounter, 0);
|
|
Exit;
|
|
end;
|
|
|
|
lf := NewLabel;
|
|
lg := NewLabel;
|
|
lc := NewLabel;
|
|
limit_cond_id1 := NewTempVar;
|
|
limit_cond_id2 := NewTempVar;
|
|
expr1_id := NewTempVar;
|
|
expr2_id := NewTempVar;
|
|
id := Parse_Ident;
|
|
Match(':=');
|
|
Gen(OP_ASSIGN, expr1_id, Parse_Expression, expr1_id);
|
|
Gen(OP_ASSIGN, id, expr1_id, id);
|
|
if IsCurrText('downto') then
|
|
begin
|
|
Match('downto');
|
|
Gen(OP_ASSIGN, expr2_id, Parse_Expression, expr2_id);
|
|
Gen(OP_LT, id, expr2_id, limit_cond_id1);
|
|
i := false;
|
|
end
|
|
else
|
|
begin
|
|
Match('to');
|
|
Gen(OP_ASSIGN, expr2_id, Parse_Expression, expr2_id);
|
|
Gen(OP_GT, id, expr2_id, limit_cond_id1);
|
|
i := true;
|
|
end;
|
|
Gen(OP_GO_TRUE, lg, limit_cond_id1, 0);
|
|
Match('do');
|
|
SetLabelHere(lf);
|
|
|
|
compound := Parse_LoopStmt(lg, lc, l_loop);
|
|
|
|
SetLabelHere(lc);
|
|
if i then
|
|
begin
|
|
Gen(OP_INC, id, NewConst(typeINTEGER, 1), id);
|
|
Gen(OP_GT, id, expr2_id, limit_cond_id2);
|
|
end
|
|
else
|
|
begin
|
|
Gen(OP_DEC, id, NewConst(typeINTEGER, 1), id);
|
|
Gen(OP_LT, id, expr2_id, limit_cond_id2);
|
|
end;
|
|
if not compound then
|
|
GenPause;
|
|
Gen(OP_GO_FALSE, lf, limit_cond_id2, 0);
|
|
SetLabelHere(lg);
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_WithStmt;
|
|
var
|
|
id, K: Integer;
|
|
begin
|
|
K := WithStack.Count;
|
|
Match('with');
|
|
repeat
|
|
id := Parse_Expression;
|
|
Gen(OP_BEGIN_WITH, id, 0, 0);
|
|
WithStack.Push(id);
|
|
if NotMatch(',') then
|
|
Break;
|
|
until false;
|
|
Match('do');
|
|
Parse_Statement;
|
|
|
|
while WithStack.Count > K do
|
|
begin
|
|
id := WithStack.Top;
|
|
Gen(OP_END_WITH, id, 0, 0);
|
|
WithStack.Pop;
|
|
end;
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_TryStmt;
|
|
var
|
|
id, type_id, l_try, BlockId: Integer;
|
|
begin
|
|
if not SupportedSEH then
|
|
RaiseError(errTryExceptNotImplemented, []);
|
|
|
|
l_try := GenBeginTry;
|
|
|
|
Match('try');
|
|
|
|
repeat
|
|
if IsCurrText('except') then
|
|
Break;
|
|
if IsCurrText('finally') then
|
|
Break;
|
|
if IsEOF then
|
|
Break;
|
|
Parse_Statement;
|
|
if NotMatch(';') then
|
|
Break;
|
|
until false;
|
|
|
|
Gen(OP_EXCEPT_SEH, 0, 0, 0);
|
|
|
|
if IsCurrText('except') then
|
|
begin
|
|
Gen(OP_GO, l_try, 0, 0);
|
|
GenExcept;
|
|
|
|
Call_SCANNER;
|
|
//ExceptionBlock
|
|
|
|
if IsCurrText('on') then
|
|
begin
|
|
while IsCurrText('on') do
|
|
begin
|
|
BlockId := NewTempVar;
|
|
LevelStack.push(BlockId);
|
|
Gen(OP_BEGIN_BLOCK, BlockId, 0, 0);
|
|
|
|
if IsNext2Text(':') then
|
|
begin
|
|
DECLARE_SWITCH := true;
|
|
Match('on');
|
|
id := Parse_Ident;
|
|
DECLARE_SWITCH := false;
|
|
Match(':');
|
|
type_id := Parse_Ident;
|
|
end
|
|
else
|
|
begin
|
|
DECLARE_SWITCH := false;
|
|
Match('on');
|
|
type_id := Parse_Ident;
|
|
id := NewTempVar;
|
|
end;
|
|
|
|
Gen(OP_ASSIGN_TYPE, id, type_id, 0);
|
|
|
|
GenExceptOn(type_id);
|
|
Gen(OP_ASSIGN, id, CurrExceptionObjectId, id);
|
|
|
|
Gen(OP_BEGIN_EXCEPT_BLOCK, 0, 0, 0);
|
|
Match('do');
|
|
Parse_Statement;
|
|
Gen(OP_END_EXCEPT_BLOCK, 0, 0, 0);
|
|
|
|
Gen(OP_GO, l_try, 0, 0);
|
|
|
|
Gen(OP_END_BLOCK, BlockId, 0, 0);
|
|
LevelStack.Pop;
|
|
if IsCurrText(';') then
|
|
Match(';');
|
|
end;
|
|
|
|
GenExceptOn(0);
|
|
|
|
if IsCurrText('else') then
|
|
begin
|
|
Gen(OP_BEGIN_EXCEPT_BLOCK, 0, 0, 0);
|
|
Call_SCANNER;
|
|
Parse_Statement;
|
|
|
|
if IsCurrText(';') then
|
|
Match(';');
|
|
Gen(OP_END_EXCEPT_BLOCK, 0, 0, 0);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
Gen(OP_BEGIN_EXCEPT_BLOCK, 0, 0, 0);
|
|
repeat
|
|
if IsCurrText('end') then
|
|
Break;
|
|
if IsEOF then
|
|
Break;
|
|
Parse_Statement;
|
|
if NotMatch(';') then
|
|
Break;
|
|
until false;
|
|
Gen(OP_END_EXCEPT_BLOCK, 0, 0, 0);
|
|
end;
|
|
end // except
|
|
else if IsCurrText('finally') then
|
|
begin
|
|
GenFinally;
|
|
Call_SCANNER;
|
|
repeat
|
|
if IsCurrText('end') then
|
|
Break;
|
|
if IsEOF then
|
|
Break;
|
|
Parse_Statement;
|
|
if NotMatch(';') then
|
|
Break;
|
|
until false;
|
|
GenCondRaise;
|
|
end // finally
|
|
else
|
|
Match('finally');
|
|
SetLabelHere(l_try);
|
|
GenEndTry;
|
|
Match('end');
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_RaiseStmt;
|
|
begin
|
|
if not SupportedSEH then
|
|
RaiseError(errRaiseNotImplemented, []);
|
|
|
|
Match('raise');
|
|
if IsCurrText(';') then
|
|
Gen(OP_RAISE, 0, RaiseMode, 0)
|
|
else
|
|
begin
|
|
Gen(OP_RAISE, Parse_Expression, RaiseMode, 0);
|
|
end;
|
|
end;
|
|
|
|
// EXPRESSIONS
|
|
|
|
function TPascalParser.Parse_ArgumentList(SubId: Integer): Integer;
|
|
var
|
|
I: Integer;
|
|
L: TIntegerList;
|
|
bracket: String;
|
|
begin
|
|
try
|
|
bracket := ')';
|
|
L := TIntegerList.Create;
|
|
try
|
|
if IsCurrText('(') then
|
|
begin
|
|
Match('(');
|
|
bracket := ')';
|
|
end
|
|
else if IsCurrText('[') then
|
|
begin
|
|
Match('[');
|
|
bracket := ']';
|
|
end
|
|
else
|
|
Match('(');
|
|
result := 0;
|
|
if (not IsCurrText(')')) then
|
|
begin
|
|
repeat
|
|
Inc(result);
|
|
L.Add(Parse_Expression);
|
|
if NotMatch(',') then
|
|
Break;
|
|
until false;
|
|
end;
|
|
|
|
for I:=0 to L.Count - 1 do
|
|
Gen(OP_PUSH, L[I], I, SubID);
|
|
|
|
Match(bracket);
|
|
finally
|
|
FreeAndNil(L);
|
|
end;
|
|
except
|
|
Gen(OP_CALL, SubId, 0, 0);
|
|
raise;
|
|
end;
|
|
end;
|
|
|
|
function TPascalParser.Parse_ConstantExpression: Integer;
|
|
begin
|
|
try
|
|
CONST_ONLY := true;
|
|
result := Parse_Expression;
|
|
finally
|
|
CONST_ONLY := false;
|
|
end;
|
|
end;
|
|
|
|
function TPascalParser.Parse_Expression: Integer;
|
|
var
|
|
Op: Integer;
|
|
begin
|
|
if IsCurrText('procedure') then
|
|
begin
|
|
result := Parse_AnonymousProcedure;
|
|
Exit;
|
|
end
|
|
else if IsCurrText('function') then
|
|
begin
|
|
result := Parse_AnonymousFunction;
|
|
Exit;
|
|
end
|
|
else if IsCurrText('lambda') then
|
|
begin
|
|
RemoveLastIdent(CurrToken.Id);
|
|
result := Parse_LambdaExpression;
|
|
Exit;
|
|
end;
|
|
|
|
result := Parse_SimpleExpression;
|
|
while (CurrToken.Id = OP_LT) or
|
|
(CurrToken.Id = OP_LE) or
|
|
(CurrToken.Id = OP_GT) or
|
|
(CurrToken.Id = OP_GE) or
|
|
(CurrToken.Id = OP_EQ) or
|
|
(CurrToken.Id = OP_NE) or
|
|
(CurrToken.Id = OP_IS) or
|
|
(CurrToken.Id = OP_AS) or
|
|
(CurrToken.Id = OP_SET_MEMBERSHIP) do
|
|
begin
|
|
Op := CurrToken.Id;
|
|
Call_SCANNER;
|
|
result := BinOp(Op, result, Parse_SimpleExpression);
|
|
end;
|
|
end;
|
|
|
|
function TPascalParser.Parse_SimpleExpression: Integer;
|
|
var
|
|
Op, L, I: Integer;
|
|
Lst: TCodeRecList;
|
|
R: TCodeRec;
|
|
begin
|
|
if CompleteBooleanEval then
|
|
begin
|
|
result := Parse_Term;
|
|
while IsCurrText('+') or
|
|
IsCurrText('-') or
|
|
IsCurrText('or') or
|
|
IsCurrText('xor') do
|
|
begin
|
|
Op := CurrToken.Id;
|
|
Call_SCANNER;
|
|
result := BinOp(Op, result, Parse_Term);
|
|
end;
|
|
Exit;
|
|
end;
|
|
|
|
L := 0;
|
|
Lst := TCodeRecList.Create;
|
|
try
|
|
result := Parse_Term;
|
|
while (CurrToken.Id = OP_PLUS) or
|
|
(CurrToken.Id = OP_MINUS) or
|
|
(CurrToken.Id = OP_OR) or
|
|
(CurrToken.Id = OP_XOR) do
|
|
begin
|
|
if (CurrToken.Id = OP_OR) and (Lst.Count = 0) then
|
|
L := NewLabel;
|
|
|
|
if CurrToken.Id = OP_OR then
|
|
begin
|
|
R := Gen(OP_ASSIGN, 0, result, 0);
|
|
Lst.Add(R);
|
|
Gen(OP_GO_TRUE_BOOL, L, result, 0);
|
|
end;
|
|
|
|
Op := CurrToken.Id;
|
|
Call_SCANNER;
|
|
result := BinOp(Op, result, Parse_Term);
|
|
end;
|
|
|
|
if Lst.Count > 0 then
|
|
begin
|
|
for I:=0 to Lst.Count - 1 do
|
|
begin
|
|
R := TCodeRec(Lst[I]);
|
|
R.Arg1 := result;
|
|
R.Res := result;
|
|
end;
|
|
SetLabelHere(L);
|
|
end;
|
|
finally
|
|
FreeAndNil(Lst);
|
|
end;
|
|
end;
|
|
|
|
function TPascalParser.Parse_Term: Integer;
|
|
var
|
|
Op, L, I: Integer;
|
|
Lst: TCodeRecList;
|
|
R: TCodeRec;
|
|
begin
|
|
if CompleteBooleanEval then
|
|
begin
|
|
result := Parse_Factor;
|
|
while (CurrToken.Id = OP_MULT) or
|
|
(CurrToken.Id = OP_DIV) or
|
|
(CurrToken.Id = OP_IDIV) or
|
|
(CurrToken.Id = OP_MOD) or
|
|
(CurrToken.Id = OP_SHL) or
|
|
(CurrToken.Id = OP_SHR) or
|
|
(CurrToken.Id = OP_AND) do
|
|
begin
|
|
Op := CurrToken.Id;
|
|
Call_SCANNER;
|
|
result := BinOp(Op, result, Parse_Factor);
|
|
end;
|
|
Exit;
|
|
end;
|
|
|
|
L := 0;
|
|
Lst := TCodeRecList.Create;
|
|
try
|
|
result := Parse_Factor;
|
|
while (CurrToken.Id = OP_MULT) or
|
|
(CurrToken.Id = OP_DIV) or
|
|
(CurrToken.Id = OP_IDIV) or
|
|
(CurrToken.Id = OP_MOD) or
|
|
(CurrToken.Id = OP_SHL) or
|
|
(CurrToken.Id = OP_SHR) or
|
|
(CurrToken.Id = OP_AND) do
|
|
begin
|
|
if (CurrToken.Id = OP_AND) and (Lst.Count = 0) then
|
|
L := NewLabel;
|
|
|
|
if CurrToken.Id = OP_AND then
|
|
begin
|
|
R := Gen(OP_ASSIGN, 0, result, 0);
|
|
Lst.Add(R);
|
|
Gen(OP_GO_FALSE_BOOL, L, result, 0);
|
|
end;
|
|
|
|
Op := CurrToken.Id;
|
|
Call_SCANNER;
|
|
result := BinOp(Op, result, Parse_Factor);
|
|
end;
|
|
|
|
if Lst.Count > 0 then
|
|
begin
|
|
for I:=0 to Lst.Count - 1 do
|
|
begin
|
|
R := TCodeRec(Lst[I]);
|
|
R.Arg1 := result;
|
|
R.Res := result;
|
|
end;
|
|
SetLabelHere(L);
|
|
end;
|
|
|
|
finally
|
|
FreeAndNil(Lst);
|
|
end;
|
|
end;
|
|
|
|
function TPascalParser.Parse_Factor: Integer;
|
|
var
|
|
SubId, K, Id: Integer;
|
|
ValidConst: Boolean;
|
|
{$IFDEF CPP_SYN}
|
|
temp, r: Integer;
|
|
{$ENDIF}
|
|
S: String;
|
|
v: Variant;
|
|
label
|
|
LabelDesignator;
|
|
begin
|
|
|
|
if CurrToken.TokenClass = tcBooleanConst then
|
|
begin
|
|
result := Parse_BooleanLiteral;
|
|
if IsCurrText('.') then
|
|
begin
|
|
if CONST_ONLY then
|
|
CreateError(errConstantExpressionExpected, []);
|
|
result := Parse_Designator(result);
|
|
end;
|
|
end
|
|
else if CurrToken.TokenClass = tcCharConst then
|
|
begin
|
|
result := Parse_CharLiteral;
|
|
if IsCurrText('.') then
|
|
begin
|
|
if CONST_ONLY then
|
|
CreateError(errConstantExpressionExpected, []);
|
|
result := Parse_Designator(result);
|
|
end;
|
|
end
|
|
else if CurrToken.TokenClass = tcPCharConst then
|
|
begin
|
|
result := Parse_PCharLiteral;
|
|
if IsCurrText('.') then
|
|
begin
|
|
if CONST_ONLY then
|
|
CreateError(errConstantExpressionExpected, []);
|
|
result := Parse_Designator(result);
|
|
end;
|
|
end
|
|
else if CurrToken.TokenClass = tcIntegerConst then
|
|
begin
|
|
result := Parse_IntegerLiteral;
|
|
if IsCurrText('.') then
|
|
begin
|
|
if CONST_ONLY then
|
|
CreateError(errConstantExpressionExpected, []);
|
|
result := Parse_Designator(result);
|
|
end;
|
|
end
|
|
else if CurrToken.TokenClass = tcDoubleConst then
|
|
begin
|
|
result := Parse_DoubleLiteral;
|
|
if IsCurrText('.') then
|
|
begin
|
|
if CONST_ONLY then
|
|
CreateError(errConstantExpressionExpected, []);
|
|
result := Parse_Designator(result);
|
|
end;
|
|
end
|
|
else if IsCurrText('+') then
|
|
begin
|
|
Call_SCANNER;
|
|
result := UnaryOp(OP_POSITIVE, Parse_Factor);
|
|
end
|
|
else if IsCurrText('-') then
|
|
begin
|
|
Call_SCANNER;
|
|
ValidConst := CurrToken.TokenClass in [tcIntegerConst, tcDoubleConst];
|
|
Id := Parse_Factor;
|
|
if ValidConst then
|
|
begin
|
|
result := Id;
|
|
v := GetValue(id);
|
|
if v > 0 then
|
|
SetValue(Id, - v);
|
|
end
|
|
else
|
|
result := UnaryOp(OP_NEG, Id);
|
|
end
|
|
{$IFDEF CPP_SYN}
|
|
else if IsCurrText('++') then
|
|
begin
|
|
if CONST_ONLY then
|
|
CreateError(errConstantExpressionExpected, []);
|
|
|
|
Call_SCANNER;
|
|
result := Parse_Expression;
|
|
Id := NewTempVar;
|
|
Gen(OP_PLUS, result, NewConst(typeINTEGER, 1), Id);
|
|
Gen(OP_ASSIGN, result, Id, result);
|
|
end
|
|
else if IsCurrText('--') then
|
|
begin
|
|
if CONST_ONLY then
|
|
CreateError(errConstantExpressionExpected, []);
|
|
|
|
Call_SCANNER;
|
|
result := Parse_Expression;
|
|
Id := NewTempVar;
|
|
Gen(OP_MINUS, result, NewConst(typeINTEGER, 1), Id);
|
|
Gen(OP_ASSIGN, result, Id, result);
|
|
end
|
|
{$ENDIF}
|
|
else if IsCurrText('*') then
|
|
begin
|
|
Call_SCANNER;
|
|
result := UnaryOp(OP_POSITIVE, Parse_Factor);
|
|
end
|
|
else if IsCurrText('not') then
|
|
begin
|
|
Call_SCANNER;
|
|
result := UnaryOp(OP_NOT, Parse_Factor);
|
|
end
|
|
else if IsCurrText('(') then
|
|
begin
|
|
Match('(');
|
|
result := Parse_Expression;
|
|
Match(')');
|
|
if IsCurrText('.') or IsCurrText('[') then
|
|
result := Parse_Designator(result);
|
|
end
|
|
else if IsCurrText('[') then
|
|
begin
|
|
result := Parse_SetConstructor;
|
|
end
|
|
else if IsCurrText('@') then
|
|
begin
|
|
Match('@');
|
|
result := NewTempVar;
|
|
Gen(OP_ADDRESS, Parse_Designator, 0, result);
|
|
end
|
|
else if IsCurrText('assigned') and (not InScope('assigned')) then
|
|
begin
|
|
if CONST_ONLY then
|
|
CreateError(errConstantExpressionExpected, []);
|
|
|
|
Call_SCANNER;
|
|
Match('(');
|
|
result := NewTempVar;
|
|
Gen(OP_ASSIGNED, Parse_Expression, 0, result);
|
|
Match(')');
|
|
Exit;
|
|
end
|
|
else if IsCurrText('sizeof') and (not InScope('sizeof')) then
|
|
begin
|
|
Match('sizeof');
|
|
Match('(');
|
|
result := NewTempVar;
|
|
Gen(OP_SIZEOF, Parse_Expression, 0, result);
|
|
Match(')');
|
|
end
|
|
else if IsCurrText('typeinfo') and (not InScope('typeinfo')) then
|
|
begin
|
|
if CONST_ONLY then
|
|
CreateError(errConstantExpressionExpected, []);
|
|
|
|
Match('typeinfo');
|
|
Match('(');
|
|
result := NewTempVar;
|
|
SetType(result, typePOINTER);
|
|
Gen(OP_TYPEINFO, Parse_Expression, 0, result);
|
|
Match(')');
|
|
end
|
|
else if IsCurrText('pred') and (not InScope('pred')) then
|
|
begin
|
|
Match('pred');
|
|
Match('(');
|
|
result := NewTempVar;
|
|
Gen(OP_PRED, Parse_Expression, 0, result);
|
|
Match(')');
|
|
end
|
|
else if IsCurrText('succ') and (not InScope('succ')) then
|
|
begin
|
|
Match('succ');
|
|
Match('(');
|
|
result := NewTempVar;
|
|
Gen(OP_SUCC, Parse_Expression, 0, result);
|
|
Match(')');
|
|
end
|
|
else if IsCurrText('ord') and (not InScope('ord')) then
|
|
begin
|
|
Match('ord');
|
|
Match('(');
|
|
result := NewTempVar;
|
|
Gen(OP_ORD, Parse_Expression, 0, result);
|
|
Match(')');
|
|
end
|
|
else if IsCurrText('chr') and (not InScope('chr')) then
|
|
begin
|
|
Match('chr');
|
|
Match('(');
|
|
result := NewTempVar;
|
|
Gen(OP_CHR, Parse_Expression, 0, result);
|
|
Match(')');
|
|
end
|
|
else if IsCurrText('high') and (not InScope('high')) then
|
|
begin
|
|
Match('high');
|
|
Match('(');
|
|
result := NewTempVar;
|
|
Gen(OP_HIGH, Parse_Expression, 0, result);
|
|
Match(')');
|
|
end
|
|
else if IsCurrText('low') and (not InScope('low')) then
|
|
begin
|
|
Match('low');
|
|
Match('(');
|
|
result := NewTempVar;
|
|
Gen(OP_LOW, Parse_Expression, 0, result);
|
|
Match(')');
|
|
end
|
|
else if IsCurrText('abs') and (not InScope('abs')) then
|
|
begin
|
|
Match('abs');
|
|
Match('(');
|
|
result := NewTempVar;
|
|
Gen(OP_ABS, Parse_Expression, 0, result);
|
|
Match(')');
|
|
end
|
|
else if IsCurrText('length') and (not InScope('length')) then
|
|
begin
|
|
S := GetNext2Text;
|
|
Id := Lookup(S, CurrLevel);
|
|
if Id = 0 then
|
|
goto LabelDesignator;
|
|
if GetSymbolRec(Id).FinalTypeId <> typeOPENARRAY then
|
|
goto LabelDesignator;
|
|
Id := GetOpenArrayHighId(Id);
|
|
result := NewTempVar;
|
|
Gen(OP_PLUS, Id, NewConst(typeINTEGER, 1), result);
|
|
Match('length');
|
|
Match('(');
|
|
Parse_Expression;
|
|
Match(')');
|
|
end
|
|
else if IsCurrText('inherited') then
|
|
begin
|
|
if CONST_ONLY then
|
|
CreateError(errConstantExpressionExpected, []);
|
|
|
|
Call_SCANNER;
|
|
SubId := NewTempVar;
|
|
result := NewTempVar;
|
|
K := Parse_Ident;
|
|
RemoveInstruction(OP_EVAL, -1, -1, K);
|
|
Gen(OP_EVAL_INHERITED, K, 0, SubId);
|
|
if IsCurrText('(') or IsCurrText('[') then
|
|
Gen(OP_CALL_INHERITED, SubID, Parse_ArgumentList(SubId), result)
|
|
else
|
|
Gen(OP_CALL_INHERITED, SubID, 0, result);
|
|
end
|
|
else
|
|
begin
|
|
LabelDesignator:
|
|
result := Parse_Designator;
|
|
if IsCurrText(':=') then
|
|
if GetSymbolRec(result).OwnerId = 0 then
|
|
if CurrLevel > 0 then
|
|
if GetKind(CurrLevel) in KindSUBS then
|
|
if (GetName(result) <> '') and StrEql(GetName(result), GetName(CurrSubId)) then
|
|
result := CurrResultId;
|
|
|
|
if IsCurrText('(') then
|
|
begin
|
|
if CONST_ONLY then
|
|
CreateError(errConstantExpressionExpected, []);
|
|
|
|
SubId := result;
|
|
result := NewTempVar;
|
|
K := Parse_ArgumentList(SubId);
|
|
Gen(OP_CALL, SubID, K, result);
|
|
|
|
if IsCurrText('.') or IsCurrText('[') then
|
|
result := Parse_Designator(result);
|
|
end
|
|
else if GetKind(result) = KindSUB then
|
|
begin
|
|
if CONST_ONLY then
|
|
CreateError(errConstantExpressionExpected, []);
|
|
|
|
SubId := result;
|
|
result := NewTempVar;
|
|
SetName(result, GetName(SubId));
|
|
SetKind(result, KindNONE);
|
|
Gen(OP_EVAL, 0, 0, result);
|
|
|
|
if IsCurrText('.') or IsCurrText('[') then
|
|
result := Parse_Designator(result);
|
|
end;
|
|
|
|
{$IFDEF CPP_SYN}
|
|
if IsCurrText('++') then // post increment expression
|
|
begin
|
|
if CONST_ONLY then
|
|
CreateError(errConstantExpressionExpected, []);
|
|
|
|
Match('++');
|
|
temp := NewTempVar;
|
|
Gen(OP_ASSIGN, temp, result, temp);
|
|
r := NewTempVar;
|
|
Gen(OP_PLUS, result, NewConst(typeINTEGER, 1), r);
|
|
Gen(OP_ASSIGN, result, r, result);
|
|
Gen(OP_POSTFIX_EXPRESSION, 0, 0, 0);
|
|
result := temp;
|
|
end
|
|
else if IsCurrText('--') then // post decrement expression
|
|
begin
|
|
if CONST_ONLY then
|
|
CreateError(errConstantExpressionExpected, []);
|
|
|
|
Match('--');
|
|
temp := NewTempVar;
|
|
Gen(OP_ASSIGN, temp, result, temp);
|
|
r := NewTempVar;
|
|
Gen(OP_MINUS, result, NewConst(typeINTEGER, 1), r);
|
|
Gen(OP_ASSIGN, result, r, result);
|
|
Gen(OP_POSTFIX_EXPRESSION, 0, 0, 0);
|
|
result := temp;
|
|
end;
|
|
{$ENDIF}
|
|
end;
|
|
end;
|
|
|
|
function TPascalParser.Parse_SetConstructor: Integer;
|
|
var
|
|
id1, id2, k: Integer;
|
|
begin
|
|
Match('[');
|
|
if not IsCurrText(']') then
|
|
begin
|
|
k := 0;
|
|
result := NewTempVar;
|
|
|
|
repeat
|
|
if IsEOF then
|
|
break;
|
|
// parse member group
|
|
|
|
id1 := Parse_Expression;
|
|
if IsCurrText('..') then
|
|
begin
|
|
Match('..');
|
|
id2 := Parse_Expression;
|
|
Gen(OP_CHECK_SUBRANGE_TYPE, id1, id2, 0);
|
|
Gen(OP_SET_INCLUDE_INTERVAL, result, id1, id2);
|
|
end
|
|
else
|
|
Gen(OP_SET_INCLUDE, result, id1, 0);
|
|
|
|
Inc(k);
|
|
|
|
If NotMatch(',') then
|
|
break;
|
|
until false;
|
|
|
|
SetCount(result, k);
|
|
|
|
end
|
|
else
|
|
result := EmptySetId;
|
|
|
|
Match(']');
|
|
end;
|
|
|
|
function TPascalParser.Parse_Designator(init_id: Integer = 0): Integer;
|
|
var
|
|
ok: Boolean;
|
|
id: Integer;
|
|
S: String;
|
|
begin
|
|
if init_id = 0 then
|
|
result := Parse_QualId
|
|
else
|
|
result := init_id;
|
|
|
|
if IsOuterLocalVar(result) then
|
|
begin
|
|
AnonymStack.Top.BindList.Add(result);
|
|
S := GetName(result);
|
|
result := NewTempVar;
|
|
SetName(result, S);
|
|
Gen(OP_EVAL, 0, 0, result);
|
|
end;
|
|
|
|
repeat
|
|
if IsCurrText('.') then
|
|
begin
|
|
FIELD_OWNER_ID := result;
|
|
id := FIELD_OWNER_ID;
|
|
|
|
Match('.');
|
|
result := Parse_Ident;
|
|
Gen(OP_FIELD, id, result, result);
|
|
ok := true;
|
|
end
|
|
else if IsCurrText('[') then // index
|
|
begin
|
|
Match('[');
|
|
repeat
|
|
id := result;
|
|
result := NewTempVar;
|
|
Gen(OP_ELEM, id, Parse_Expression, result);
|
|
if NotMatch(',') then
|
|
Break;
|
|
until false;
|
|
Match(']');
|
|
ok := true;
|
|
end
|
|
else if IsCurrText('(') then
|
|
begin
|
|
Id := result;
|
|
result := NewTempVar;
|
|
Gen(OP_CALL, Id, Parse_ArgumentList(Id), result);
|
|
ok := true;
|
|
end
|
|
else if IsCurrText('^') then
|
|
begin
|
|
Match('^');
|
|
id := result;
|
|
result := NewTempVar;
|
|
Gen(OP_TERMINAL, id, 0, result);
|
|
ok := true;
|
|
end
|
|
else
|
|
ok := false;
|
|
until not ok;
|
|
end;
|
|
|
|
function TPascalParser.Parse_Label: Integer;
|
|
begin
|
|
if not (CurrToken.TokenClass in [tcIntegerConst, tcIdentifier]) then
|
|
RaiseError(errIdentifierExpected, [CurrToken.Text]);
|
|
result := CurrToken.Id;
|
|
if DECLARE_SWITCH then
|
|
SetKind(result, KindLABEL)
|
|
else if GetKind(result) <> KindLABEL then
|
|
RaiseError(errLabelExpected, []);
|
|
Call_SCANNER;
|
|
end;
|
|
|
|
function TPascalParser.Parse_Ident: Integer;
|
|
begin
|
|
if CurrToken.TokenClass = tcKeyword then
|
|
begin
|
|
if IsCurrText('nil') then
|
|
begin
|
|
result := NilId;
|
|
Call_SCANNER;
|
|
Exit;
|
|
end;
|
|
end;
|
|
result := inherited Parse_Ident;
|
|
end;
|
|
|
|
procedure TPascalParser.Call_SCANNER;
|
|
var
|
|
S: String;
|
|
begin
|
|
SetPrevToken;
|
|
|
|
inherited;
|
|
|
|
while CurrToken.TokenClass = tcSeparator do
|
|
begin
|
|
Gen(OP_SEPARATOR, CurrModule.ModuleNumber, CurrToken.Id, 0);
|
|
inherited Call_SCANNER;
|
|
end;
|
|
|
|
if CollectSig then
|
|
Sig := Sig + ' ' + CurrToken.Text;
|
|
|
|
if DECLARE_SWITCH then
|
|
Exit;
|
|
|
|
if CurrToken.TokenClass = tcKeyword then
|
|
begin
|
|
if StrEql(CurrToken.Text, 'String') then
|
|
begin
|
|
{$IFDEF PAXARM}
|
|
CurrToken.Id := typeUNICSTRING;
|
|
{$ELSE}
|
|
if IsUNIC then
|
|
CurrToken.Id := typeUNICSTRING
|
|
else
|
|
CurrToken.Id := typeANSISTRING;
|
|
{$ENDIF}
|
|
CurrToken.TokenClass := tcIdentifier;
|
|
Exit;
|
|
end
|
|
else if StrEql(CurrToken.Text, 'File') then
|
|
begin
|
|
CurrToken.Id := H_TFileRec;
|
|
CurrToken.TokenClass := tcIdentifier;
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
if CurrToken.TokenClass = tcIdentifier then
|
|
begin
|
|
S := CurrToken.Text;
|
|
if StrEql(S, 'Char') then
|
|
begin
|
|
{$IFDEF PAXARM}
|
|
CurrToken.Id := typeWIDECHAR;
|
|
{$ELSE}
|
|
if IsUNIC then
|
|
CurrToken.Id := typeWIDECHAR
|
|
else
|
|
CurrToken.Id := typeANSICHAR;
|
|
{$ENDIF}
|
|
end
|
|
else if StrEql(S, 'PChar') then
|
|
begin
|
|
{$IFDEF PAXARM}
|
|
CurrToken.Id := typePWIDECHAR;
|
|
{$ELSE}
|
|
if IsUNIC then
|
|
CurrToken.Id := typePWIDECHAR
|
|
else
|
|
CurrToken.Id := typePANSICHAR;
|
|
{$ENDIF}
|
|
end
|
|
else if StrEql(S, 'NativeInt') then
|
|
begin
|
|
CurrToken.Id := typeNATIVEINT;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TPascalParser.ReadToken;
|
|
begin
|
|
inherited;
|
|
|
|
while CurrToken.TokenClass = tcSeparator do
|
|
begin
|
|
Gen(OP_SEPARATOR, CurrModule.ModuleNumber, CurrToken.Id, 0);
|
|
inherited ReadToken;
|
|
end;
|
|
end;
|
|
|
|
function TPascalParser.Parse_DirectiveList(SubId: Integer): TIntegerList;
|
|
var
|
|
S: String;
|
|
begin
|
|
result := TIntegerList.Create;
|
|
|
|
repeat
|
|
if Parse_PortabilityDirective <> portNone then
|
|
if IsCurrText(';') then
|
|
Match(';');
|
|
S := CurrToken.Text;
|
|
|
|
if StrEql(S, 'overload') then
|
|
begin
|
|
if Assigned(OnParseSubDirective) then
|
|
OnParseSubDirective(Owner, S, dirOVERLOAD);
|
|
|
|
RemoveLastIdent(CurrToken.Id);
|
|
|
|
Call_SCANNER;
|
|
result.Add(dirOVERLOAD);
|
|
SetOverloaded(SubId);
|
|
|
|
if Parse_PortabilityDirective <> portNone then
|
|
Match(';')
|
|
else if IsCurrText(';') then
|
|
Match(';');
|
|
end
|
|
else if StrEql(S, 'forward') then
|
|
begin
|
|
if Assigned(OnParseSubDirective) then
|
|
OnParseSubDirective(Owner, S, dirFORWARD);
|
|
|
|
RemoveLastIdent(CurrToken.Id);
|
|
|
|
Call_SCANNER;
|
|
result.Add(dirFORWARD);
|
|
|
|
if Parse_PortabilityDirective <> portNone then
|
|
Match(';')
|
|
else if IsCurrText(';') then
|
|
Match(';');
|
|
end
|
|
else if StrEql(S, 'message') then
|
|
begin
|
|
if Assigned(OnParseSubDirective) then
|
|
OnParseSubDirective(Owner, S, 0);
|
|
|
|
RemoveLastIdent(CurrToken.Id);
|
|
|
|
if DECLARE_SWITCH then
|
|
if CurrToken.Id = StCard then
|
|
DiscardLastSTRecord;
|
|
|
|
Call_SCANNER;
|
|
Parse_Expression;
|
|
|
|
if Parse_PortabilityDirective <> portNone then
|
|
Match(';')
|
|
else if IsCurrText(';') then
|
|
Match(';');
|
|
end
|
|
else if StrEql(S, 'inline') then
|
|
begin
|
|
if Assigned(OnParseSubDirective) then
|
|
OnParseSubDirective(Owner, S, 0);
|
|
Call_SCANNER;
|
|
|
|
if Parse_PortabilityDirective <> portNone then
|
|
Match(';')
|
|
else if IsCurrText(';') then
|
|
Match(';');
|
|
end
|
|
else if StrEql(S, 'stdcall') then
|
|
begin
|
|
if Assigned(OnParseSubDirective) then
|
|
OnParseSubDirective(Owner, S, ccSTDCALL);
|
|
|
|
RemoveLastIdent(CurrToken.Id);
|
|
Call_SCANNER;
|
|
SetCallConvention(SubId, ccSTDCALL);
|
|
|
|
if Parse_PortabilityDirective <> portNone then
|
|
Match(';')
|
|
else if IsCurrText(';') then
|
|
Match(';');
|
|
end
|
|
else if StrEql(S, 'safecall') then
|
|
begin
|
|
if Assigned(OnParseSubDirective) then
|
|
OnParseSubDirective(Owner, S, ccSAFECALL);
|
|
|
|
RemoveLastIdent(CurrToken.Id);
|
|
Call_SCANNER;
|
|
SetCallConvention(SubId, ccSAFECALL);
|
|
|
|
if Parse_PortabilityDirective <> portNone then
|
|
Match(';')
|
|
else if IsCurrText(';') then
|
|
Match(';');
|
|
end
|
|
else if StrEql(S, 'register') then
|
|
begin
|
|
if Assigned(OnParseSubDirective) then
|
|
OnParseSubDirective(Owner, S, ccREGISTER);
|
|
|
|
RemoveLastIdent(CurrToken.Id);
|
|
|
|
Call_SCANNER;
|
|
SetCallConvention(SubId, ccREGISTER);
|
|
|
|
if Parse_PortabilityDirective <> portNone then
|
|
Match(';')
|
|
else if IsCurrText(';') then
|
|
Match(';');
|
|
end
|
|
else if StrEql(S, 'cdecl') then
|
|
begin
|
|
if Assigned(OnParseSubDirective) then
|
|
OnParseSubDirective(Owner, S, ccCDECL);
|
|
|
|
RemoveLastIdent(CurrToken.Id);
|
|
|
|
Call_SCANNER;
|
|
SetCallConvention(SubId, ccCDECL);
|
|
|
|
if Parse_PortabilityDirective <> portNone then
|
|
Match(';')
|
|
else if IsCurrText(';') then
|
|
Match(';');
|
|
end
|
|
else if StrEql(S, 'msfastcall') then
|
|
begin
|
|
if Assigned(OnParseSubDirective) then
|
|
OnParseSubDirective(Owner, S, ccMSFASTCALL);
|
|
|
|
RemoveLastIdent(CurrToken.Id);
|
|
|
|
Call_SCANNER;
|
|
SetCallConvention(SubId, ccMSFASTCALL);
|
|
|
|
if Parse_PortabilityDirective <> portNone then
|
|
Match(';')
|
|
else if IsCurrText(';') then
|
|
Match(';');
|
|
end
|
|
else if StrEql(S, 'pascal') then
|
|
begin
|
|
if Assigned(OnParseSubDirective) then
|
|
OnParseSubDirective(Owner, S, ccPASCAL);
|
|
|
|
RemoveLastIdent(CurrToken.Id);
|
|
|
|
Call_SCANNER;
|
|
SetCallConvention(SubId, ccPASCAL);
|
|
|
|
if Parse_PortabilityDirective <> portNone then
|
|
Match(';')
|
|
else if IsCurrText(';') then
|
|
Match(';');
|
|
end
|
|
else if StrEql(S, 'virtual') then
|
|
begin
|
|
if Assigned(OnParseSubDirective) then
|
|
OnParseSubDirective(Owner, S, cmVIRTUAL);
|
|
|
|
RemoveLastIdent(CurrToken.Id);
|
|
|
|
Call_SCANNER;
|
|
result.Add(dirVIRTUAL);
|
|
SetCallMode(SubId, cmVIRTUAL);
|
|
|
|
if Parse_PortabilityDirective <> portNone then
|
|
Match(';')
|
|
else if IsCurrText(';') then
|
|
Match(';');
|
|
end
|
|
else if StrEql(S, 'static') then
|
|
begin
|
|
if Assigned(OnParseSubDirective) then
|
|
OnParseSubDirective(Owner, S, cmSTATIC);
|
|
|
|
RemoveLastIdent(CurrToken.Id);
|
|
|
|
Call_SCANNER;
|
|
result.Add(dirSTATIC);
|
|
SetCallMode(SubId, cmSTATIC);
|
|
|
|
if Parse_PortabilityDirective <> portNone then
|
|
Match(';')
|
|
else if IsCurrText(';') then
|
|
Match(';');
|
|
end
|
|
else if StrEql(S, 'dynamic') then
|
|
begin
|
|
if Assigned(OnParseSubDirective) then
|
|
OnParseSubDirective(Owner, S, cmDYNAMIC);
|
|
|
|
RemoveLastIdent(CurrToken.Id);
|
|
|
|
Call_SCANNER;
|
|
result.Add(dirDYNAMIC);
|
|
SetCallMode(SubId, cmDYNAMIC);
|
|
Gen(OP_ADD_MESSAGE, SubId, NewConst(typeINTEGER, -1000), 0);
|
|
|
|
if Parse_PortabilityDirective <> portNone then
|
|
Match(';')
|
|
else if IsCurrText(';') then
|
|
Match(';');
|
|
end
|
|
else if StrEql(S, 'assembler') then
|
|
begin
|
|
if Assigned(OnParseSubDirective) then
|
|
OnParseSubDirective(Owner, S, 0);
|
|
|
|
RemoveLastIdent(CurrToken.Id);
|
|
Call_SCANNER;
|
|
|
|
if Parse_PortabilityDirective <> portNone then
|
|
Match(';')
|
|
else if IsCurrText(';') then
|
|
Match(';');
|
|
end
|
|
else if StrEql(S, 'override') then
|
|
begin
|
|
if Assigned(OnParseSubDirective) then
|
|
OnParseSubDirective(Owner, S, cmOVERRIDE);
|
|
|
|
RemoveLastIdent(CurrToken.Id);
|
|
|
|
Call_SCANNER;
|
|
result.Add(dirOVERRIDE);
|
|
SetCallMode(SubId, cmOVERRIDE);
|
|
Gen(OP_ADD_MESSAGE, SubId, NewConst(typeINTEGER, -1000), 0);
|
|
Gen(OP_CHECK_OVERRIDE, SubId, 0, 0);
|
|
|
|
if Parse_PortabilityDirective <> portNone then
|
|
Match(';')
|
|
else if IsCurrText(';') then
|
|
Match(';');
|
|
end
|
|
else if StrEql(S, 'abstract') then
|
|
begin
|
|
if Assigned(OnParseSubDirective) then
|
|
OnParseSubDirective(Owner, S, dirABSTRACT);
|
|
|
|
RemoveLastIdent(CurrToken.Id);
|
|
|
|
Call_SCANNER;
|
|
result.Add(dirABSTRACT);
|
|
|
|
if Parse_PortabilityDirective <> portNone then
|
|
Match(';')
|
|
else if IsCurrText(';') then
|
|
Match(';');
|
|
end
|
|
else if StrEql(S, 'final') then
|
|
begin
|
|
if Assigned(OnParseSubDirective) then
|
|
OnParseSubDirective(Owner, S, dirFINAL);
|
|
|
|
RemoveLastIdent(CurrToken.Id);
|
|
|
|
SetFinal(SubId, true);
|
|
Call_SCANNER;
|
|
result.Add(dirFINAL);
|
|
|
|
if Parse_PortabilityDirective <> portNone then
|
|
Match(';')
|
|
else if IsCurrText(';') then
|
|
Match(';');
|
|
end
|
|
else if StrEql(S, 'reintroduce') then
|
|
begin
|
|
if Assigned(OnParseSubDirective) then
|
|
OnParseSubDirective(Owner, S, dirREINTRODUCE);
|
|
|
|
RemoveLastIdent(CurrToken.Id);
|
|
|
|
Call_SCANNER;
|
|
result.Add(dirREINTRODUCE);
|
|
|
|
if Parse_PortabilityDirective <> portNone then
|
|
Match(';')
|
|
else if IsCurrText(';') then
|
|
Match(';');
|
|
end
|
|
else
|
|
break;
|
|
until false;
|
|
|
|
if result.IndexOf(dirVIRTUAL) >= 0 then
|
|
if result.IndexOf(dirVIRTUAL) = -1 then
|
|
CreateError(errAbstractMethodsMustBeVirtual, []);
|
|
|
|
Parse_PortabilityDirective;
|
|
|
|
if IsCurrText(';') then
|
|
Match(';');
|
|
end;
|
|
|
|
function TPascalParser.Parse_PortabilityDirective: TPortDir;
|
|
var
|
|
ok: Boolean;
|
|
S: String;
|
|
begin
|
|
result := portNone;
|
|
repeat
|
|
ok := false;
|
|
S := CurrToken.Text;
|
|
if StrEql(S, 'platform') then
|
|
begin
|
|
RemoveLastIdent(CurrToken.Id);
|
|
Call_SCANNER;
|
|
if IsCurrText('=') then
|
|
begin
|
|
Call_SCANNER;
|
|
Parse_Expression;
|
|
end;
|
|
result := portPlatform;
|
|
ok := true;
|
|
end;
|
|
if StrEql(S, 'deprecated') then
|
|
begin
|
|
RemoveLastIdent(CurrToken.Id);
|
|
|
|
Call_SCANNER;
|
|
if not IsCurrText(';') then
|
|
Call_SCANNER;
|
|
result := portDeprecated;
|
|
ok := true;
|
|
end;
|
|
if StrEql(S, 'library') then
|
|
begin
|
|
Call_SCANNER;
|
|
result := portLibrary;
|
|
ok := true;
|
|
end;
|
|
until not ok;
|
|
end;
|
|
|
|
procedure TPascalParser.InitSub(var SubId: Integer);
|
|
begin
|
|
if AnonymStack.Count = 0 then
|
|
begin
|
|
CheckAbstract(SubId);
|
|
ReplaceForwardDeclaration(SubId);
|
|
end;
|
|
|
|
inherited InitSub(SubId);
|
|
|
|
Scanner.AttachId(SubId, true);
|
|
Scanner.DoComment;
|
|
|
|
if GetSymbolRec(SubId).CallMode = cmSTATIC then
|
|
GetSymbolRec(CurrSelfId).Name := '';
|
|
|
|
InitMethodDef(SubId);
|
|
end;
|
|
|
|
procedure TPascalParser.Match(const S: String);
|
|
begin
|
|
inherited;
|
|
end;
|
|
|
|
function TPascalParser.MatchEx(const S: String): Boolean;
|
|
begin
|
|
result := true;
|
|
Tag := 0;
|
|
Match(S);
|
|
if Tag = 1 then
|
|
result := false;
|
|
end;
|
|
|
|
function TPascalParser.InScope(const S: String): Boolean;
|
|
var
|
|
id: Integer;
|
|
begin
|
|
id := Lookups(S, LevelStack);
|
|
if id = 0 then
|
|
result := false
|
|
else
|
|
result := not GetSymbolRec(id).Host;
|
|
end;
|
|
|
|
procedure TPascalParser.EndMethodDef(SubId: Integer);
|
|
var
|
|
TypeId: Integer;
|
|
begin
|
|
inherited;
|
|
|
|
TypeId := GetLevel(SubId);
|
|
|
|
// if CurrModule.IsExtra then
|
|
// Exit;
|
|
|
|
if TypeId = 0 then
|
|
Exit;
|
|
if GetKind(TypeId) <> KindTYPE then
|
|
Exit;
|
|
|
|
// if not IsGeneric(TypeId) then
|
|
// Exit;
|
|
|
|
if GetSymbolRec(SubId).IsSharedMethod then
|
|
with TKernel(kernel).TypeDefList.FindMethodDef(SubId) do
|
|
Definition := 'class ' + Definition;
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_TypeRestriction(LocalTypeParams: TStringObjectList);
|
|
var
|
|
temp: Boolean;
|
|
I: Integer;
|
|
TR: TTypeRestrictionRec;
|
|
begin
|
|
temp := DECLARE_SWITCH;
|
|
try
|
|
DECLARE_SWITCH := false;
|
|
if not IsCurrText(':') then
|
|
Exit;
|
|
Call_SCANNER;
|
|
TR := TTypeRestrictionRec.Create;
|
|
TR.N := TKernel(kernel).Code.Card;
|
|
if IsCurrText('class') then
|
|
begin
|
|
Call_SCANNER;
|
|
if IsCurrText(',') then
|
|
begin
|
|
Match(',');
|
|
Match('constructor');
|
|
end;
|
|
TR.Id := H_TObject;
|
|
end
|
|
else if IsCurrText('constructor') then
|
|
begin
|
|
Call_SCANNER;
|
|
if IsCurrText(',') then
|
|
begin
|
|
Match(',');
|
|
Match('class');
|
|
end;
|
|
TR.Id := H_TObject;
|
|
end
|
|
else if IsCurrText('record') then
|
|
begin
|
|
Call_SCANNER;
|
|
TR.Id := typeRECORD;
|
|
end
|
|
else
|
|
begin
|
|
TR.Id := Parse_QualId;
|
|
if IsCurrText(',') then
|
|
begin
|
|
Match(',');
|
|
Match('constructor');
|
|
end;
|
|
end;
|
|
finally
|
|
DECLARE_SWITCH := temp;
|
|
end;
|
|
if TR = nil then
|
|
Exit;
|
|
for I := LocalTypeParams.Count - 1 downto 0 do
|
|
begin
|
|
if LocalTypeParams.Objects[I] <> nil then
|
|
break;
|
|
LocalTypeParams.Objects[I] := TR.Clone;
|
|
end;
|
|
FreeAndNil(TR);
|
|
end;
|
|
|
|
procedure TPascalParser.Parse_Attribute;
|
|
begin
|
|
while IsCurrText('[') do
|
|
begin
|
|
Call_SCANNER;
|
|
repeat
|
|
Parse_Expression;
|
|
if NotMatch(',') then
|
|
break;
|
|
until false;
|
|
Match(']');
|
|
end;
|
|
end;
|
|
|
|
procedure TPascalParser.RemoveKeywords;
|
|
begin
|
|
HideKeyword(I_STRICT);
|
|
HideKeyword(I_PRIVATE);
|
|
HideKeyword(I_PROTECTED);
|
|
HideKeyword(I_PUBLIC);
|
|
HideKeyword(I_PUBLISHED);
|
|
end;
|
|
|
|
procedure TPascalParser.RestoreKeywords;
|
|
begin
|
|
inherited;
|
|
end;
|
|
|
|
function TPascalParser.Parse_LoopStmt(l_break, l_continue, l_loop: Integer): Boolean;
|
|
begin
|
|
BreakStack.Push(l_break, l_loop);
|
|
ContinueStack.Push(l_continue, l_loop);
|
|
BeginLoop;
|
|
result := Parse_Statement;
|
|
EndLoop;
|
|
BreakStack.Pop;
|
|
ContinueStack.Pop;
|
|
end;
|
|
|
|
end.
|