📄 ucodeparser.pas
字号:
//will nevertheless return a TMyForm-object. So the original type
//needs to be saved, so MyDlgResult can be be found (it wouldn't in
//TCustomForm).
ConstructType :TRecordType;
//are we parsing an identifier-path (identifiers
InIdentPath :( //separated by dots etc.)
iipNo, //no, we don't
iipIdent, //yes, we just read an identifier
iipDot //yes, we just read a dot
);
//are brackets [] possible, i.e. indexing (an array)?
BracketsPossible :Boolean;
//is this a message-handler and it has to be taken in account
IsMessageMethod :Boolean; //if "inherited" is found
PointerOperator :Boolean; //if an "@" has been found
begin
if Token = '' then //if first token not read yet
if not GetToken(Token) then //read the first token
Exception(etSyntax, 'No expression before end of file!');
// if IsWordIn(Token, EndOfExpressions, Index) or
// ((length(Token) = 1) and (Token[1] in [';', ',', ':', ')', ']'])) or
// (Token = ':=') then
// Exception(etSyntax, 'Empty Expression!');
TypeIdent := nil; //no identifiers so far
TypeCast := False; //not a type itself specified so far
TheFile := nil; //and no file as part of an identifier
InIdentPath := iipNo; //not parsing an identifier at the moment
BracketsPossible := False; //nothing found, after that brackets [] can follow
PointerOperator := False; //no "@" found so far
//as long as no keyword or character ending the expression (or the statement)
//or a closing brace/bracket found
while ((InIdentPath = iipDot) or
not IsWordIn(Token, EndOfExpressions, Index) or
(not StopAtIn and (Index = EndOfExpressionsIn))) and
((length(Token) <> 1) or
not (Token[1] in [';', ',', ':', ')', ']'])) and
(Token <> ':=') do
begin
//found an identifier? (this includes "inherited")
if (Token <> '') and (Token[1] in StartIdentifierChars) and
((InIdentPath = iipDot) or
(not IsWordIn(Token, Operators, Index) or
//"at" can be an operator instead of an identifier after "raise"
((Index = OperatorAt) and
//if it follows directly after another identifier treat it as operator
(InIdentPath <> iipIdent)))) then
begin
if InIdentPath = iipIdent then
ExceptionFmt(etSyntax,
'Found identifier "%s" directly after another identifier!',
[Token]);
ConstructType := FFunctionParseSelf; //assume Self as type
if InIdentPath = iipDot then //found a "." before?
begin
if LowerCase(Token) = 'inherited' then
Exception(etSyntax, 'Found inherited after ".", expected identifier!');
if assigned(TypeIdent) then //type before the "." is known?
begin
if not (TypeIdent is TRecordType) then
ExceptionFmt(etSyntax,
'"%s" is not record-like, so ".%s" can''t be found in it!',
[TypeIdent.Name, Token]);
ConstructType := TRecordType(TypeIdent); //save the type
//try to find the identifier in this type
Ident := ConstructType.FindMember(Token, FThisFile,
(ConstructType = FFunctionParseSelf) or
(ConstructType.InFile = FThisFile));
end
else
if assigned(TheFile) then //was it a name of a file before the "."?
Ident := TheFile.Idents.GetIdentByName(Token) //use identifier in it
else
Ident := nil; //identifier unknown, like before
TheFile := nil; //not a file anymore
if not assigned(Ident) then //identifier unknown?
AddToUnknownIdents(Token, '.') //add to list
else
//add to list of global identifiers
AddToGlobalList(Ident);
end //if InIdentPath = iipDot
else //new identifier-path (no "." before it)
begin
assert(not assigned(TheFile));
if LowerCase(Token) = 'inherited' then //use of "inherited" identifier?
begin
if not assigned(FFunctionParseSelf) then
Exception(etSyntax, 'Using of "inherited" not in a method!');
PushPosition;
if not GetToken(Token) then //get next token, the identifier
Exception(etSyntax,
'Unexpected end of file in expression after "inherited"!');
//identifier follows?
if not IsWordIn(Token, EndOfExpressions, Index) and
((length(Token) <> 1) or
((Token[1] <> ';') and (Token[1] <> ',') and
(Token[1] <> ':') and (Token[1] <> ')') and
(Token[1] <> ']'))) and
(Token <> ':=') then
begin
LosePosition; //use this token
IsMessageMethod := False; //if not found, add to unknown-list
end
else //no identifier: shortcut for calling same inherited function
begin
PopPosition; //push token back
assert(assigned(FTopLevelFunctionNS));
Token := FTopLevelFunctionNS.FuncIdent.Name;
//save if it is a message-handler, in that case it's possible, that
//there is no inherited function of the same name
IsMessageMethod := faMessage in
FTopLevelFunctionNS.FuncIdent.Attributes;
end;
ConstructType := ConstructType.GetParent; //get parent class
if assigned(ConstructType) then //parent class known?
begin
//search inherited identifier in parent-class
Ident := ConstructType.FindMember(Token, FThisFile, True);
if not assigned(Ident) then //inherited identifier not found
begin
if not IsMessageMethod then //add to list of unknown identifiers
AddToUnknownIdents(Token, 'inherited ' +
FFunctionParseSelf.Name + '.');
end
else //add to list of used global identifiers
AddToGlobalList(Ident);
ConstructType := FFunctionParseSelf; //in case it was a constructor
end
else //no parent-class known
begin
Ident := nil; //identifier not known
if not IsMessageMethod then //add to list of unknown identifiers
AddToUnknownIdents(Token, 'inherited ' +
FFunctionParseSelf.Name + '.');
end;
end //if Token = 'inherited'
else
begin
//try to find the identifier
Ident := FCurrentNameSpace.FindIdent(Token, TheFile);
if assigned(Ident) then
//add to list of used global identifiers
AddToGlobalList(Ident);
if not assigned(Ident) and not assigned(TheFile) then
AddToUnknownIdents(Token); //add to list of unknown identifiers
end; //else Token = 'inherited'
end; //else InIdentPath = iipDot
if Ident is TFunction then //if it is an function
//add the function-identifier to list of called functions
AddToCalledList(TFunction(Ident));
if (Ident is TFunction) and //if it is a constructor
(TFunction(Ident).FuncKind = fkConstructor) and
assigned(ConstructType) and
not assigned(TFunction(Ident).ReturnType) then
TypeIdent := ConstructType //use the original (class) type
else
TypeIdent := GetType(Ident); //use type of identifier
TypeCast := Ident is TType; //a type itself specified?
InIdentPath := iipIdent; //we just read an identifier
BracketsPossible := False; //brackets [] are possible after it
end //if Token is an Identifier
else
//Token is (, [, ., or ^?
if (length(Token) = 1) and (Token[1] in ['(', '[', '.', '^']) then
case Token[1] of
'.': begin
if InIdentPath <> iipIdent then
Exception(etSyntax,
'Found "." without identifier before it!');
//auto-dereference pointers
if TypeIdent is TPointerType then
TypeIdent := GetType(TPointerType(TypeIdent).BaseType);
//for class-variables use the base class
if TypeIdent is TClassReferenceType then
TypeIdent := GetType(TClassReferenceType(TypeIdent).
BaseClass);
if not (TypeIdent is TRecordType) and
assigned(TypeIdent) then
begin
WarningMessage(etSyntax,
'Found "." without record-like-identifier before it (Variant?)!');
TypeIdent := nil;
end;
InIdentPath := iipDot; //another identifier will be expected
BracketsPossible := False; //brackets [] can't follow a "."
end; //case Token = '.'
'(': begin
//braces are not allowed directly after a dot
if InIdentPath = iipDot then
Exception(etSyntax,
'Found "(" after ".", expected identifier!');
TheFile := nil; //not a file anymore
if InIdentPath = iipNo then //no identifier before this?
begin
//parse sub-expression between braces
if ParseExpression('', @TypeIdent) <> ')' then
Exception(etSyntax,
'Expected ")" after "(" without identifier before it, failed!');
//use the calculated identifier (if found) as
InIdentPath := iipIdent; //current identifier
TypeCast := False; //type not in braces for casts
end
else
begin
//parse everything between the braces
repeat
Token := ParseExpression(''); //parse each expression
until
//parameter-list of a function-call
(Token <> ',') and
//Write[Ln], Str: width of parameter
(Token <> ':') and
//record-constants?
// (Token <> ';') and
//named parameters (automation objects)
(Token <> ':=');
if Token <> ')' then
Exception(etSyntax, 'Expected ")" after "(", failed!');
if TypeCast and assigned(TypeIdent) then
//increment statistic
FThisFile.Statistic.Increment(psfTypeCastsKnown);
end;
//brackets [] can't follow; or it's a type for
BracketsPossible := False; //which it's valid
end; //case Token = '('
'[': if InIdentPath = iipNo then //no identifier before it?
begin
//it seems to be a set-constructor or a constant array
repeat
Token := ParseExpression(''); //parse each item/range
until Token <> ','; //separated by comma
if Token <> ']' then
Exception(etSyntax, 'Expected "]" after "[", failed!');
BracketsPossible := False; //no brackets after a set
TheFile := nil; //not a file anymore
TypeCast := False; //not a type itself specified
end
else
begin
//brackets are not allowed directly after a dot
if InIdentPath = iipDot then
Exception(etSyntax,
'Found "[" after ".", expected identifier!');
TheFile := nil; //not a file anymore
if TypeIdent is TPointerType then //auto-dereference pointers
TypeIdent := GetType(TPointerType(TypeIdent).BaseType);
// BracketsPossible := True; //PChar is an "array"
if TypeIdent is TRecordType then //an object?
begin //get default-property
Ident := TRecordType(TypeIdent).GetDefaultProperty;
TypeIdent := GetType(Ident);
if TypeIdent is TPointerType then //dereference pointers
TypeIdent := GetType(TPointerType(TypeIdent).BaseType);
end;
//no brackets allowed?
if not (TypeIdent is TArrayType) and
not BracketsPossible
and assigned(TypeIdent) then
begin
if not (TypeIdent is TStringType) then //not after string?
WarningMessage(etSyntax,
'Found "[" without array-identifier before it (PChar?)!');
//type would be char, but simple types don't matter
TypeIdent := nil;
end;
repeat
Token := ParseExpression(''); //parse all indizes
until Token <> ','; //separated by comma
if Token <> ']' then
Exception(etSyntax, 'Expected "]" after "[", failed!');
BracketsPossible := True; //in case it is multi-dimensional
while TypeIdent is TArrayType do //get base-type of array
TypeIdent := GetType(TArrayType(TypeIdent).BaseType);
TypeCast := False; //not a type itself specified
end; //case Token = '['
'^': begin
if InIdentPath = iipDot then //dereferencing only of idents
Exception(etSyntax, 'Found "^" after "."!')
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -