From 6a9f045e8b7ef4bd2f2910fd8e862d6389e6c5d3 Mon Sep 17 00:00:00 2001 From: Stefan Glienke Date: Thu, 9 Sep 2021 11:27:59 +0200 Subject: [PATCH 1/9] added support for varargs keyword --- Source/DelphiAST.pas | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Source/DelphiAST.pas b/Source/DelphiAST.pas index c908cc5..55f2678 100644 --- a/Source/DelphiAST.pas +++ b/Source/DelphiAST.pas @@ -112,6 +112,7 @@ TPasSyntaxTreeBuilder = class(TmwSimplePasParEx) procedure DirectiveBindingMessage; override; procedure DirectiveCalling; override; procedure DirectiveInline; override; + procedure DirectiveVarargs; override; procedure DispInterfaceForward; override; procedure DotOp; override; procedure ElseExpression; override; @@ -294,7 +295,8 @@ TStringStreamHelper = class helper for TStringStream type TAttributeValue = (atAsm, atTrue, atFunction, atProcedure, atClassOf, atClass, atConst, atConstructor, atDestructor, atEnum, atInterface, atNil, atNumeric, - atOut, atPointer, atName, atString, atSubRange, atVar, atDispInterface); + atOut, atPointer, atName, atString, atSubRange, atVar, atDispInterface, + atVarargs); var AttributeValues: array[TAttributeValue] of string; @@ -1151,6 +1153,16 @@ procedure TPasSyntaxTreeBuilder.DirectiveInline; inherited; end; +procedure TPasSyntaxTreeBuilder.DirectiveVarargs; +begin + FStack.Push(ntExternal).SetAttribute(anType, AttributeValues[atVarArgs]); + try + inherited; + finally + FStack.Pop; + end; +end; + procedure TPasSyntaxTreeBuilder.DispInterfaceForward; begin FStack.Peek.SetAttribute(anForwarded, AttributeValues[atTrue]); From fb17badcd86b30ac37dc1b70a72b8c8960ceef43 Mon Sep 17 00:00:00 2001 From: Stefan Glienke Date: Tue, 2 Aug 2022 14:36:09 +0200 Subject: [PATCH 2/9] added support for external keyword --- Source/DelphiAST.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/DelphiAST.pas b/Source/DelphiAST.pas index 55f2678..3f20e13 100644 --- a/Source/DelphiAST.pas +++ b/Source/DelphiAST.pas @@ -296,7 +296,7 @@ TStringStreamHelper = class helper for TStringStream TAttributeValue = (atAsm, atTrue, atFunction, atProcedure, atClassOf, atClass, atConst, atConstructor, atDestructor, atEnum, atInterface, atNil, atNumeric, atOut, atPointer, atName, atString, atSubRange, atVar, atDispInterface, - atVarargs); + atVarargs, atExternal); var AttributeValues: array[TAttributeValue] of string; @@ -1357,7 +1357,7 @@ procedure TPasSyntaxTreeBuilder.ExpressionList; procedure TPasSyntaxTreeBuilder.ExternalDirective; begin - FStack.Push(ntExternal); + FStack.Push(ntExternal).SetAttribute(anType, AttributeValues[atExternal]); try inherited; finally From e0f88b77544b68ace8a5e2a06ce2b0b8483f8647 Mon Sep 17 00:00:00 2001 From: Stefan Glienke Date: Thu, 9 Sep 2021 11:28:34 +0200 Subject: [PATCH 3/9] added support for unsafe keyword after method --- Source/SimpleParser/SimpleParser.Lexer.pas | 2 +- Source/SimpleParser/SimpleParser.pas | 47 ++++++---------------- 2 files changed, 13 insertions(+), 36 deletions(-) diff --git a/Source/SimpleParser/SimpleParser.Lexer.pas b/Source/SimpleParser/SimpleParser.Lexer.pas index 585f2e5..e74b889 100644 --- a/Source/SimpleParser/SimpleParser.Lexer.pas +++ b/Source/SimpleParser/SimpleParser.Lexer.pas @@ -908,7 +908,7 @@ function TmwBasePasLex.Func66: TptTokenKind; Result := ptIdentifier; if KeyComp('Single') then FExID := ptSingle else if KeyComp('Type') then Result := ptType else - if KeyComp('Unsafe') then Result := ptUnsafe; + if KeyComp('Unsafe') then FExID := ptUnsafe; end; function TmwBasePasLex.Func69: TptTokenKind; diff --git a/Source/SimpleParser/SimpleParser.pas b/Source/SimpleParser/SimpleParser.pas index d7efd2c..e051017 100644 --- a/Source/SimpleParser/SimpleParser.pas +++ b/Source/SimpleParser/SimpleParser.pas @@ -180,7 +180,8 @@ interface ptFinal, ptExperimental, ptDispId, - ptNoreturn + ptNoreturn, + ptUnsafe ]; type @@ -4860,38 +4861,18 @@ procedure TmwSimplePasPar.LabelDeclarationSection; procedure TmwSimplePasPar.ProceduralDirective; begin case GenID of - ptAbstract: - begin - DirectiveBinding; - end; + ptAbstract, ptDynamic, ptMessage, ptNoreturn, ptOverload, ptOverride, ptReintroduce, ptVirtual: + DirectiveBinding; ptCdecl, ptPascal, ptRegister, ptSafeCall, ptStdCall: - begin - DirectiveCalling; - end; + DirectiveCalling; ptExport, ptFar, ptNear: - begin - Directive16Bit; - end; + Directive16Bit; ptExternal: - begin - ExternalDirective; - end; - ptDynamic, ptMessage, ptOverload, ptOverride, ptReintroduce, ptVirtual, ptNoreturn: - begin - DirectiveBinding; - end; - ptAssembler: - begin - NextToken; - end; - ptStatic: - begin - NextToken; - end; + ExternalDirective; + ptAssembler, ptFinal, ptExperimental, ptDelayed, ptStatic, ptUnsafe: + NextToken; ptInline: - begin - DirectiveInline; - end; + DirectiveInline; ptDeprecated: DirectiveDeprecated; ptLibrary: @@ -4902,12 +4883,8 @@ procedure TmwSimplePasPar.ProceduralDirective; DirectiveLocal; ptVarargs: DirectiveVarargs; - ptFinal, ptExperimental, ptDelayed: - NextToken; else - begin - SynError(InvalidProceduralDirective); - end; + SynError(InvalidProceduralDirective); end; end; @@ -5915,4 +5892,4 @@ procedure TmwSimplePasPar.CustomAttribute; AttributeSections; end; -end. \ No newline at end of file +end. From fc8fd368ca5f7efb1aa0fd9104577cd74dc8c992 Mon Sep 17 00:00:00 2001 From: Stefan Glienke Date: Thu, 9 Sep 2021 11:36:52 +0200 Subject: [PATCH 4/9] added MANAGED_RECORD to InitDefinesDefinedByCompiler --- Source/SimpleParser/SimpleParser.Lexer.pas | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Source/SimpleParser/SimpleParser.Lexer.pas b/Source/SimpleParser/SimpleParser.Lexer.pas index e74b889..933a03e 100644 --- a/Source/SimpleParser/SimpleParser.Lexer.pas +++ b/Source/SimpleParser/SimpleParser.Lexer.pas @@ -2849,6 +2849,9 @@ procedure TmwBasePasLex.InitDefinesDefinedByCompiler; {$IFDEF ELF} AddDefine('ELF'); {$ENDIF} + {$IFDEF MANAGED_RECORD} + AddDefine('MANAGED_RECORD'); + {$ENDIF} {$IFDEF NEXTGEN} AddDefine('NEXTGEN'); {$ENDIF} From 4e7e13ae1f05e65fa9a03dd25a017e5873e00303 Mon Sep 17 00:00:00 2001 From: Stefan Glienke Date: Wed, 20 Jul 2022 12:18:37 +0200 Subject: [PATCH 5/9] avoid deprecated warning --- Source/SimpleParser/SimpleParser.Lexer.pas | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Source/SimpleParser/SimpleParser.Lexer.pas b/Source/SimpleParser/SimpleParser.Lexer.pas index 933a03e..203233d 100644 --- a/Source/SimpleParser/SimpleParser.Lexer.pas +++ b/Source/SimpleParser/SimpleParser.Lexer.pas @@ -1907,8 +1907,13 @@ function TmwBasePasLex.IsIdentifiers(AChar: Char): Boolean; begin // assuming Delphi identifier may include letters, digits, underscore symbol // and any character over 127 except surrogates + {$IF RTLVersion >= 25} + Result := AChar.IsLetterOrDigit or (AChar = '_') + or ((Ord(AChar) > 127) and not AChar.IsHighSurrogate and not AChar.IsLowSurrogate); + {$ELSE} Result := TCharacter.IsLetterOrDigit(AChar) or (AChar = '_') or ((Ord(AChar) > 127) and not TCharacter.IsHighSurrogate(AChar) and not TCharacter.IsLowSurrogate(AChar)); + {$IFEND} end; procedure TmwBasePasLex.LFProc; From a82ee2c113c78058c5d820387f15f1814968c146 Mon Sep 17 00:00:00 2001 From: Stefan Glienke Date: Wed, 20 Jul 2022 18:31:48 +0200 Subject: [PATCH 6/9] added missing detection of directives on anonymous method type --- Source/SimpleParser/SimpleParser.pas | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/Source/SimpleParser/SimpleParser.pas b/Source/SimpleParser/SimpleParser.pas index e051017..cbbc681 100644 --- a/Source/SimpleParser/SimpleParser.pas +++ b/Source/SimpleParser/SimpleParser.pas @@ -5565,6 +5565,13 @@ procedure TmwSimplePasPar.AnonymousMethod; FormalParameterList; end; end; + + while ExID in [ptCdecl, ptExport, ptFar, ptNear, ptOverload, ptOverride, + ptPascal, ptRegister, ptSafeCall, ptStdCall, ptStatic, ptVarargs] do + begin + ProceduralDirective; + end; + Block; end; @@ -5573,21 +5580,27 @@ procedure TmwSimplePasPar.AnonymousMethodType; ExpectedEx(ptReference); Expected(ptTo); case TokenID of - ptProcedure: + ptFunction: begin NextToken; if TokenID = ptRoundOpen then FormalParameterList; + Expected(ptColon); + ReturnType; end; - ptFunction: + ptProcedure: begin NextToken; if TokenID = ptRoundOpen then FormalParameterList; - Expected(ptColon); - ReturnType; end; end; + + while ExID in [ptCdecl, ptExport, ptFar, ptNear, ptOverload, ptOverride, + ptPascal, ptRegister, ptSafeCall, ptStdCall, ptStatic, ptVarargs] do + begin + ProceduralDirective; + end; end; procedure TmwSimplePasPar.AddDefine(const ADefine: string); From c7eb5cf7c2307aeef02571b6a05e5f4eafee01df Mon Sep 17 00:00:00 2001 From: Stefan Glienke Date: Wed, 20 Jul 2022 18:32:30 +0200 Subject: [PATCH 7/9] implemented handling of parentheses in conditional expression --- Source/SimpleParser/SimpleParser.Lexer.pas | 33 ++++++++++++++++++---- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/Source/SimpleParser/SimpleParser.Lexer.pas b/Source/SimpleParser/SimpleParser.Lexer.pas index 203233d..793ecd1 100644 --- a/Source/SimpleParser/SimpleParser.Lexer.pas +++ b/Source/SimpleParser/SimpleParser.Lexer.pas @@ -1703,7 +1703,7 @@ function TmwBasePasLex.EvaluateConditionalExpression(const AParams: String): Boo LIsRtlVer: Boolean; LOper: string; LValue: Integer; - p: Integer; + p, LBracketLevel: Integer; begin { TODO : Expand support for <=> evaluations (complicated to do). Expand support for NESTED expressions } LEvaluation := leeNone; @@ -1742,11 +1742,10 @@ function TmwBasePasLex.EvaluateConditionalExpression(const AParams: String): Boo end; end; end else - if (Pos('DEFINED(', LParams) = 1) or (Pos('NOT DEFINED(', LParams) = 1) then + if (Pos('DEFINED(', LParams) = 1) or (Pos('NOT DEFINED(', LParams) = 1) or (Pos('(', LParams) = 1) then begin Result := True; // Optimistic - while (Pos('DEFINED(', LParams) = 1) or (Pos('NOT DEFINED(', LParams) = 1) do - begin + repeat if Pos('DEFINED(', LParams) = 1 then begin LDefine := Copy(LParams, 9, Pos(')', LParams) - 9); @@ -1766,6 +1765,30 @@ function TmwBasePasLex.EvaluateConditionalExpression(const AParams: String): Boo leeAnd: Result := Result and (not IsDefined(LDefine)); leeOr: Result := Result or (not IsDefined(LDefine)); end; + end + else if Pos('(', LParams) = 1 then + begin + LBracketLevel := 1; + for p := 2 to Length(LParams) do + case LParams[p] of + '(': Inc(LBracketLevel); + ')': + begin + Dec(LBracketLevel); + if LBracketLevel = 0 then + Break; + end; + end; + if LBracketLevel = 0 then // matching closing bracket was found + begin + LDefine := Copy(LParams, 2, p - 2); + LParams := TrimLeft(Copy(LParams, p + 1)); + case LEvaluation of + leeNone: Result := EvaluateConditionalExpression(LDefine); + leeAnd: Result := Result and EvaluateConditionalExpression(LDefine); + leeOr: Result := Result or EvaluateConditionalExpression(LDefine); + end; + end; end; // Determine next Evaluation if Pos('AND ', LParams) = 1 then @@ -1778,7 +1801,7 @@ function TmwBasePasLex.EvaluateConditionalExpression(const AParams: String): Boo LEvaluation := leeOr; LParams := TrimLeft(Copy(LParams, 3, Length(LParams) - 2)); end; - end; + until not ((Pos('DEFINED(', LParams) = 1) or (Pos('NOT DEFINED(', LParams) = 1) or (Pos('(', LParams) = 1)); end else Result := False; end; From b360c2520428c1c7b58f403575fcf21cf7209799 Mon Sep 17 00:00:00 2001 From: Stefan Glienke Date: Mon, 22 Jan 2024 18:58:41 +0100 Subject: [PATCH 8/9] fix for older versions --- Source/DelphiAST.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/DelphiAST.pas b/Source/DelphiAST.pas index 3f20e13..0a784b6 100644 --- a/Source/DelphiAST.pas +++ b/Source/DelphiAST.pas @@ -1078,7 +1078,7 @@ function TPasSyntaxTreeBuilder.DequoteString(const S: string): string; QuoteCount, I: Integer; begin QuoteCount := 0; - for I := Low(S) to High(S) do + for I := 1 to Length(S) do if S[I] = '''' then Inc(QuoteCount) else From 876ba612479c5b680aa7c1f20df8a9e4a437b310 Mon Sep 17 00:00:00 2001 From: Stefan Glienke Date: Mon, 27 Jul 2026 16:20:05 +0200 Subject: [PATCH 9/9] support for align(identifier) --- Source/SimpleParser/SimpleParser.pas | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Source/SimpleParser/SimpleParser.pas b/Source/SimpleParser/SimpleParser.pas index cbbc681..15989be 100644 --- a/Source/SimpleParser/SimpleParser.pas +++ b/Source/SimpleParser/SimpleParser.pas @@ -4388,7 +4388,15 @@ procedure TmwSimplePasPar.RecordAlign; procedure TmwSimplePasPar.RecordAlignValue; begin - Expected(ptIntegerConst); + if TokenID = ptRoundOpen then + begin + RoundOpen; + if TokenID in [ptIdentifier, ptIntegerConst] then + NextToken; + RoundClose; + end + else + Expected(ptIntegerConst); end; procedure TmwSimplePasPar.RecordFieldConstant;