pascal_parser.pas
来自「Delphi脚本控件」· PAS 代码 · 共 698 行 · 第 1/2 页
PAS
698 行
////////////////////////////////////////////////////////////////////////////
// PAXScript Interpreter
// Author: Alexander Baranovsky (ab@cable.netlux.org)
// ========================================================================
// Copyright (c) Alexander Baranovsky, 2003-2005. All rights reserved.
// Code Version: 3.0
// ========================================================================
// Unit: PASCAL_PARSER.pas
// ========================================================================
////////////////////////////////////////////////////////////////////////////
{$I PaxScript.def}
unit PASCAL_PARSER;
interface
uses
SysUtils, Classes,
BASE_CONSTS,
BASE_SYS,
BASE_SCANNER,
BASE_EXTERN;
type
TPascalScanner = class(TPAXScanner)
public
procedure ReadToken; override;
end;
TPascalParser = class
public
Scanner: TPascalScanner;
CurrToken: TPAXToken;
D: TPAXMethodDefinition;
ResultType: String;
NP: Integer;
IsDynamicArrayType: Boolean;
constructor Create;
destructor Destroy; override;
procedure Call_SCANNER;
function IsCurrText(const S: String): boolean;
function Parse_Ident: String;
procedure Match(const S: String);
function Parse_Type(var TypeID, ExtraTypeID, Size: Integer): ShortString;
procedure Parse_IdentList;
procedure Parse_FormalParameter;
procedure Parse_FormalParameters;
procedure Parse_Heading;
function Parse_Property(var ReadName, WriteName: String;
var Def: Boolean; DefList: TPAXDefinitionList): String;
procedure ParseUsesClause(Output: TStrings);
end;
implementation
procedure TPascalScanner.ReadToken;
procedure ScanChrs;
var
S: String;
I: Integer;
begin
S := '';
repeat
GetNextChar;
ScanDigits;
I := StrToInt(Token.Text);
S := S + Chr(I);
if LA(1) = '#' then
GetNextChar
else
Break;
until false;
Token.Text := S;
Token.TokenClass := tcStringConst;
if LA(1) = '''' then
begin
GetNextChar;
ScanString('''');
Token.Text := S + Token.Text;
end;
end;
begin
repeat
GetNextChar;
Token.TokenClass := tcNone;
Token.ID := 0;
case c of
#8, #9, #10, #13, #32: ScanWhiteSpace;
#255: ScanEOF;
'0'..'9': ScanDigits;
'$': ScanHexDigits;
'A'..'Z', 'a'..'z', '_':
ScanIdentifier;
'+': ScanPlus;
'-': ScanMinus;
'=': ScanEQ;
':': ScanColon;
';': ScanSemiColon;
'(': ScanLeftRoundBracket;
')': ScanRightRoundBracket;
'[': ScanLeftBracket;
']': ScanRightBracket;
',': ScanComma;
'''': ScanString('''');
'#': ScanChrs;
'{':
begin
repeat
GetNextChar;
if c in [#10,#13] then
begin
IncLineNumber;
PosNumber := -1;
if c = #13 then
GetNextChar;
end;
until LA(1) in ['}', #255];
GetNextChar;
end;
else
raise TPAXScriptFailure.Create(errIllegalCharacter);
end;
if Token.TokenClass <> tcNone then
Exit;
until false;
end;
constructor TPascalParser.Create;
begin
inherited;
Scanner := TPascalScanner.Create(Self);
ResultType := '';
NP := 0;
IsDynamicArrayType := false;
end;
destructor TPascalParser.Destroy;
begin
Scanner.Free;
inherited;
end;
procedure TPascalParser.Call_SCANNER;
begin
Scanner.ReadToken;
CurrToken := Scanner.Token;
if CurrToken.TokenClass = tcSeparator then
if CurrToken.ID <> SP_EOF then
begin
Call_SCANNER;
Exit;
end;
end;
function TPascalParser.IsCurrText(const S: String): boolean;
begin
result := StrEql(CurrToken.Text, S)
end;
procedure TPascalParser.Match(const S: String);
begin
if not IsCurrText(S) then
raise TPAXScriptFailure.Create(Format(err_X_expected_but_Y_fond, [S, CurrToken.Text]));
end;
function TPascalParser.Parse_Ident: String;
begin
if CurrToken.TokenClass <> tcId then
raise TPAXScriptFailure.Create(errIdentifierExpected);
result := CurrToken.Text;
Call_SCANNER;
end;
function TPascalParser.Parse_Type(var TypeID, ExtraTypeID, Size: Integer): ShortString;
var
I: Integer;
RTTIDef: TPAXRTTITypeDefinition;
ClassDef: TPAXClassDefinition;
S: String;
label
Again;
begin
ExtraTypeID := 0;
IsDynamicArrayType := false;
Size := -1;
S := Parse_Ident;
result := S;
S := FindTypeAlias(result, true);
if S <> '' then
result := S;
if StrEql(result, 'array') then
begin
Again:
ExtraTypeID := typeDYNAMICARRAY;
Match('of');
Call_SCANNER;
result := Parse_Ident;
if StrEql(result, 'array') then goto Again;
if StrEql(result, 'const') then
result := 'TVarRec';
end
else if StrEql(result, 'paxarray') then
begin
typeID := typeARRAY;
ExtraTypeID := typeARRAY;
Exit;
end;
for I:=0 to PAXTypes.Count - 1 do
if StrEql(result, PAXTypes[I]) then
begin
typeID := I;
Exit;
end;
typeID := typeCLASS;
RTTIDef := D.DefList.FindRTTITypeDefByName(result);
if RTTIDef <> nil then
begin
typeID := RTTIDef.FinalType;
Exit;
end;
ClassDef := D.DefList.FindClassDefByName(result);
if ClassDef <> nil then
begin
if ClassDef.classKind = ckEnum then
typeID := typeINTEGER
else if ClassDef.classKind = ckDynamicArray then
begin
IsDynamicArrayType := true;
ExtraTypeId := typeDYNAMICARRAY;
TypeID := ClassDef.ElType;
end
else if ClassDef.classKind = ckInterface then
typeID := typeINTERFACE;
Size := ClassDef.RecordSize;
Exit;
end;
S := UpperCase(result);
if UnresolvedTypes.IndexOf(S) = -1 then
UnresolvedTypes.Add(S);
if StrEql(result, 'IInterface') then
typeID := typeINTERFACE;
if Pos('CLASS', UpperCase(result)) > 0 then
typeID := typeCLASSREF;
end;
procedure TPascalParser.Parse_IdentList;
var
S: String;
begin
Inc(D.NP);
S := Parse_Ident;
D.ParamNames[D.NP - 1] := S;
while IsCurrText(',') do
begin
Inc(D.NP);
Call_SCANNER;
S := Parse_Ident;
D.ParamNames[D.NP - 1] := S;
end;
end;
procedure TPascalParser.Parse_FormalParameter;
var
I, PrevNP, TypeID, ExtraTypeID, Size: Integer;
ByRef, IsSelf, IsOut, IsConst: Boolean;
StrType, S: String;
begin
ByRef := false;
IsOut := false;
IsConst := false;
if IsCurrText('var') then
begin
ByRef := true;
Call_SCANNER;
end
else if IsCurrText('const') then
begin
IsConst := true;
Call_SCANNER;
end
else if IsCurrText('out') then
begin
ByRef := true;
IsOut := true;
Call_SCANNER;
end;
PrevNP := D.NP;
IsSelf := CurrToken.Text = 'Self';
Parse_IdentList;
if (D.NP = 1) and (PrevNP = 0) and D.NewFake and IsSelf then
Dec(D.NP);
TypeID := TypeVOID;
if IsCurrText(':') then
begin
Call_SCANNER;
StrType := Parse_Type(TypeID, ExtraTypeID, Size);
end
else
if IsOut then
TypeID := TypeINTERFACE;
for I:= PrevNP + 1 to D.NP do
begin
D.Types[I - 1] := TypeID;
D.ExtraTypes[I - 1] := ExtraTypeID;
D.StrTypes[I - 1] := StrType;
D.ByRefs[I - 1] := ByRef;
D.Consts[I - 1] := IsConst;
D.Sizes[I - 1] := Size;
end;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?