source: branches/generator/UGrammer.pas

Last change on this file was 137, checked in by chronos, 6 years ago
  • Added: Lookup tables can be defined and their usage set from grammer rules.
File size: 20.1 KB
Line 
1unit UGrammer;
2
3{$mode delphi}{$H+}
4
5interface
6
7uses
8 Classes, SysUtils, fgl, DOM, XmlWrite, UXMLUtils, Math;
9
10type
11 TRule = class;
12 TRules = class;
13 TGrammer = class;
14 TRuleItems = class;
15 TLookupTable = class;
16
17 TRuleItemType = (ritTerminal, ritNonTerminal, ritSubItems, ritTerminalRange);
18 TGrammerNotation = (gnBnf, gnEbnf);
19 TLookupTableAction = (taCreate, taReference);
20
21 { TRuleItem }
22
23 TRuleItem = class
24 private
25 FGrammer: TGrammer;
26 FParentRule: TRule;
27 procedure SetGrammer(AValue: TGrammer);
28 procedure SetParentRule(AValue: TRule);
29 public
30 Optional: Boolean;
31 Repetitive: Boolean;
32 AnyExcept: Boolean;
33 RuleItemType: TRuleItemType;
34 Terminal: string;
35 TerminalFrom: string;
36 TerminalTo: string;
37 EscapedStrings: Boolean;
38 NonTerminalName: string;
39 NonTerminal: TRule;
40 SubItems: TRuleItems;
41 LookupTableUsed: Boolean;
42 LookupTable: TLookupTable;
43 LookupTableName: string;
44 LookupTableAction: TLookupTableAction;
45 function GetCharLength: Integer;
46 procedure LoadFromXmlNode(Node: TDOMNode);
47 procedure SaveToXmlNode(Node: TDOMNode);
48 function GetString: string;
49 function ExportAsString(Notation: TGrammerNotation): string;
50 constructor Create;
51 destructor Destroy; override;
52 property Grammer: TGrammer read FGrammer write SetGrammer;
53 property ParentRule: TRule read FParentRule write SetParentRule;
54 end;
55
56 TRuleType = (rtAnd, rtOr);
57
58 { TRuleItems }
59
60 TRuleItems = class(TFPGObjectList<TRuleItem>)
61 private
62 FParentRule: TRule;
63 procedure SetParentRule(AValue: TRule);
64 public
65 Grammer: TGrammer;
66 RuleType: TRuleType;
67 WithWhiteSpeaces: Boolean;
68 function GetCharLength: Integer;
69 procedure LoadFromXmlNode(Node: TDOMNode);
70 procedure SaveToXmlNode(Node: TDOMNode);
71 procedure UpdateRuleReference;
72 function GetString: string;
73 function ExportAsString(Notation: TGrammerNotation): string;
74 property ParentRule: TRule read FParentRule write SetParentRule;
75 end;
76
77 TRuleLinkType = (ltRequire);
78
79 TRuleLink = class
80 LinkType: TRuleLinkType;
81 Rule: TRule;
82 end;
83
84 TRuleLinks = class(TFPGObjectList<TRuleLink>)
85
86 end;
87
88 TRuleLevel = (rlParser, rlTokenizer);
89
90 { TRule }
91
92 TRule = class
93 private
94 FGrammer: TGrammer;
95 procedure SetGrammer(AValue: TGrammer);
96 public
97 Name: string;
98 CreateSourceNode: Boolean;
99 Level: TRuleLevel;
100 Items: TRuleItems;
101 Links: TRuleLinks;
102 constructor Create;
103 destructor Destroy; override;
104 procedure GetUsedByRule(RefRule: TRule; UsedByRules: TStrings);
105 procedure LoadFromXmlNode(Node: TDOMNode);
106 procedure SaveToXmlNode(Node: TDOMNode);
107 function GetString: string;
108 function ExportAsString(Notation: TGrammerNotation): string;
109 property Grammer: TGrammer read FGrammer write SetGrammer;
110 end;
111
112 { TRules }
113
114 TRules = class(TFPGObjectList<TRule>)
115 Grammer: TGrammer;
116 function FindName(Name: string): TRule;
117 procedure LoadFromXmlNode(Node: TDOMNode);
118 procedure SaveToXmlNode(Node: TDOMNode);
119 function GetString: string;
120 function ExportAsString(Notation: TGrammerNotation): string;
121 end;
122
123 TLookupTableItem = class
124 Name: string;
125 end;
126
127 { TLookupTable }
128
129 TLookupTable = class
130 Name: string;
131 Grammer: TGrammer;
132 Items: TFPGObjectList<TLookupTableItem>;
133 procedure LoadFromXmlNode(Node: TDOMNode);
134 procedure SaveToXmlNode(Node: TDOMNode);
135 constructor Create;
136 destructor Destroy; override;
137 end;
138
139 { TLookupTables }
140
141 TLookupTables = class(TFPGObjectList<TLookupTable>)
142 Grammer: TGrammer;
143 function FindName(Name: string): TLookupTable;
144 procedure LoadFromXmlNode(Node: TDOMNode);
145 procedure SaveToXmlNode(Node: TDOMNode);
146 end;
147
148 { TGrammer }
149
150 TGrammer = class
151 private
152 FModified: Boolean;
153 FOnChange: TNotifyEvent;
154 FOnDestroy: TNotifyEvent;
155 procedure SetModified(AValue: Boolean);
156 procedure DoChange;
157 procedure DoDestroy;
158 public
159 FileName: string;
160 Rules: TRules;
161 LookupTables: TLookupTables;
162 TopRule: TRule;
163 WhiteSpaceRule: TRule;
164 procedure LoadFromXmlFile(FileName: string);
165 procedure SaveToXmlFile(FileName: string);
166 procedure Clear;
167 constructor Create;
168 destructor Destroy; override;
169 procedure GetUsedByRule(RefRule: TRule; UsedByRules: TStrings);
170 function GetString: string;
171 function ExportAsString(Notation: TGrammerNotation): string;
172 procedure Change;
173 property Modified: Boolean read FModified write SetModified;
174 property OnChange: TNotifyEvent read FOnChange write FOnChange;
175 property OnDestroy: TNotifyEvent read FOnDestroy write FOnDestroy;
176 end;
177
178const
179 RuleLevelText: array[TRuleLevel] of string = ('Parser', 'Tokenizer');
180 RuleTypeText: array[TRuleType] of string = ('and', 'or');
181
182
183implementation
184
185{ TLookupTables }
186
187function TLookupTables.FindName(Name: string): TLookupTable;
188var
189 I: Integer;
190begin
191 I := 0;
192 while (I < Count) and (Items[I].Name <> Name) do Inc(I);
193 if I < Count then Result := Items[I]
194 else Result := nil;
195end;
196
197procedure TLookupTables.LoadFromXmlNode(Node: TDOMNode);
198var
199 RuleNode: TDOMNode;
200 LookupTable: TLookupTable;
201begin
202 RuleNode := Node.FirstChild;
203 while Assigned(RuleNode) do begin
204 if RuleNode.NodeName = 'LookupTable' then begin
205 LookupTable := TLookupTable.Create;
206 LookupTable.Grammer := Grammer;
207 LookupTable.LoadFromXmlNode(RuleNode);
208 Add(LookupTable);
209 end;
210 RuleNode := RuleNode.NextSibling;
211 end;
212end;
213
214procedure TLookupTables.SaveToXmlNode(Node: TDOMNode);
215var
216 LookupTable: TLookupTable;
217 RuleNode: TDOMNode;
218begin
219 for LookupTable in Self do begin
220 RuleNode := Node.OwnerDocument.CreateElement('LookupTable');
221 LookupTable.SaveToXmlNode(RuleNode);
222 Node.AppendChild(RuleNode);
223 end;
224end;
225
226{ TLookupTable }
227
228procedure TLookupTable.LoadFromXmlNode(Node: TDOMNode);
229begin
230 Name := ReadString(Node, 'Name', '');
231end;
232
233procedure TLookupTable.SaveToXmlNode(Node: TDOMNode);
234begin
235 WriteString(Node, 'Name', Name);
236end;
237
238constructor TLookupTable.Create;
239begin
240 Items := TFPGObjectList<TLookupTableItem>.Create;
241end;
242
243destructor TLookupTable.Destroy;
244begin
245 FreeAndNil(Items);
246 inherited Destroy;
247end;
248
249{ TGrammer }
250
251procedure TGrammer.SetModified(AValue: Boolean);
252begin
253 if FModified = AValue then Exit;
254 FModified := AValue;
255 if AValue then DoChange;
256end;
257
258procedure TGrammer.DoChange;
259begin
260 if Assigned(FOnChange) then FOnChange(Self);
261end;
262
263procedure TGrammer.DoDestroy;
264begin
265 if Assigned(FOnDestroy) then FOnDestroy(Self);
266end;
267
268procedure TGrammer.LoadFromXmlFile(FileName: string);
269var
270 Doc: TXMLDocument;
271 RootNode: TDOMNode;
272 RulesNode: TDOMNode;
273 Rule: TRule;
274begin
275 Self.FileName := FileName;
276 Rules.Clear;
277 try
278 ReadXMLFileParser(Doc, FileName);
279
280 RootNode := Doc.DocumentElement;
281 if RootNode.NodeName = 'GrammerProject' then begin
282 RulesNode := RootNode.FindNode('Rules');
283 if Assigned(RulesNode) then begin
284 Rules.LoadFromXmlNode(RulesNode);
285 end;
286 RulesNode := RootNode.FindNode('LookupTables');
287 if Assigned(RulesNode) then begin
288 LookupTables.LoadFromXmlNode(RulesNode);
289 end;
290
291 TopRule := Rules.FindName(ReadString(RootNode, 'TopRule', ''));
292 WhiteSpaceRule := Rules.FindName(ReadString(RootNode, 'WhiteSpaceRule', ''));
293 end;
294 finally
295 FreeAndNil(Doc);
296 end;
297
298 // Update rule references
299 for Rule in Rules do
300 Rule.Items.UpdateRuleReference;
301end;
302
303procedure TGrammer.SaveToXmlFile(FileName: string);
304var
305 Doc: TXMLDocument;
306 RootNode: TDOMNode;
307 RulesNode: TDOMNode;
308begin
309 Self.FileName := FileName;
310 Doc := TXMLDocument.Create;
311 try
312 RootNode := Doc.CreateElement('GrammerProject');
313 Doc.AppendChild(RootNode);
314
315 RulesNode := Doc.CreateElement('Rules');
316 RootNode.AppendChild(RulesNode);
317 Rules.SaveToXmlNode(RulesNode);
318
319 RulesNode := Doc.CreateElement('LookupTables');
320 RootNode.AppendChild(RulesNode);
321 LookupTables.SaveToXmlNode(RulesNode);
322
323 if Assigned(TopRule) then
324 WriteString(RootNode, 'TopRule', TopRule.Name);
325 if Assigned(WhiteSpaceRule) then
326 WriteString(RootNode, 'WhiteSpaceRule', WhiteSpaceRule.Name);
327
328 WriteXMLFile(Doc, FileName);
329 Modified := False;
330 finally
331 FreeAndNil(Doc);
332 end;
333end;
334
335procedure TGrammer.Clear;
336begin
337 TopRule := nil;
338 Rules.Clear;
339end;
340
341constructor TGrammer.Create;
342begin
343 Rules := TRules.Create;
344 Rules.Grammer := Self;
345 LookupTables := TLookupTables.Create;
346 LookupTables.Grammer := Self;
347end;
348
349destructor TGrammer.Destroy;
350begin
351 DoDestroy;
352 FreeAndNil(LookupTables);
353 FreeAndNil(Rules);
354 inherited Destroy;
355end;
356
357procedure TGrammer.GetUsedByRule(RefRule: TRule; UsedByRules: TStrings);
358var
359 Rule: TRule;
360begin
361 UsedByRules.Clear;
362 for Rule in Rules do
363 Rule.GetUsedByRule(RefRule, UsedByRules);
364end;
365
366function TGrammer.GetString: string;
367begin
368 Result := Rules.GetString;
369end;
370
371function TGrammer.ExportAsString(Notation: TGrammerNotation): string;
372begin
373 Result := Rules.ExportAsString(Notation);
374end;
375
376procedure TGrammer.Change;
377begin
378 DoChange;
379end;
380
381{ TRuleItem }
382
383procedure TRuleItem.SaveToXmlNode(Node: TDOMNode);
384var
385 SubItemsNode: TDOMNode;
386begin
387 WriteInteger(Node, 'Type', Integer(RuleItemType));
388 WriteBoolean(Node, 'Optional', Optional);
389 WriteBoolean(Node, 'Repetitive', Repetitive);
390 WriteBoolean(Node, 'AnyExcept', AnyExcept);
391 WriteBoolean(Node, 'EscapedStrings', EscapedStrings);
392
393 case RuleItemType of
394 ritTerminal: WriteString(Node, 'Terminal', Terminal);
395 ritNonTerminal: WriteString(Node, 'NonTerminal', NonTerminal.Name);
396 ritSubItems: begin
397 SubItemsNode := Node.OwnerDocument.CreateElement('SubItems');
398 Node.AppendChild(SubItemsNode);
399 SubItems.SaveToXmlNode(SubItemsNode);
400 end;
401 ritTerminalRange: begin
402 WriteString(Node, 'TerminalFrom', TerminalFrom);
403 WriteString(Node, 'TerminalTo', TerminalTo);
404 end;
405 end;
406 WriteBoolean(Node, 'LookupTableUsed', LookupTableUsed);
407 WriteString(Node, 'LookupTable', LookupTableName);
408 WriteInteger(Node, 'LookupTableAction', Integer(LookupTableAction));
409end;
410
411function TRuleItem.GetString: string;
412begin
413 case RuleItemType of
414 ritTerminal: Result := '"' + Terminal + '"';
415 ritNonTerminal: Result := NonTerminal.Name;
416 ritSubItems: Result := '(' + SubItems.GetString + ')';
417 ritTerminalRange: Result := '(' + TerminalFrom + ' .. ' + TerminalTo + ')';
418 end;
419 if Optional then Result := '+' + Result;
420 if Repetitive then Result := '*' + Result;
421 if AnyExcept then Result := '!' + Result;
422end;
423
424function TRuleItem.ExportAsString(Notation: TGrammerNotation): string;
425begin
426 case Notation of
427 gnBnf: begin
428 case RuleItemType of
429 ritTerminal: Result := Terminal;
430 ritNonTerminal: Result := '<' + NonTerminal.Name + '>';
431 ritSubItems: begin
432 if not Optional and not Repetitive then
433 Result := '(' + SubItems.ExportAsString(Notation) + ')'
434 else Result := SubItems.ExportAsString(Notation);
435 end;
436 ritTerminalRange: Result := '(' + TerminalFrom + ' .. ' + TerminalTo + ')';
437 end;
438 if Optional and not Repetitive then Result := '[' + Result + ']';
439 if Repetitive then Result := '{' + Result + '}';
440 if AnyExcept then Result := 'other then ' + Result;
441 end;
442 gnEbnf: begin
443 case RuleItemType of
444 ritTerminal: Result := '"' + Terminal + '"';
445 ritNonTerminal: Result := NonTerminal.Name;
446 ritSubItems: begin
447 if not Optional and not Repetitive then
448 Result := '(' + SubItems.ExportAsString(Notation) + ')'
449 else Result := SubItems.ExportAsString(Notation);
450 end;
451 ritTerminalRange: Result := '(' + TerminalFrom + ' .. ' + TerminalTo + ')';
452 end;
453 if Optional and not Repetitive then Result := '[' + Result + ']';
454 if Repetitive then Result := '{' + Result + '}';
455 if AnyExcept then Result := 'other then ' + Result;
456 end;
457 end;
458end;
459
460constructor TRuleItem.Create;
461begin
462 SubItems := TRuleItems.Create;
463 SubItems.Grammer := Grammer;
464end;
465
466destructor TRuleItem.Destroy;
467begin
468 FreeAndNil(SubItems);
469 inherited Destroy;
470end;
471
472procedure TRuleItem.SetParentRule(AValue: TRule);
473begin
474 if FParentRule = AValue then Exit;
475 FParentRule := AValue;
476 SubItems.ParentRule := AValue;
477end;
478
479function TRuleItem.GetCharLength: Integer;
480begin
481 Result := 0;
482 if not Optional then
483 case RuleItemType of
484 ritTerminal: Result := Length(Terminal);
485 //ritNonTerminal: Result := NonTerminal.Items.GetCharLength;
486 ritSubItems: Result := SubItems.GetCharLength;
487 ritTerminalRange: Result := Max(Length(TerminalFrom), Length(TerminalTo))
488 end;
489end;
490
491procedure TRuleItem.SetGrammer(AValue: TGrammer);
492begin
493 if FGrammer = AValue then Exit;
494 FGrammer := AValue;
495 SubItems.Grammer := AValue;
496end;
497
498procedure TRuleItem.LoadFromXmlNode(Node: TDOMNode);
499var
500 SubItemsNode: TDOMNode;
501begin
502 RuleItemType := TRuleItemType(ReadInteger(Node, 'Type', Integer(ritTerminal)));
503 Optional := ReadBoolean(Node, 'Optional', False);
504 Repetitive := ReadBoolean(Node, 'Repetitive', False);
505 AnyExcept := ReadBoolean(Node, 'AnyExcept', False);
506 EscapedStrings := ReadBoolean(Node, 'EscapedStrings', False);
507 case RuleItemType of
508 ritTerminal: Terminal := ReadString(Node, 'Terminal', '');
509 ritNonTerminal: NonTerminalName := ReadString(Node, 'NonTerminal', '');
510 ritSubItems: begin
511 SubItemsNode := Node.FindNode('SubItems');
512 if Assigned(SubItemsNode) then SubItems.LoadFromXmlNode(SubItemsNode);
513 end;
514 ritTerminalRange: begin
515 TerminalFrom := ReadString(Node, 'TerminalFrom', '');
516 TerminalTo := ReadString(Node, 'TerminalTo', '');
517 end;
518 end;
519 LookupTableUsed := ReadBoolean(Node, 'LookupTableUsed', False);
520 LookupTableName := ReadString(Node, 'LookupTable', '');
521 LookupTableAction := TLookupTableAction(ReadInteger(Node, 'LookupTableAction', 0));
522end;
523
524{ TRuleItems }
525
526procedure TRuleItems.SaveToXmlNode(Node: TDOMNode);
527var
528 RuleItem: TRuleItem;
529 RuleItemNode: TDOMNode;
530begin
531 WriteInteger(Node, 'Type', Integer(RuleType));
532 WriteBoolean(Node, 'WithWhiteSpaces', WithWhiteSpeaces);
533
534 for RuleItem in Self do begin
535 RuleItemNode := Node.OwnerDocument.CreateElement('RuleItem');
536 RuleItem.SaveToXmlNode(RuleItemNode);
537 Node.AppendChild(RuleItemNode);
538 end;
539end;
540
541procedure TRuleItems.UpdateRuleReference;
542var
543 RuleItem: TRuleItem;
544begin
545 for RuleItem in Self do begin
546 case RuleItem.RuleItemType of
547 ritNonTerminal: RuleItem.NonTerminal := Grammer.Rules.FindName(RuleItem.NonTerminalName);
548 ritSubItems: RuleItem.SubItems.UpdateRuleReference;
549 end;
550 RuleItem.LookupTable := Grammer.LookupTables.FindName(RuleItem.LookupTableName);
551 end;
552end;
553
554function TRuleItems.GetString: string;
555var
556 Item: TRuleItem;
557begin
558 Result := '';
559 for Item in Self do begin
560 if Item <> First then begin
561 if RuleType = rtAnd then Result := Result + ' '
562 else if RuleType = rtOr then Result := Result + ' | ';
563 end;
564 Result := Result + Item.GetString;
565 end;
566end;
567
568function TRuleItems.ExportAsString(Notation: TGrammerNotation): string;
569var
570 Item: TRuleItem;
571begin
572 Result := '';
573 for Item in Self do begin
574 if Item <> First then begin
575 if RuleType = rtAnd then begin
576 case Notation of
577 gnBnf: Result := Result + ' ';
578 gnEbnf: Result := Result + ', ';
579 end;
580 end else
581 if RuleType = rtOr then begin
582 case Notation of
583 gnBnf: Result := Result + ' | ';
584 gnEbnf: Result := Result + ' | ';
585 end;
586 end;
587 end;
588 Result := Result + Item.ExportAsString(Notation);
589 end;
590end;
591
592procedure TRuleItems.SetParentRule(AValue: TRule);
593begin
594 if FParentRule = AValue then Exit;
595 FParentRule := AValue;
596end;
597
598function TRuleItems.GetCharLength: Integer;
599var
600 Item: TRuleItem;
601begin
602 Result := 0;
603 if RuleType = rtOr then begin
604 for Item in Self do
605 Result := Max(Result, Item.GetCharLength);
606 end else
607 if RuleType = rtAnd then begin
608 for Item in Self do
609 Result := Result + Item.GetCharLength;
610 end;
611end;
612
613procedure TRuleItems.LoadFromXmlNode(Node: TDOMNode);
614var
615 RuleItemNode: TDOMNode;
616 RuleItem: TRuleItem;
617begin
618 RuleType := TRuleType(ReadInteger(Node, 'Type', Integer(rtAnd)));
619 WithWhiteSpeaces := ReadBoolean(Node, 'WithWhiteSpaces', False);
620
621 RuleItemNode := Node.FirstChild;
622 while Assigned(RuleItemNode) do begin
623 if RuleItemNode.NodeName = 'RuleItem' then begin
624 RuleItem := TRuleItem.Create;
625 RuleItem.Grammer := Grammer;
626 RuleItem.ParentRule := ParentRule;
627 RuleItem.LoadFromXmlNode(RuleItemNode);
628 Add(RuleItem);
629 end;
630 RuleItemNode := RuleItemNode.NextSibling;
631 end;
632end;
633
634{ TRule }
635
636procedure TRule.SaveToXmlNode(Node: TDOMNode);
637var
638 RuleItemsNode: TDOMNode;
639begin
640 WriteString(Node, 'Name', Name);
641 WriteBoolean(Node, 'CreateSourceNode', CreateSourceNode);
642 WriteInteger(Node, 'Level', Integer(Level));
643
644 RuleItemsNode := Node.OwnerDocument.CreateElement('RuleItems');
645 Node.AppendChild(RuleItemsNode);
646 Items.SaveToXmlNode(RuleItemsNode);
647end;
648
649function TRule.GetString: string;
650begin
651 Result := Name + ' ::= ' + Items.GetString;
652end;
653
654function TRule.ExportAsString(Notation: TGrammerNotation): string;
655begin
656 case Notation of
657 gnBnf: Result := Name + ' ::= ' + Items.ExportAsString(Notation);
658 gnEbnf: Result := Name + ' = ' + Items.ExportAsString(Notation);
659 end;
660end;
661
662procedure TRule.SetGrammer(AValue: TGrammer);
663begin
664 if FGrammer = AValue then Exit;
665 FGrammer := AValue;
666 Items.Grammer := AValue;
667end;
668
669constructor TRule.Create;
670begin
671 Items := TRuleItems.Create;
672 Items.ParentRule := Self;
673 Links := TRuleLinks.Create;
674end;
675
676destructor TRule.Destroy;
677begin
678 FreeAndNil(Links);
679 FreeAndNil(Items);
680 inherited Destroy;
681end;
682
683procedure TRule.GetUsedByRule(RefRule: TRule; UsedByRules: TStrings);
684var
685 Item: TRuleItem;
686begin
687 for Item in Items do
688 if (Item.RuleItemType = ritNonTerminal) and
689 (Item.NonTerminal = RefRule) and
690 (UsedByRules.IndexOf(Item.ParentRule.Name) = -1) then
691 UsedByRules.AddObject(Item.ParentRule.Name, Item.ParentRule);
692end;
693
694procedure TRule.LoadFromXmlNode(Node: TDOMNode);
695var
696 ItemsNode: TDOMNode;
697begin
698 Name := ReadString(Node, 'Name', '');
699 CreateSourceNode := ReadBoolean(Node, 'CreateSourceNode', False);
700 Level := TRuleLevel(ReadInteger(Node, 'Level', 0));
701
702 ItemsNode := Node.FindNode('RuleItems');
703 if Assigned(ItemsNode) then begin
704 Items.LoadFromXmlNode(ItemsNode);
705 end;
706end;
707
708{ TRules }
709
710procedure TRules.SaveToXmlNode(Node: TDOMNode);
711var
712 Rule: TRule;
713 RuleNode: TDOMNode;
714begin
715 for Rule in Self do begin
716 RuleNode := Node.OwnerDocument.CreateElement('Rule');
717 Rule.SaveToXmlNode(RuleNode);
718 Node.AppendChild(RuleNode);
719 end;
720end;
721
722function TRules.FindName(Name: string): TRule;
723var
724 I: Integer;
725begin
726 I := 0;
727 while (I < Count) and (Items[I].Name <> Name) do Inc(I);
728 if I < Count then Result := Items[I]
729 else Result := nil;
730end;
731
732procedure TRules.LoadFromXmlNode(Node: TDOMNode);
733var
734 RuleNode: TDOMNode;
735 Rule: TRule;
736begin
737 RuleNode := Node.FirstChild;
738 while Assigned(RuleNode) do begin
739 if RuleNode.NodeName = 'Rule' then begin
740 Rule := TRule.Create;
741 Rule.Grammer := Grammer;
742 Rule.LoadFromXmlNode(RuleNode);
743 Add(Rule);
744 end;
745 RuleNode := RuleNode.NextSibling;
746 end;
747end;
748
749function TRules.GetString: string;
750var
751 Rule: TRule;
752begin
753 Result := '';
754 for Rule in Self do begin
755 Result := Result + Rule.GetString + LineEnding;
756 end;
757end;
758
759function TRules.ExportAsString(Notation: TGrammerNotation): string;
760var
761 Rule: TRule;
762begin
763 Result := '';
764 for Rule in Self do begin
765 Result := Result + Rule.ExportAsString(Notation) + LineEnding;
766 end;
767end;
768
769end.
770
Note: See TracBrowser for help on using the repository browser.