📄 uidentparser.pas
字号:
~result the next following token }
function TIdentifierParser.ParseConstantExpression(var ExprTokens: String;
EndDirectives: TAllowedExpressionDirectives = []): String;
//keywords (identifiers) that are operators
const Operators: array[0..10] of String =
('and', 'as', 'div', 'in', 'is',
'mod', 'not', 'or', 'shl', 'shr',
'xor');
var Expression :String; //the expression tokens
Token, Token2 :String; //a token
Dummy :Integer; //index of a token
//are we parsing an identifier-path (identifiers
InIdentPath :( //separated by dots etc.)
iipNo, //no, we don't
iipIdent, //yes, we just read an identifier/value
iipDot //yes, we just read a dot
);
ValueWasString :Boolean; //if the last value was a string
//"absolute", "deprecated", "library", "platform" or etc. found?
DirectiveFound :Boolean;
//a keyword found ending the expression (the statement)?
KeyWordFound :Boolean;
begin
Expression := '';
Token := ExprTokens;
if (Token = '') and not GetToken(Token) then //get first token
Exception(etSyntax, 'No expression before end of file!');
InIdentPath := iipNo; //not parsing an identifier at the moment
ValueWasString := False; //the current value is no string (no value at all)
DirectiveFound := False; //no directive found so far
KeyWordFound := False; //statement not end reached
//as long as no directive or character ending the expression
//or a closing brace/bracket found
while not DirectiveFound and not KeyWordFound and
((Length(Token) <> 1) or
not (Token[1] in [';', ',', ':', ')', ']'])) and
(Token <> ':=') and (Token <> '..') and
((LowerCase(Token) <> 'of') or (InIdentPath = iipDot)) do
begin
//found an identifier?
if (Token <> '') and (Token[1] in StartIdentifierChars) and
not IsWordIn(Token, Operators, Dummy) then
begin
if InIdentPath = iipIdent then
begin
Token2 := LowerCase(Token);
if (not (aedAbsolute in EndDirectives) or (Token2 <> 'absolute')) and
(not (aedIndexName in EndDirectives) or
((Token2 <> 'index') and (Token2 <> 'name'))) and
(not (aedResident in EndDirectives) or (Token2 <> 'resident')) and
(not (aedPortability in EndDirectives) or
not IsWordIn(Token2, IdentPortability, Dummy)) and
(not (aedProperty in EndDirectives) or
not IsWordIn(Token2, PropertyWords, Dummy)) then
ExceptionFmt(etSyntax,
'Found identifier "%s" directly after another identifier!',
[Token]);
DirectiveFound := True; //directive found, expression ended
end
else
begin
InIdentPath := iipIdent; //we just read an identifier
ValueWasString := False;
Expression := Expression + ' ' + Token;
end;
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!');
InIdentPath := iipDot; //another identifier will be expected
Expression := Expression + ' .';
end; //case Token = '.'
'(': begin
//braces are not allowed directly after a dot
if InIdentPath = iipDot then
Exception(etSyntax,
'Found "(" after ".", expected identifier!');
if InIdentPath = iipNo then //no identifier before this?
begin
//parse everything between the braces
Expression := Expression + ' (';
repeat
Token2 := '';
Token := ParseConstantExpression(Token2);
Expression := Expression + ' ' + Token2 + Token;
until
(Token <> ',') and //initialization of array-constants
// (Token <> ':='); //named parameters (automation objects)
(Token <> ':') and //initialization of record-constants
(Token <> ';'); //initialization of record-constants
if Token <> ')' then
Exception(etSyntax, 'Expected ")" after "(", failed!');
end
else
begin
//parse everything between the braces
Expression := Expression + ' (';
repeat
Token2 := '';
Token := ParseConstantExpression(Token2);
Expression := Expression + ' ' + Token2 + Token;
until
True;
// (Token <> ',');// and //parameter-list of a function-call;
// (Token <> ':='); //named parameters (automation objects)
// (Token <> ':') and //Write(abc:Width:...)
// (Token <> ';'); //initialization of record-constants
if Token <> ')' then
Exception(etSyntax, 'Expected ")" after "(", failed!');
end;
InIdentPath := iipIdent;
ValueWasString := False;
end; //case Token = '('
'[': if InIdentPath = iipNo then //no identifier before it?
begin //set-constructor
Expression := Expression + ' [';
repeat
Token2 := ''; //parse all items/elements
Token := ParseConstantExpression(Token2);
Expression := Expression + ' ' + Token2 + Token;
until (Token <> ',') and //separated by comma and
(Token <> '..'); //double-dots
if Token <> ']' then
Exception(etSyntax, 'Expected "]" after "[", failed!');
InIdentPath := iipIdent;
ValueWasString := False;
end
else
begin
//brackets are not allowed directly after a dot
if InIdentPath = iipDot then
Exception(etSyntax,
'Found "[" after ".", expected identifier!');
Expression := Expression + ' [';
repeat
Token2 := ''; //parse all indizes
Token := ParseConstantExpression(Token2);
Expression := Expression + ' ' + Token2 + Token;
until Token <> ','; //separated by comma
if Token <> ']' then
Exception(etSyntax, 'Expected "]" after "[", failed!');
InIdentPath := iipIdent;
ValueWasString := False;
end; //case Token = '['
'^': if InIdentPath = iipDot then //dereferencing only of idents
Exception(etSyntax, 'Found "^" after "."!')
else
if (InIdentPath = iipIdent) and not ValueWasString then
Expression := Expression + '^'
else
begin //insert control-character: ^C for #3 etc.
//an awfull Turbo Pascal remnant
if not GetToken(Token) or (length(Token) <> 1) then
Exception(etSyntax,
'Expected single character after "^" for control-sequence!');
if not ValueWasString then //not in a string?
Expression := Expression + ' '; //add separator
Expression := Expression + '^' + Token; //add the char-token
InIdentPath := iipIdent; //read a value
ValueWasString := True; //of type string
end; // case Token = '^'
else
raise SysUtils.Exception.Create('Error: invalid character in function-body; change and recompile DelphiDoc!');
end //if Token is (, [, ., or ^ ; case Token of
else
if (Token = '=') and (aedEqual in EndDirectives) then
DirectiveFound := True
else
if (Token[1] in ['0'..'9', '.', '''', '$', '#']) or //is a value?
((PascalDialect = pdFreePascal) and (Token[1] in ['&', '%'])) then
begin
if (InIdentPath <> iipNo) and
(not ValueWasString or not (Token[1] in ['''', '#'])) then
Exception(etSyntax,
'Found number directly after another/identifier!');
InIdentPath := iipIdent;
//not another part of a string?
if not ValueWasString or not (Token[1] in ['''', '#']) then
Expression := Expression + ' '; //add separating space
ValueWasString := Token[1] in ['''', '#']; //is a string?
if Token[1] = '#' then //is a character-sign?
begin
if not GetToken(Token) or
(not (Token[1] in ['0'..'9', '$']) and
((PascalDialect <> pdFreePascal) or
not (Token[1] in ['&', '%']))) then
Exception(etSyntax,
'Expected number of character after "#", failed!');
Token := '#' + Token; //prepend the character-sign again
end;
Expression := Expression + Token; //append the token
end
else //some other operator
begin
InIdentPath := iipNo; //no identifier found so far after operator
ValueWasString := False; //and also no string
//merged with following ident gives a pointer
Expression := Expression + ' ' + Token;
//nothing further to do to handle the operator
end;
//if not at end of expression (by a directive), get the next token
if not DirectiveFound then
begin
PushPosition;
if not GetToken(Token) then
Exception(etSyntax, 'Unexpected end of file in constant expression!');
//could be a keyword?
KeyWordFound := (InIdentPath <> iipDot) and
IsWordIn(Token, TopLevelWordsFile, Dummy);
if KeyWordFound then
begin
Token := '';
PopPosition;
end
else
LosePosition;
end;
end; //while Token not EndOfStmt
Result := Token; //return next (last known) token
if (Expression <> '') and (Expression[1] <> '^') then
begin
assert(Expression[1] = ' ');
Delete(Expression, 1, 1);
end;
ExprTokens := Expression;
end;
{Parses a list of definitions of parameters, terminated by a closing brace ")",
like used in in functions or function types or the list of array indices of
properties, terminating by a closing bracket "]".
~param List the list of parameters to which the parsed identifiers
should be added
~param PropertyIndices if it's a list of array indices instead of function
parameters }
procedure TIdentifierParser.ParseParams(List: TIdentifierList;
PropertyIndices: Boolean);
var ParamList :TIdentifierList; //the list of parameters with same type
Token :String; //a token
//kind of the parameter (normal "", "var", "const" or "out")
Kind :TParameterKind;
Param :TParameter; //each parameter
TheType :TType; //type of the parameter
Init :String; //default value
i :Integer; //counter through parameters
begin
//create list of together defined parameters (share same type etc.)
ParamList := TIdentifierList.Create;
try
Token := '';
//while list hasn't reached the end
while ((Token <> '') or GetToken(Token)) and
((PropertyIndices or (Token <> ')')) and
(not PropertyIndices or (Token <> ']'))) do
begin
//clear the list of parameters
ParamList.RemoveAll(False);
//get kind of the parameter
Init := LowerCase(Token);
if Init = ParameterFormalAttributNames[pkReference] then
Kind := pkReference
else
if Init = ParameterFormalAttributNames[pkConstant] then
Kind := pkConstant
else
if Init = ParameterFormalAttributNames[pkOut] then
Kind := pkOut
else
Kind := pkNormal;
if Kind <> pkNormal then
if not GetToken(Token) then
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -