Files
bds.mr.dpg/src.lib/dpglib.RuleBlock.pas
T
2026-01-03 18:33:48 +01:00

622 lines
22 KiB
ObjectPascal

unit dpglib.RuleBlock;
interface
uses
System.Classes,
dpgrtl.types,
dpglib.Types,
dpglib.Lookahead,
dpglib.AlternativeBlock;
type
// =========================================================================
// TRuleBlock class specification
// =========================================================================
TRuleBlock = class( TAlternativeBlock,
IRuleBlock,
IAlternativeBlock,
IAlternativeElem,
IGrammarElem)
// ---------------------------------------------------------------
// Members
// ---------------------------------------------------------------
protected
fRuleName : AnsiString;
fArguments : AnsiString;
fThrowSpec : AnsiString;
fReturnAction : AnsiString;
fLocals : AnsiString;
fIgnoreRule : AnsiString;
fExHandlerType : AnsiString;
fExHandlerCode : AnsiString;
fEndNode : IRuleEndElem;
fLock : array of boolean;
fCache : array of ILookahead;
fTestLiterals : boolean;
fDefErrorHandler : boolean;
fLabeledElems : TInterfaceList;
fOneOrMoreBlocks : TInterfaceList;
fNMBlocks : TInterfaceList;
fSynPredBlocks : TInterfaceList;
// ---------------------------------------------------------------
// Internals
// ---------------------------------------------------------------
// protected
// function FindExceptionSpec( pSpec: AnsiString) : IExceptionSpec; overload;
// function FindExceptionSpec( pSpec: IToken): IExceptionSpec; overload;
// ---------------------------------------------------------------
// Constructor/destructor
// ---------------------------------------------------------------
public
constructor Create( pGrammar : IGrammar;
pID : AnsiString); overload;
constructor Create( pGrammar : IGrammar;
pID : AnsiString;
pLine : integer;
pDoAutoGen : boolean); overload;
destructor Destroy; override;
// ---------------------------------------------------------------
// IGrammarElem overrides
// ---------------------------------------------------------------
public
procedure Generate;
function Look( pK: integer): ILookahead;
function AsString : AnsiString;
// ---------------------------------------------------------------
// IAlternativeBlock overrides
// ---------------------------------------------------------------
public
procedure PrepareForAnalysis; override;
// ---------------------------------------------------------------
// IRuleBlock methods
// ---------------------------------------------------------------
protected
function GetRuleName : AnsiString;
function GetArguments : AnsiString;
function GetThrowSpec : AnsiString;
function GetReturnAction : AnsiString;
function GetLocals : AnsiString;
function GetEndNode : IRuleEndElem;
function GetTestLiterals : boolean;
function GetLabeledElems : TInterfaceList;
function GetExHandlerType : AnsiString;
function GetExHandlerCode : AnsiString;
function GetDefErrorHandler : boolean;
function GetIgnoreRule : AnsiString;
function GetOneOrMoreBlocks : TInterfaceList;
function GetNMBlocks : TInterfaceList;
function GetSynPredBlocks : TInterfaceList;
function GetLock( i: integer): boolean;
function GetCache(i: integer): ILookahead;
procedure SetRuleName( pRuleName : AnsiString);
procedure SetArguments( pArguments : AnsiString);
procedure SetThrowSpec( pThrowSpec : AnsiString);
procedure SetReturnAction( pAction : AnsiString);
procedure SetLocals( pLocals : AnsiString);
procedure SetEndNode( pNode : IRuleEndElem);
procedure SetTestLiterals( pTestLiterals : boolean);
procedure SetLabeledElems( pLabeledElems : TInterfaceList);
procedure SetExHandlerType( pExType : AnsiString);
procedure SetExHandlerCode( pExCode : AnsiString);
procedure SetDefErrorHandler( pErrorHandler : boolean);
procedure SetIgnoreRule( pRule : AnsiString);
procedure SetLock( i:integer; pLock : boolean);
procedure SetCache(i:integer; pCache : ILookahead);
public
procedure AddExceptionSpec( pExceptionSpec : IExceptionSpec);
procedure SetOption( pKey, pValue : IToken);
function IsLexerAutoGenRule: boolean;
end;
implementation
uses
System.SysUtils,
dpglib.Messages;
// ****************************************************************************
// Constructor/destructor
// ****************************************************************************
// ============================================================================
// Constructor
// ============================================================================
constructor TRuleBlock.Create(pGrammar: IGrammar; pID: AnsiString);
var
pg: IParserGrammar;
begin
inherited Create( pGrammar);
fRuleName := pID;
fLabeledElems := TInterfaceList.Create;
fOneOrMoreBlocks := TInterfaceList.Create;
fNMBlocks := TInterfaceList.Create;
fSynPredBlocks := TInterfaceList.Create;
fLine := 0;
SetLength( fCache, fGrammar.MaxK +1);
if fGrammar.QueryInterface(IParserGrammar, pg) = S_OK then
fDoAutoGen := true;
end;
// ============================================================================
// Constructor
// ============================================================================
constructor TRuleBlock.Create( pGrammar : IGrammar;
pID : AnsiString;
pLine : integer;
pDoAutoGen : boolean);
begin
inherited Create( pGrammar);
fRuleName := pID;
fLabeledElems := TInterfaceList.Create;
fDoAutoGen := pDoAutoGen;
fOneOrMoreBlocks := TInterfaceList.Create;
fNMBlocks := TInterfaceList.Create;
fSynPredBlocks := TInterfaceList.Create;
fLine := pLine;
SetLength( fCache, fGrammar.MaxK +1);
end;
// ============================================================================
// Destructor
// ============================================================================
destructor TRuleBlock.Destroy;
var
i : integer;
begin
FreeAndNil( fLabeledElems);
FreeAndNil( fOneOrMoreBlocks);
FreeAndNil( fNMBlocks);
FreeAndNil( fSynPredBlocks);
for i:=Low(fCache) to High(fCache) do
fCache[i] := nil;
fCache := nil;
inherited;
end;
// ****************************************************************************
// IGrammarElem overrides
// ****************************************************************************
// ============================================================================
// Generate
// ============================================================================
procedure TRuleBlock.Generate;
begin
fGrammar.Generator.Gen( self);
end;
// ============================================================================
// Look
// ============================================================================
function TRuleBlock.Look(pK: integer): ILookahead;
begin
result := fGrammar.LLkAnalyzer.Look( pK, self);
end;
// ============================================================================
// AsString
// ============================================================================
function TRuleBlock.AsString: AnsiString;
begin
result := '';
end;
// ****************************************************************************
// IAlternativeBlock overrides
// ****************************************************************************
// ============================================================================
// PrepareForAnalysis
// ============================================================================
procedure TRuleBlock.PrepareForAnalysis;
begin
inherited;
SetLength( fLock, fGrammar.MaxK +1);
end;
// ****************************************************************************
// IRuleBlock implementation
// ****************************************************************************
// ============================================================================
// GetArguments
// ============================================================================
function TRuleBlock.GetArguments: AnsiString;
begin
result := fArguments;
end;
// ============================================================================
// GetDefErrorHandler
// ============================================================================
function TRuleBlock.GetDefErrorHandler: boolean;
begin
result := fDefErrorHandler;
end;
// ============================================================================
// GetEndNode
// ============================================================================
function TRuleBlock.GetEndNode: IRuleEndElem;
begin
result := fEndNode;
end;
// ============================================================================
// GetIgnoreRule
// ============================================================================
function TRuleBlock.GetIgnoreRule: AnsiString;
begin
result := fIgnoreRule;
end;
// ============================================================================
// GetLock
// ============================================================================
function TRuleBlock.GetLock(i: integer): boolean;
begin
result := fLock[i];
end;
// ============================================================================
// GetCache
// ============================================================================
function TRuleBlock.GetCache(i: integer): ILookahead;
begin
result := fCache[i];
end;
// ============================================================================
// GetLabeledElems
// ============================================================================
function TRuleBlock.GetLabeledElems: TInterfaceList;
begin
result := fLabeledElems;
end;
// ============================================================================
// GetReturnAction
// ============================================================================
function TRuleBlock.GetReturnAction: AnsiString;
begin
result := fReturnAction;
end;
// ============================================================================
// GetLocals
// ============================================================================
function TRuleBlock.GetLocals: AnsiString;
begin
result := fLocals;
end;
// ============================================================================
// GetRuleName
// ============================================================================
function TRuleBlock.GetRuleName: AnsiString;
begin
result := fRuleName;
end;
// ============================================================================
// GetTestLiterals
// ============================================================================
function TRuleBlock.GetTestLiterals: boolean;
begin
result := fTestLiterals;
end;
// ============================================================================
// GetThrowSpec
// ============================================================================
function TRuleBlock.GetThrowSpec: AnsiString;
begin
result := fThrowSpec;
end;
// ============================================================================
// SetArguments
// ============================================================================
procedure TRuleBlock.SetArguments(pArguments: AnsiString);
begin
fArguments := pArguments;
end;
// ============================================================================
// SetDefErrorHandler
// ============================================================================
procedure TRuleBlock.SetDefErrorHandler(pErrorHandler: boolean);
begin
fDefErrorHandler := pErrorHandler;
end;
// ============================================================================
// SetEndNode
// ============================================================================
procedure TRuleBlock.SetEndNode(pNode: IRuleEndElem);
begin
fEndNode := pNode;
end;
// ============================================================================
// SetIgnoreRule
// ============================================================================
procedure TRuleBlock.SetIgnoreRule(pRule: AnsiString);
begin
fIgnoreRule := pRule;
end;
// ============================================================================
// SetLock
// ============================================================================
procedure TRuleBlock.SetLock(i: integer; pLock: boolean);
begin
fLock[i] := pLock;
end;
// ============================================================================
// SetCache
// ============================================================================
procedure TRuleBlock.SetCache(i: integer; pCache: ILookahead);
begin
fCache[i] := pCache;
end;
// ============================================================================
// SetLabeledElems
// ============================================================================
procedure TRuleBlock.SetLabeledElems(pLabeledElems: TInterfaceList);
begin
FreeAndNil( fLabeledElems);
fLabeledElems := pLabeledElems;
end;
// ============================================================================
// SetReturnAction
// ============================================================================
procedure TRuleBlock.SetReturnAction(pAction: AnsiString);
begin
fReturnAction := pAction;
end;
// ============================================================================
// SetLocals
// ============================================================================
procedure TRuleBlock.SetLocals(pLocals: AnsiString);
begin
fLocals := pLocals;
end;
// ============================================================================
// SetRuleName
// ============================================================================
procedure TRuleBlock.SetRuleName(pRuleName: AnsiString);
begin
fRuleName := pRuleName;
end;
// ============================================================================
// SetTestLiterals
// ============================================================================
procedure TRuleBlock.SetTestLiterals(pTestLiterals: boolean);
begin
fTestLiterals := pTestLiterals;
end;
// ============================================================================
// SetThrowSpec
// ============================================================================
procedure TRuleBlock.SetThrowSpec(pThrowSpec: AnsiString);
begin
fThrowSpec := pThrowSpec;
end;
// ============================================================================
// AddExceptionSpec
// ============================================================================
procedure TRuleBlock.AddExceptionSpec( pExceptionSpec: IExceptionSpec);
begin
(*
if FindExceptionSpec( pExceptionSpec.Lbl.TokenText) <> nil then
begin
if pExceptionSpec.Lbl.TokenText <> '' then
fGrammar.Tool.Error( 'Rule "' + fRuleName + '" already has an exception handler for label: ' + pExceptionSpec.Lbl.TokenText,
fGrammar.GrammarFile,
pExceptionSpec.Lbl.TokenLine,
pExceptionSpec.Lbl.TokenColumn)
else
fGrammar.Tool.Error( 'Rule "' + fRuleName + '" already has an exception handler',
fGrammar.GrammarFile,
pExceptionSpec.Lbl.TokenLine,
pExceptionSpec.Lbl.TokenColumn)
end
else
fExceptionSpecs.Add( pExceptionSpec);
*)
end;
// ============================================================================
// IsLexerAutoGenRule
// ============================================================================
function TRuleBlock.IsLexerAutoGenRule: boolean;
begin
result := (fRuleName = 'nextToken');
end;
// ============================================================================
// SetOption
// ============================================================================
procedure TRuleBlock.SetOption(pKey, pValue: IToken);
var
lg: ILexerGrammar;
ts: ITokenSymbol;
begin
// ---------------------------------------------------------------
// Dummy if. Needed to help commenting ifs.
// ---------------------------------------------------------------
if false then
// ---------------------------------------------------------------
// Option: defaultErrorHandler
// ---------------------------------------------------------------
else if pKey.TokenText = 'defaultErrorHandler' then
begin
if pValue.TokenText = 'true' then
fDefErrorHandler := true
else if pValue.TokenText = 'false' then
fDefErrorHandler := false
else
fGrammar.Tool.Error( 'Value for "defaultErrorHandler" must be true or false',
fGrammar.GrammarFile,
pKey.TokenLine,
pKey.TokenColumn)
end
// ---------------------------------------------------------------
// Option: testLiterals
// ---------------------------------------------------------------
else if pKey.TokenText = 'testLiterals' then
begin
if pValue.TokenText = 'true' then
fTestLiterals := true
else if pValue.TokenText = 'false' then
fTestLiterals := false
else
fGrammar.Tool.Error( 'Value for "testLiterals" must be true or false',
fGrammar.GrammarFile,
pKey.TokenLine,
pKey.TokenColumn)
end
// ---------------------------------------------------------------
// Option: generateAmbigWarnings
// ---------------------------------------------------------------
else if pKey.TokenText = 'generateAmbigWarnings' then
begin
if pValue.TokenText = 'true' then
fGenAmbigWarnings := true
else if pValue.TokenText = 'false' then
fGenAmbigWarnings := false
else
fGrammar.Tool.Error( 'Value for "generateAmbigWarnings" must be true or false',
fGrammar.GrammarFile,
pKey.TokenLine,
pKey.TokenColumn)
end
// ---------------------------------------------------------------
// Option: ignore
// ---------------------------------------------------------------
else if pKey.TokenText = 'ignore' then
begin
if fGrammar.QueryInterface(ILexerGrammar, lg) <> S_OK then
fGrammar.Tool.Error( '"Ignore" option only valid for lexer rules',
fGrammar.GrammarFile,
pKey.TokenLine,
pKey.TokenColumn)
else
fIgnoreRule := pValue.TokenText
end
// ---------------------------------------------------------------
// Option: paraphrase
// ---------------------------------------------------------------
else if pKey.TokenText = 'paraphrase' then
begin
if fGrammar.QueryInterface(ILexerGrammar, lg) <> S_OK then
fGrammar.Tool.Error( '"Paraphrase" option only valid for lexer rules',
fGrammar.GrammarFile,
pKey.TokenLine,
pKey.TokenColumn)
else
begin
ts := fGrammar.TokenManager.TokenSymbol[fRuleName];
if ts = nil then
fGrammar.Tool.Panic('Cannot find token associated with rule ' + fRuleName)
else
ts.Paraphrase := pValue.TokenText
end
end
// ---------------------------------------------------------------
// Illegal option
// ---------------------------------------------------------------
else
fGrammar.Tool.Error( Format( MSG_W_ILLEGALRULEOPTION, [pKey.TokenText]),
fGrammar.GrammarFile,
pKey.TokenLine,
pKey.TokenColumn);
end;
// ****************************************************************************
// Internals
// ****************************************************************************
function TRuleBlock.GetOneOrMoreBlocks: TInterfaceList;
begin
result := fOneOrMoreBlocks;
end;
function TRuleBlock.GetNMBlocks : TInterfaceList;
begin
result := fNMBlocks;
end;
function TRuleBlock.GetSynPredBlocks: TInterfaceList;
begin
result := fSynPredBlocks;
end;
function TRuleBlock.GetExHandlerCode: AnsiString;
begin
result := fExHandlerCode;
end;
function TRuleBlock.GetExHandlerType: AnsiString;
begin
result := fExHandlerType;
end;
procedure TRuleBlock.SetExHandlerCode(pExCode: AnsiString);
begin
fExHandlerCode := pExCode;
end;
procedure TRuleBlock.SetExHandlerType(pExType: AnsiString);
begin
fExHandlerType := pExType;
end;
end.