| 1 | unit UBuilder;
|
|---|
| 2 |
|
|---|
| 3 | {$mode delphi}
|
|---|
| 4 |
|
|---|
| 5 | interface
|
|---|
| 6 |
|
|---|
| 7 | uses
|
|---|
| 8 | Classes, SysUtils, UGrammer, StrUtils;
|
|---|
| 9 |
|
|---|
| 10 | type
|
|---|
| 11 |
|
|---|
| 12 | { TBuilder }
|
|---|
| 13 |
|
|---|
| 14 | TBuilder = class
|
|---|
| 15 | private
|
|---|
| 16 | LocalFunctions: string;
|
|---|
| 17 | LocalFunctionIndex: Integer;
|
|---|
| 18 | function Indent(Count: Integer): string;
|
|---|
| 19 | function GetItemString(Item: TRuleItem; Required: Boolean; IndentLevel: Integer): string;
|
|---|
| 20 | function StringText(const Text: string; Escaped: Boolean): string;
|
|---|
| 21 | procedure BuildMain(FileName: string);
|
|---|
| 22 | procedure BuildParser(FileName: string);
|
|---|
| 23 | function BuildParserItems(Items: TRuleItems; Required: Boolean; IndentLevel: Integer): string;
|
|---|
| 24 | procedure BuildSource(FileName: string);
|
|---|
| 25 | procedure BuildTokenizer(FileName: string);
|
|---|
| 26 | function BuildTokenizerItems(SourceFile: TStrings; Items: TRuleItems): string;
|
|---|
| 27 | public
|
|---|
| 28 | Grammer: TGrammer;
|
|---|
| 29 | procedure BuildCompiler;
|
|---|
| 30 | end;
|
|---|
| 31 |
|
|---|
| 32 |
|
|---|
| 33 | const
|
|---|
| 34 | BooleanText: array[Boolean] of string = ('False', 'True');
|
|---|
| 35 |
|
|---|
| 36 | implementation
|
|---|
| 37 |
|
|---|
| 38 | function TBuilder.Indent(Count: Integer): string;
|
|---|
| 39 | begin
|
|---|
| 40 | Result := DupeString(' ', Count);
|
|---|
| 41 | end;
|
|---|
| 42 |
|
|---|
| 43 | function TBuilder.GetItemString(Item: TRuleItem; Required: Boolean; IndentLevel: Integer): string;
|
|---|
| 44 | begin
|
|---|
| 45 | Result := '';
|
|---|
| 46 | case Item.RuleItemType of
|
|---|
| 47 | ritTerminal: Result := 'Expect(''' +
|
|---|
| 48 | StringText(Item.Terminal, Item.EscapedStrings) + ''', Required and ' + BooleanText[Required] + ')';
|
|---|
| 49 | ritNonTerminal: Result := 'Parse' + Item.NonTerminal.Name + '(Required and ' + BooleanText[Required] + ')';
|
|---|
| 50 | ritTerminalRange: Result := 'ExpectRange(''' +
|
|---|
| 51 | StringText(Item.TerminalFrom, Item.EscapedStrings) + ''', ''' +
|
|---|
| 52 | StringText(Item.TerminalTo, Item.EscapedStrings) + ''', Required and ' + BooleanText[Required] + ')';
|
|---|
| 53 | ritSubItems: begin
|
|---|
| 54 | LocalFunctions := LocalFunctions + 'function ParseSubitems' + IntToStr(LocalFunctionIndex) + '(Required: Boolean = False): Boolean;' + LineEnding;
|
|---|
| 55 | LocalFunctions := LocalFunctions + 'var' + LineEnding;
|
|---|
| 56 | LocalFunctions := LocalFunctions + ' OldPosition: TPosition;' + LineEnding;
|
|---|
| 57 | LocalFunctions := LocalFunctions + 'begin' + LineEnding;
|
|---|
| 58 | LocalFunctions := LocalFunctions + ' Result := True;' + LineEnding;
|
|---|
| 59 | LocalFunctions := LocalFunctions + BuildParserItems(Item.SubItems, Required, 1);
|
|---|
| 60 | LocalFunctions := LocalFunctions + 'end;' + LineEnding + LineEnding;
|
|---|
| 61 |
|
|---|
| 62 | Result := Result + 'ParseSubitems' + IntToStr(LocalFunctionIndex) + '(Required and ' + BooleanText[Required] + ')';
|
|---|
| 63 | Inc(LocalFunctionIndex);
|
|---|
| 64 | end;
|
|---|
| 65 | end;
|
|---|
| 66 | end;
|
|---|
| 67 |
|
|---|
| 68 | function TBuilder.StringText(const Text: string; Escaped: Boolean): string;
|
|---|
| 69 | begin
|
|---|
| 70 | Result := Text;
|
|---|
| 71 | Result := StringReplace(Result, '''', '''''', [rfReplaceAll]);
|
|---|
| 72 | if Escaped then begin
|
|---|
| 73 | Result := StringReplace(Result, '\n', '''#10''', [rfReplaceAll]);
|
|---|
| 74 | Result := StringReplace(Result, '\r', '''#13''', [rfReplaceAll]);
|
|---|
| 75 | Result := StringReplace(Result, '\t', '''#9''', [rfReplaceAll]);
|
|---|
| 76 | Result := StringReplace(Result, '\\', '\', [rfReplaceAll]);
|
|---|
| 77 | end;
|
|---|
| 78 | end;
|
|---|
| 79 |
|
|---|
| 80 | procedure TBuilder.BuildParser(FileName: string);
|
|---|
| 81 | var
|
|---|
| 82 | ParserFile: TStringList;
|
|---|
| 83 | Rule: TRule;
|
|---|
| 84 | FunctionBody: string;
|
|---|
| 85 | begin
|
|---|
| 86 | ParserFile := TStringList.Create;
|
|---|
| 87 | with ParserFile do begin
|
|---|
| 88 | Add('unit Parser;');
|
|---|
| 89 | Add('');
|
|---|
| 90 | Add('{$MODE Delphi}');
|
|---|
| 91 | Add('');
|
|---|
| 92 | Add('interface');
|
|---|
| 93 | Add('');
|
|---|
| 94 | Add('uses');
|
|---|
| 95 | Add(' SysUtils, Tokenizer, Types;');
|
|---|
| 96 | Add('');
|
|---|
| 97 | Add('type');
|
|---|
| 98 | Add(' TPosition = record');
|
|---|
| 99 | Add(' Index: Integer;');
|
|---|
| 100 | Add(' Pos: TPoint;');
|
|---|
| 101 | Add(' procedure Calc(Text: string);');
|
|---|
| 102 | Add(' end;');
|
|---|
| 103 | Add('');
|
|---|
| 104 | Add(' TParser = class');
|
|---|
| 105 | Add(' Tokenizer: TTokenizer;');
|
|---|
| 106 | Add(' Content: string;');
|
|---|
| 107 | Add(' FileName: string;');
|
|---|
| 108 | Add(' Position: TPosition;');
|
|---|
| 109 | Add(' procedure Error(Text: string);');
|
|---|
| 110 | Add(' function Expect(Text: string; Required: Boolean = False): Boolean;');
|
|---|
| 111 | Add(' function ExpectRange(CharFrom, CharTo: Char; Required: Boolean = False): Boolean;');
|
|---|
| 112 | for Rule in Grammer.Rules do
|
|---|
| 113 | //if Rule.Level = rlParser then
|
|---|
| 114 | Add(' function Parse' + Rule.Name + '(Required: Boolean = False): Boolean;');
|
|---|
| 115 | Add(' constructor Create;');
|
|---|
| 116 | Add(' destructor Destroy; override;');
|
|---|
| 117 | Add(' end;');
|
|---|
| 118 | Add('');
|
|---|
| 119 | Add('');
|
|---|
| 120 | Add('implementation');
|
|---|
| 121 | Add('');
|
|---|
| 122 | Add('procedure TPosition.Calc(Text: string);');
|
|---|
| 123 | Add('var');
|
|---|
| 124 | Add(' I: Integer;');
|
|---|
| 125 | Add('begin');
|
|---|
| 126 | Add(' for I := 1 to Length(Text) do begin');
|
|---|
| 127 | Add(' Inc(Pos.X);');
|
|---|
| 128 | Add(' Inc(Index);');
|
|---|
| 129 | Add(' if Text[I] = LineEnding then begin');
|
|---|
| 130 | Add(' Pos.X := 1;');
|
|---|
| 131 | Add(' Inc(Pos.Y);');
|
|---|
| 132 | Add(' end;');
|
|---|
| 133 | Add(' end;');
|
|---|
| 134 | Add('end;');
|
|---|
| 135 | Add('');
|
|---|
| 136 | Add('constructor TParser.Create;');
|
|---|
| 137 | Add('begin');
|
|---|
| 138 | Add(' Position.Index := 1;');
|
|---|
| 139 | Add(' Position.Pos := Point(1, 1);');
|
|---|
| 140 | Add(' Tokenizer := TTokenizer.Create;');
|
|---|
| 141 | Add('end;');
|
|---|
| 142 | Add('');
|
|---|
| 143 | Add('destructor TParser.Destroy;');
|
|---|
| 144 | Add('begin');
|
|---|
| 145 | Add(' FreeAndNil(Tokenizer);');
|
|---|
| 146 | Add('end;');
|
|---|
| 147 | Add('');
|
|---|
| 148 | Add('procedure TParser.Error(Text: string);');
|
|---|
| 149 | Add('begin');
|
|---|
| 150 | Add(' WriteLn(FileName + ''('' + IntToStr(Position.Pos.X) + '','' + IntToStr(Position.Pos.Y) + '') Error: '' + Text);');
|
|---|
| 151 | Add('end;');
|
|---|
| 152 | Add('');
|
|---|
| 153 | Add('function TParser.Expect(Text: string; Required: Boolean = False): Boolean;');
|
|---|
| 154 | Add('var');
|
|---|
| 155 | Add(' ReadText: string;');
|
|---|
| 156 | Add(' StartPos: TPosition;');
|
|---|
| 157 | Add('begin');
|
|---|
| 158 | Add(' StartPos := Position;');
|
|---|
| 159 | Add(' ReadText := Copy(Content, Position.Index, Length(Text));');
|
|---|
| 160 | Add(' Position.Calc(Text);');
|
|---|
| 161 | Add(' Result := Text = ReadText;');
|
|---|
| 162 | Add(' if not Result then begin');
|
|---|
| 163 | Add(' Position := StartPos;');
|
|---|
| 164 | Add(' if Required then Error(''Expected "'' + Text + ''" but found "'' + ReadText + ''".'');');
|
|---|
| 165 | Add(' end else WriteLn(''Expect: '' + Text);');
|
|---|
| 166 | Add('end;');
|
|---|
| 167 | Add('');
|
|---|
| 168 | Add('function TParser.ExpectRange(CharFrom, CharTo: char; Required: Boolean = False): Boolean;');
|
|---|
| 169 | Add('var');
|
|---|
| 170 | Add(' ReadChar: Char;');
|
|---|
| 171 | Add(' StartPos: TPosition;');
|
|---|
| 172 | Add('begin');
|
|---|
| 173 | Add(' StartPos := Position;');
|
|---|
| 174 | Add(' ReadChar := Content[Position.Index];');
|
|---|
| 175 | Add(' Position.Calc(Content[Position.Index]);');
|
|---|
| 176 | Add(' Result := (ReadChar >= CharFrom) and (ReadChar <= CharTo);');
|
|---|
| 177 | Add(' if not Result then begin');
|
|---|
| 178 | Add(' Position := StartPos;');
|
|---|
| 179 | Add(' if Required then Error(''Expected "'' + CharFrom + ''" to "'' + CharTo + ''" but found "'' + ReadChar + ''".'');');
|
|---|
| 180 | Add(' end else WriteLn(''ExpectRange: '' + CharFrom + ''..'' + CharTo + '': '' + ReadChar);');
|
|---|
| 181 | Add('end;');
|
|---|
| 182 | Add('');
|
|---|
| 183 | for Rule in Grammer.Rules do
|
|---|
| 184 | //if Rule.Level = rlParser then
|
|---|
| 185 | begin
|
|---|
| 186 | LocalFunctionIndex := 1;
|
|---|
| 187 | LocalFunctions := '';
|
|---|
| 188 | FunctionBody := BuildParserItems(Rule.Items, True, 1);
|
|---|
| 189 | Text := Text + 'function TParser.Parse' + Rule.Name + '(Required: Boolean = False): Boolean;' + LineEnding;
|
|---|
| 190 | Text := Text + LocalFunctions;
|
|---|
| 191 | Text := Text + 'var' + LineBreak;
|
|---|
| 192 | Text := Text + ' OldPosition: TPosition;' + LineEnding;
|
|---|
| 193 | Text := Text + 'begin' + LineEnding;
|
|---|
| 194 | //Text := Text + ' WriteLn(''Rule check: ' + Rule.Name + ''');';
|
|---|
| 195 | Text := Text + ' Result := True;' + LineEnding;
|
|---|
| 196 | Text := Text + FunctionBody;
|
|---|
| 197 | Text := Text + ' if Result then WriteLn(''Rule: ' + Rule.Name + ''');';
|
|---|
| 198 | Text := Text + 'end;' + LineEnding + LineEnding;
|
|---|
| 199 | end;
|
|---|
| 200 | Add('');
|
|---|
| 201 | Add('end.');
|
|---|
| 202 | SaveToFile(FileName);
|
|---|
| 203 | end;
|
|---|
| 204 | FreeAndNil(ParserFile);
|
|---|
| 205 | end;
|
|---|
| 206 |
|
|---|
| 207 | function TBuilder.BuildParserItems(Items: TRuleItems; Required: Boolean; IndentLevel: Integer): string;
|
|---|
| 208 | var
|
|---|
| 209 | I: Integer;
|
|---|
| 210 | Item: TRuleItem;
|
|---|
| 211 | ItemRequired: Boolean;
|
|---|
| 212 | Line: string;
|
|---|
| 213 | begin
|
|---|
| 214 | Result := Indent(IndentLevel) + 'OldPosition := Position;' + LineEnding;
|
|---|
| 215 | I := 0;
|
|---|
| 216 | for Item in Items do begin
|
|---|
| 217 | ItemRequired := not Item.Optional and Required;
|
|---|
| 218 | Line := '';
|
|---|
| 219 | case Items.RuleType of
|
|---|
| 220 | rtOr: begin
|
|---|
| 221 | Line := Line + Indent(IndentLevel);
|
|---|
| 222 | if I > 0 then Line := Line + 'else ';
|
|---|
| 223 | Line := Line + 'if ' + GetItemString(Item, False, IndentLevel) +
|
|---|
| 224 | ' then Exit';
|
|---|
| 225 | end;
|
|---|
| 226 | rtAnd: begin
|
|---|
| 227 | if not Item.Optional then
|
|---|
| 228 | Line := Line + Indent(IndentLevel) + 'Result := Result and ';
|
|---|
| 229 | if Item.Repetitive then begin
|
|---|
| 230 | if not Item.Optional then
|
|---|
| 231 | Line := Line + Indent(IndentLevel) + GetItemString(Item, ItemRequired, IndentLevel) + ';' + LineEnding;
|
|---|
| 232 | Line := Line + Indent(IndentLevel) + 'repeat' + LineEnding;
|
|---|
| 233 | Inc(IndentLevel);
|
|---|
| 234 | Line := Line + Indent(IndentLevel) + 'if not ';
|
|---|
| 235 | ItemRequired := False;
|
|---|
| 236 | end else
|
|---|
| 237 | if Item.Optional then Line := Line + Indent(IndentLevel);
|
|---|
| 238 | Line := Line + GetItemString(Item, ItemRequired, IndentLevel);
|
|---|
| 239 | if Item.Repetitive then begin
|
|---|
| 240 | Dec(IndentLevel);
|
|---|
| 241 | Line := Line + ' then Break;' + LineEnding +
|
|---|
| 242 | Indent(IndentLevel) + 'until False';
|
|---|
| 243 | end;
|
|---|
| 244 | Line := Line + ';' + LineEnding +
|
|---|
| 245 | Indent(IndentLevel) + 'if not Result then begin' + LineEnding +
|
|---|
| 246 | Indent(IndentLevel + 1) + 'Position := OldPosition;' + LineEnding +
|
|---|
| 247 | Indent(IndentLevel + 1) + 'Exit;' + LineEnding +
|
|---|
| 248 | Indent(IndentLevel) + 'end;';
|
|---|
| 249 |
|
|---|
| 250 | // Check white spaces
|
|---|
| 251 | if Assigned(Items.Grammer.WhiteSpaceRule) and Items.WithWhiteSpeaces
|
|---|
| 252 | then begin
|
|---|
| 253 | Line := Line + Indent(IndentLevel) + 'repeat' + LineEnding;
|
|---|
| 254 | Inc(IndentLevel);
|
|---|
| 255 | Line := Line + Indent(IndentLevel) + 'if not Parse' +
|
|---|
| 256 | Items.Grammer.WhiteSpaceRule.Name + '(False)' +
|
|---|
| 257 | ' then Break;' + LineEnding;
|
|---|
| 258 | Dec(IndentLevel);
|
|---|
| 259 | Line := Line + Indent(IndentLevel) + 'until False;' + LineEnding;
|
|---|
| 260 | end;
|
|---|
| 261 | end;
|
|---|
| 262 | end;
|
|---|
| 263 | Result := Result + Line + LineEnding;
|
|---|
| 264 | Inc(I);
|
|---|
| 265 | end;
|
|---|
| 266 | case Items.RuleType of
|
|---|
| 267 | rtOr: begin
|
|---|
| 268 | Result := Result + Indent(IndentLevel) + 'else begin' + LineEnding;
|
|---|
| 269 | Result := Result + Indent(IndentLevel) + ' if Required then Error(''Unexpected token'');' + LineEnding;
|
|---|
| 270 | Result := Result + Indent(IndentLevel) + ' Result := False;' + LineEnding;
|
|---|
| 271 | Result := Result + Indent(IndentLevel) + 'end;' + LineEnding;
|
|---|
| 272 | end;
|
|---|
| 273 | end;
|
|---|
| 274 | end;
|
|---|
| 275 |
|
|---|
| 276 | procedure TBuilder.BuildMain(FileName: string);
|
|---|
| 277 | var
|
|---|
| 278 | ParserFile: TStringList;
|
|---|
| 279 | begin
|
|---|
| 280 | ParserFile := TStringList.Create;
|
|---|
| 281 | with ParserFile do begin
|
|---|
| 282 | Add('program Compiler;');
|
|---|
| 283 | Add('');
|
|---|
| 284 | Add('{$MODE Delphi}');
|
|---|
| 285 | Add('');
|
|---|
| 286 | Add('uses');
|
|---|
| 287 | Add(' Source, Parser, Tokenizer, SysUtils;');
|
|---|
| 288 | Add('');
|
|---|
| 289 | Add('procedure Compile(FileName: string);');
|
|---|
| 290 | Add('var');
|
|---|
| 291 | Add(' SourceFile: file of Char;');
|
|---|
| 292 | Add(' Parser: TParser;');
|
|---|
| 293 | Add(' I: Integer;');
|
|---|
| 294 | Add('begin');
|
|---|
| 295 | Add(' AssignFile(SourceFile, FileName);');
|
|---|
| 296 | Add(' Reset(SourceFile);');
|
|---|
| 297 | Add(' Parser := TParser.Create;');
|
|---|
| 298 | Add(' Parser.FileName := ExtractFileName(FileName);');
|
|---|
| 299 | Add(' SetLength(Parser.Content, FileSize(SourceFile));');
|
|---|
| 300 | Add(' I := 1;');
|
|---|
| 301 | Add(' while not Eof(SourceFile) do begin');
|
|---|
| 302 | Add(' Read(SourceFile, Parser.Content[I]);');
|
|---|
| 303 | Add(' Inc(I);');
|
|---|
| 304 | Add(' end;');
|
|---|
| 305 | Add(' CloseFile(SourceFile);');
|
|---|
| 306 | if Assigned(Grammer.TopRule) then
|
|---|
| 307 | Add(' Parser.Parse' + Grammer.TopRule.Name + '(True);');
|
|---|
| 308 | Add(' FreeAndNil(Parser);');
|
|---|
| 309 | Add('end;');
|
|---|
| 310 | Add('');
|
|---|
| 311 | Add('begin');
|
|---|
| 312 | Add(' if ParamCount > 0 then');
|
|---|
| 313 | Add(' Compile(ParamStr(1))');
|
|---|
| 314 | Add(' else WriteLn(''File name not specified as parameter.'');');
|
|---|
| 315 | Add('end.');
|
|---|
| 316 | SaveToFile(FileName);
|
|---|
| 317 | end;
|
|---|
| 318 | FreeAndNil(ParserFile);
|
|---|
| 319 | end;
|
|---|
| 320 |
|
|---|
| 321 | procedure TBuilder.BuildSource(FileName: string);
|
|---|
| 322 | var
|
|---|
| 323 | Rule: TRule;
|
|---|
| 324 | Item: TRuleItem;
|
|---|
| 325 | SourceFile: TStringList;
|
|---|
| 326 | TypeSectionStarted: Boolean;
|
|---|
| 327 | I: Integer;
|
|---|
| 328 | begin
|
|---|
| 329 | SourceFile := TStringList.Create;
|
|---|
| 330 | with SourceFile do begin
|
|---|
| 331 | Add('unit Source;');
|
|---|
| 332 | Add('');
|
|---|
| 333 | Add('{$MODE Delphi}');
|
|---|
| 334 | Add('');
|
|---|
| 335 | Add('interface');
|
|---|
| 336 | Add('');
|
|---|
| 337 | Add('uses');
|
|---|
| 338 | Add(' fgl;');
|
|---|
| 339 | Add('');
|
|---|
| 340 | TypeSectionStarted := False;
|
|---|
| 341 | for Rule in Grammer.Rules do
|
|---|
| 342 | //if Rule.CreateSourceNode then
|
|---|
| 343 | begin
|
|---|
| 344 | if not TypeSectionStarted then begin
|
|---|
| 345 | Add('type');
|
|---|
| 346 | TypeSectionStarted := True;
|
|---|
| 347 | end;
|
|---|
| 348 | Add(' T' + Rule.Name + ' = class;');
|
|---|
| 349 | end;
|
|---|
| 350 | Add('');
|
|---|
| 351 | for Rule in Grammer.Rules do
|
|---|
| 352 | //if Rule.CreateSourceNode then
|
|---|
| 353 | begin
|
|---|
| 354 | Add(' T' + Rule.Name + ' = class');
|
|---|
| 355 | I := 1;
|
|---|
| 356 | for Item in Rule.Items do begin
|
|---|
| 357 | if Item.RuleItemType = ritNonTerminal then
|
|---|
| 358 | if Item.Repetitive then
|
|---|
| 359 | Add(' ' + Item.NonTerminal.Name + IntToStr(I) + ': TFPGObjectList<T' + Item.NonTerminal.Name + '>;')
|
|---|
| 360 | else Add(' ' + Item.NonTerminal.Name + IntToStr(I) + ': T' + Item.NonTerminal.Name + ';');
|
|---|
| 361 | Inc(I);
|
|---|
| 362 | end;
|
|---|
| 363 | Add(' end;' + LineEnding);
|
|---|
| 364 | end;
|
|---|
| 365 | Add('');
|
|---|
| 366 | Add('implementation');
|
|---|
| 367 | Add('');
|
|---|
| 368 |
|
|---|
| 369 | Add('end.');
|
|---|
| 370 |
|
|---|
| 371 | SaveToFile(FileName);
|
|---|
| 372 | end;
|
|---|
| 373 | FreeAndNil(SourceFile);
|
|---|
| 374 | end;
|
|---|
| 375 |
|
|---|
| 376 | function TBuilder.BuildTokenizerItems(SourceFile: TStrings; Items: TRuleItems): string;
|
|---|
| 377 | var
|
|---|
| 378 | Item: TRuleItem;
|
|---|
| 379 | Line: string;
|
|---|
| 380 | begin
|
|---|
| 381 | Result := '';
|
|---|
| 382 | Line := '';
|
|---|
| 383 | with SourceFile do begin
|
|---|
| 384 | for Item in Items do begin
|
|---|
| 385 | case Item.RuleItemType of
|
|---|
| 386 | ritTerminal: Line := Line + '(Value = ''' + StringText(Item.Terminal, Item.EscapedStrings) + ''')';
|
|---|
| 387 | ritNonTerminal: Line := Line + 'Is' + Item.NonTerminalName + '(Value)';
|
|---|
| 388 | ritTerminalRange: Line := Line + '((Value > ''' + StringText(Item.TerminalFrom, Item.EscapedStrings) + ''') and (Value < ''' + StringText(Item.TerminalTo, Item.EscapedStrings) + '''))';
|
|---|
| 389 | ritSubItems: Line := Line + '(' + BuildTokenizerItems(SourceFile, Item.SubItems) + ')';
|
|---|
| 390 | end;
|
|---|
| 391 | if Item <> Items[Items.Count - 1] then
|
|---|
| 392 | Line := Line + ' ' + RuleTypeText[Items.RuleType] + ' ';
|
|---|
| 393 | if Length(Line) > 80 then begin
|
|---|
| 394 | Result := Result + Line + LineEnding;
|
|---|
| 395 | Line := '';
|
|---|
| 396 | end;
|
|---|
| 397 | end;
|
|---|
| 398 | Result := Result + Line;
|
|---|
| 399 | end;
|
|---|
| 400 | end;
|
|---|
| 401 |
|
|---|
| 402 | procedure TBuilder.BuildTokenizer(FileName: string);
|
|---|
| 403 | var
|
|---|
| 404 | Rule: TRule;
|
|---|
| 405 | SourceFile: TStringList;
|
|---|
| 406 | begin
|
|---|
| 407 | SourceFile := TStringList.Create;
|
|---|
| 408 | with SourceFile do begin
|
|---|
| 409 | Add('unit Tokenizer;');
|
|---|
| 410 | Add('');
|
|---|
| 411 | Add('{$MODE Delphi}');
|
|---|
| 412 | Add('');
|
|---|
| 413 | Add('interface');
|
|---|
| 414 | Add('');
|
|---|
| 415 | Add('uses');
|
|---|
| 416 | Add(' fgl;');
|
|---|
| 417 | Add('');
|
|---|
| 418 | Add('type');
|
|---|
| 419 | Add(' TTokenizer = class');
|
|---|
| 420 | Add(' function ReadNext: string;');
|
|---|
| 421 | Add(' function Expect(Text: string): Boolean;');
|
|---|
| 422 | for Rule in Grammer.Rules do
|
|---|
| 423 | if (Rule.Level = rlTokenizer) then begin
|
|---|
| 424 | Add(' function Is' + Rule.Name + '(Value: Char): Boolean;');
|
|---|
| 425 | end;
|
|---|
| 426 | Add(' end;');
|
|---|
| 427 | Add('');
|
|---|
| 428 | Add('implementation');
|
|---|
| 429 | Add('');
|
|---|
| 430 | Add('function TTokenizer.ReadNext: string;');
|
|---|
| 431 | Add('begin');
|
|---|
| 432 | Add('end;');
|
|---|
| 433 | Add('');
|
|---|
| 434 | Add('function TTokenizer.Expect(Text: string): Boolean;');
|
|---|
| 435 | Add('begin');
|
|---|
| 436 | Add('end;');
|
|---|
| 437 |
|
|---|
| 438 |
|
|---|
| 439 | for Rule in Grammer.Rules do
|
|---|
| 440 | if Rule.Level = rlTokenizer then begin
|
|---|
| 441 | Add('function TTokenizer.Is' + Rule.Name + '(Value: Char): Boolean;');
|
|---|
| 442 | Add('begin');
|
|---|
| 443 | Add(' Result := ' + BuildTokenizerItems(SourceFile, Rule.Items) + ';');
|
|---|
| 444 | Add('end;' + LineEnding);
|
|---|
| 445 | end;
|
|---|
| 446 | Add('end.');
|
|---|
| 447 |
|
|---|
| 448 | SaveToFile(FileName);
|
|---|
| 449 | end;
|
|---|
| 450 | FreeAndNil(SourceFile);
|
|---|
| 451 | end;
|
|---|
| 452 |
|
|---|
| 453 | procedure TBuilder.BuildCompiler;
|
|---|
| 454 | var
|
|---|
| 455 | OutputDir: string;
|
|---|
| 456 | begin
|
|---|
| 457 | OutputDir := 'Generated';
|
|---|
| 458 | ForceDirectories(OutputDir);
|
|---|
| 459 |
|
|---|
| 460 | BuildMain(OutputDir + DirectorySeparator + 'Compiler.pas');
|
|---|
| 461 | BuildSource(OutputDir + DirectorySeparator + 'Source.pas');
|
|---|
| 462 | BuildParser(OutputDir + DirectorySeparator + 'Parser.pas');
|
|---|
| 463 | BuildTokenizer(OutputDir + DirectorySeparator + 'Tokenizer.pas');
|
|---|
| 464 | end;
|
|---|
| 465 |
|
|---|
| 466 |
|
|---|
| 467 | end.
|
|---|
| 468 |
|
|---|