Ignore:
Timestamp:
Nov 29, 2017, 12:31:26 PM (7 years ago)
Author:
chronos
Message:
  • Added: New rules flag directing if source node should be generated for them.
  • Added: New and Save menu actions.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/generator/URules.pas

    r117 r119  
    66
    77uses
    8   Classes, SysUtils, fgl, DOM, XmlRead, XmlWrite, UXMLUtils;
     8  Classes, SysUtils, fgl, DOM, XmlRead, XmlWrite, UXMLUtils, Math;
    99
    1010type
     
    3232    NonTerminal: TRule;
    3333    SubItems: TRuleItems;
     34    function GetCharLength: Integer;
    3435    procedure LoadFromXmlNode(Node: TDOMNode);
    3536    procedure SaveToXmlNode(Node: TDOMNode);
    36     function GetBNF: string;
     37    function GetString: string;
    3738    constructor Create;
    3839    destructor Destroy; override;
     
    5253    Grammer: TGrammer;
    5354    RuleType: TRuleType;
     55    function GetCharLength: Integer;
    5456    procedure LoadFromXmlNode(Node: TDOMNode);
    5557    procedure SaveToXmlNode(Node: TDOMNode);
    5658    procedure UpdateRuleReference;
    57     function GetBNF: string;
     59    function GetString: string;
    5860    property ParentRule: TRule read FParentRule write SetParentRule;
    5961  end;
     
    7880  public
    7981    Name: string;
     82    CreateSourceNode: Boolean;
    8083    Items: TRuleItems;
    8184    Links: TRuleLinks;
     
    8588    procedure LoadFromXmlNode(Node: TDOMNode);
    8689    procedure SaveToXmlNode(Node: TDOMNode);
    87     function GetBNF: string;
     90    function GetString: string;
    8891  end;
    8992
     
    9598    procedure LoadFromXmlNode(Node: TDOMNode);
    9699    procedure SaveToXmlNode(Node: TDOMNode);
    97     function GetBNF: string;
     100    function GetString: string;
    98101  end;
    99102
     
    101104
    102105  TGrammer = class
     106  private
     107    FModified: Boolean;
     108    procedure SetModified(AValue: Boolean);
     109    procedure BuildMain(FileName: string);
     110    procedure BuildSource(FileName: string);
     111  public
    103112    FileName: string;
    104113    Rules: TRules;
     
    107116    constructor Create;
    108117    destructor Destroy; override;
    109     function GetBNF: string;
     118    procedure BuildCompiler;
     119    function GetString: string;
     120    property Modified: Boolean read FModified write SetModified;
    110121  end;
    111122
     
    113124
    114125{ TGrammer }
     126
     127procedure TGrammer.SetModified(AValue: Boolean);
     128begin
     129  if FModified = AValue then Exit;
     130  FModified := AValue;
     131end;
     132
     133procedure TGrammer.BuildMain(FileName: string);
     134var
     135  ParserFile: TStringList;
     136begin
     137  ParserFile := TStringList.Create;
     138  with ParserFile do begin
     139    Add('program Compiler;');
     140    Add('');
     141    Add('{$MODE Delphi}');
     142    Add('');
     143    Add('uses');
     144    Add('  Source;');
     145    Add('');
     146    Add('procedure Compile;');
     147    Add('begin');
     148    Add('end;');
     149    Add('');
     150    Add('begin');
     151    Add('  Compile;');
     152    Add('end.');
     153    SaveToFile(FileName);
     154  end;
     155  FreeAndNil(ParserFile);
     156end;
     157
     158procedure TGrammer.BuildSource(FileName: string);
     159var
     160  Rule: TRule;
     161  Item: TRuleItem;
     162  Line: string;
     163  I: Integer;
     164  SourceFile: TStringList;
     165begin
     166  SourceFile := TStringList.Create;
     167  with SourceFile do begin
     168    Add('unit Source;');
     169    Add('');
     170    Add('{$MODE Delphi}');
     171    Add('');
     172    Add('interface');
     173    Add('');
     174    Add('uses');
     175    Add('  fgl;');
     176    Add('');
     177    Add('type');
     178    for Rule in Rules do begin
     179      Add('  T' + Rule.Name + ' = class;');
     180    end;
     181    Add('');
     182    for Rule in Rules do begin
     183      Add('  T' + Rule.Name + ' = class');
     184      for Item in Rule.Items do begin
     185        if Item.RuleItemType = ritNonTerminal then
     186          if Item.Repetitive then
     187          Add('    ' + Item.NonTerminal.Name + ': TFPGObjectList<T' + Item.NonTerminal.Name + '>;')
     188          else Add('    ' + Item.NonTerminal.Name + ': T' + Item.NonTerminal.Name + ';');
     189      end;
     190      Add('  end;' + LineEnding);
     191    end;
     192    Add('');
     193    Add('implementation');
     194    Add('');
     195    for Rule in Rules do
     196    if Rule.CreateSourceNode then begin
     197      Add('function Parse' + Rule.Name + ': Boolean;');
     198      Add('begin');
     199      I := 0;
     200      for Item in Rule.Items do begin
     201        Line := '  ';
     202        if Rule.Items.RuleType = rtOr then begin
     203          if I > 0 then Line := Line + 'else ';
     204          Line := Line + 'if ';
     205        end else
     206        if Rule.Items.RuleType = rtAnd then begin
     207          Line := Line + '';
     208        end;
     209        if Item.RuleItemType = ritTerminal then
     210          Line := Line + 'Expect(''' + Item.Terminal + ''')'
     211        else if Item.RuleItemType = ritNonTerminal then
     212          Line := Line + 'Parse' + Item.NonTerminal.Name;
     213        if Rule.Items.RuleType = rtOr then begin
     214          Line := Line + ' then ';
     215        end else
     216        if Rule.Items.RuleType = rtAnd then begin
     217          Line := Line + ';';
     218        end;
     219        Add(Line);
     220        Inc(I);
     221      end;
     222      if Rule.Items.RuleType = rtOr then begin
     223        Add('  else ShowError(''Unexpected token'');');
     224      end;
     225      Add('end;');
     226      Add('');
     227    end;
     228
     229    Add('end.');
     230
     231    SaveToFile(FileName);
     232  end;
     233  FreeAndNil(SourceFile);
     234end;
    115235
    116236procedure TGrammer.LoadFromXmlFile(FileName: string);
     
    159279
    160280    WriteXMLFile(Doc, FileName);
     281    Modified := False;
    161282  finally
    162283    Doc.Free;
     
    176297end;
    177298
    178 function TGrammer.GetBNF: string;
    179 begin
    180   Result := Rules.GetBNF;
     299procedure TGrammer.BuildCompiler;
     300var
     301  OutputDir: string;
     302begin
     303  OutputDir := 'Generated';
     304  ForceDirectories(OutputDir);
     305
     306  BuildMain(OutputDir + DirectorySeparator + 'Compiler.pas');
     307  BuildSource(OutputDir + DirectorySeparator +'Source.pas');
     308end;
     309
     310function TGrammer.GetString: string;
     311begin
     312  Result := Rules.GetString;
    181313end;
    182314
     
    202334end;
    203335
    204 function TRuleItem.GetBNF: string;
     336function TRuleItem.GetString: string;
    205337begin
    206338  case RuleItemType of
    207339    ritTerminal: Result := '"' + Terminal + '"';
    208340    ritNonTerminal: Result := NonTerminal.Name;
    209     ritSubItems: Result := '(' + SubItems.GetBNF + ')';
     341    ritSubItems: Result := '(' + SubItems.GetString + ')';
    210342  end;
    211343  if Optional then Result := '+' + Result;
     
    230362  FParentRule := AValue;
    231363  SubItems.ParentRule := AValue;
     364end;
     365
     366function TRuleItem.GetCharLength: Integer;
     367begin
     368  case RuleItemType of
     369    ritTerminal: Result := Length(Terminal);
     370    ritNonTerminal: Result := Length(NonTerminal.Name);
     371    ritSubItems: Result := SubItems.GetCharLength;
     372  end;
    232373end;
    233374
     
    283424end;
    284425
    285 function TRuleItems.GetBNF: string;
     426function TRuleItems.GetString: string;
    286427var
    287428  Item: TRuleItem;
     
    293434      else if RuleType = rtOr then Result := Result + ' | ';
    294435    end;
    295     Result := Result + Item.GetBNF;
     436    Result := Result + Item.GetString;
    296437  end;
    297438end;
     
    301442  if FParentRule = AValue then Exit;
    302443  FParentRule := AValue;
     444end;
     445
     446function TRuleItems.GetCharLength: Integer;
     447var
     448  Item: TRuleItem;
     449begin
     450  Result := 0;
     451  if RuleType = rtOr then begin
     452    for Item in Self do
     453      Result := Max(Result, Item.GetCharLength);
     454  end else
     455  if RuleType = rtAnd then begin
     456    for Item in Self do
     457      Result := Result + Item.GetCharLength;
     458  end;
    303459end;
    304460
     
    330486begin
    331487  WriteString(Node, 'Name', Name);
     488  WriteBoolean(Node, 'CreateSourceNode', CreateSourceNode);
    332489
    333490  RuleItemsNode := Node.OwnerDocument.CreateElement('RuleItems');
     
    336493end;
    337494
    338 function TRule.GetBNF: string;
    339 begin
    340   Result := Name + ' ::= ' + Items.GetBNF;
     495function TRule.GetString: string;
     496begin
     497  Result := Name + ' ::= ' + Items.GetString;
    341498end;
    342499
     
    370527begin
    371528  Name := ReadString(Node, 'Name', '');
     529  CreateSourceNode := ReadBoolean(Node, 'CreateSourceNode', False);
    372530
    373531  ItemsNode := Node.FindNode('RuleItems');
     
    418576end;
    419577
    420 function TRules.GetBNF: string;
     578function TRules.GetString: string;
    421579var
    422580  Rule: TRule;
     
    424582  Result := '';
    425583  for Rule in Self do begin
    426     Result := Result + Rule.GetBNF + LineEnding;
     584    Result := Result + Rule.GetString + LineEnding;
    427585  end;
    428586end;
Note: See TracChangeset for help on using the changeset viewer.