Ignore:
Timestamp:
Oct 20, 2010, 11:02:10 AM (14 years ago)
Author:
george
Message:
  • Fixed: Better error message cursor position focusing.
  • Modified: All source code is tokenized to token list at once.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/Transpascal/Compiler/Analyze/UParser.pas

    r71 r72  
    66
    77uses
    8   SysUtils, Variants, Classes,
     8  SysUtils, Variants, Classes, Contnrs,
    99  Dialogs, USourceCode, FileUtil;
    1010
     
    1919    ttOperator, ttEndOfFile, ttLineComment, ttBlockComment1, ttBlockComment2,
    2020    ttUnknown, ttWhiteSpace);
     21
     22  TToken = class
     23    Token: string;
     24    CodePosition: TPoint;
     25    TokenType: TTokenType;
     26  end;
    2127
    2228  { TBaseParser }
     
    2935    FNextTokenType: TTokenType;
    3036    FParserState: TParserState;
    31     PreviousChar: char;
    32     CurrentChar: char;
     37    PreviousChar: Char;
     38    CurrentChar: Char;
     39    TokenCodePosition: TPoint;
     40    procedure GetNextToken;
    3341  public
    3442    ProgramCode: TProgram;
    35     CodeStreamPosition: integer;
     43    CodeStreamPosition: Integer;
    3644    CodePosition: TPoint;
    37     LastTokenEnd: TPoint;
    38     LastTokenStart: TPoint;
    3945    SourceCodeText: TStringList;
     46    Tokens: TObjectList; // TObjectList<TToken>
     47    TokenIndex: Integer;
     48    constructor Create;
     49    destructor Destroy; override;
    4050    function IsAlphanumeric(Character: char): boolean;
    41     procedure GetNextToken;
    42     function ReadCode: string;
    43     function NextToken: string;
    44     function NextTokenType: TTokenType;
    45     procedure Expect(Code: string);
    4651    function IsWhiteSpace(Character: char): boolean;
    4752    function IsAlphabetic(Character: char): boolean;
     
    4954    function IsKeyword(Text: string): boolean;
    5055    function IsOperator(Text: string): boolean;
    51     procedure Log(Text: string);
    52     procedure ErrorMessage(const Text: string; const Arguments: array of const);
     56    function ReadCode: string;
     57    function NextToken: string;
     58    function NextTokenType: TTokenType;
     59    procedure Expect(Code: string);
     60    procedure ErrorMessage(const Text: string; const Arguments: array of const;
     61      TokenOffset: Integer);
    5362    property OnErrorMessage: TOnErrorMessage read FOnErrorMessage write FOnErrorMessage;
    54     procedure Init;
     63    procedure Process;
    5564    property FileName: string read FFileName write FFileName;
    5665  end;
    5766
    5867resourcestring
    59   SUnknownIdentifier = 'Unknown identificator "%s".';
    60   SIllegalExpression = 'Illegal expression "%s".';
    6168  SExpectedButFound = 'Expected "%s" but "%s" found.';
    62   SRedefineIdentifier = 'Identificator "%s" redefinition.';
    63   STypeNotDefined = 'Type "%s" not defined.';
    64   SEndOfDataReached = 'Parser reached to end of input data.';
    65   SUndefinedVariable = 'Undefined variable "%s".';
    66   SUndefinedType = 'Undefined type "%s".';
    67   SUndefinedConstant = 'Undefined constant "%s".';
    68   SUnitNotFound = 'Unit "%s" not found.';
    6969
    7070implementation
     
    7272{ TBaseParser }
    7373
    74 procedure TBaseParser.ErrorMessage(const Text: string; const Arguments: array of const);
     74procedure TBaseParser.ErrorMessage(const Text: string; const Arguments: array of const;
     75  TokenOffset: Integer);
    7576begin
    7677  if Assigned(FOnErrorMessage) then
    77     FOnErrorMessage(Format(Text, Arguments), LastTokenStart, FileName);
     78  if (TokenIndex + TokenOffset) < Tokens.Count then begin
     79    FOnErrorMessage(Format(Text, Arguments),
     80      TToken(Tokens[TokenIndex + TokenOffset]).CodePosition, FileName);
     81  end;
    7882end;
    7983
    8084procedure TBaseParser.Expect(Code: string);
    8185begin
    82   Log('Expected: ' + Code + '  Readed: ' + FNextToken);
    83   if FNextToken <> Code then begin
    84     //ReadCode;
    85     ErrorMessage(SExpectedButFound, [Code, FNextToken]);
     86  if NextToken <> Code then begin
     87    ErrorMessage(SExpectedButFound, [Code, FNextToken], -2);
    8688
    8789    // Recovery: try to find nearest same code
    88     while (FNextToken <> Code) and (FNextTokenType <> ttEndOfFile) do
    89       GetNextToken;
    90   end;
    91   GetNextToken;
     90    while (NextToken <> Code) and (NextTokenType <> ttEndOfFile) do
     91      ReadCode;
     92  end;
     93  ReadCode;
    9294end;
    9395
     
    9597begin
    9698  Result := (Character in ['a'..'z']) or (Character in ['A'..'Z']);
     99end;
     100
     101constructor TBaseParser.Create;
     102begin
     103  Tokens := TObjectList.Create;
     104end;
     105
     106destructor TBaseParser.Destroy;
     107begin
     108  Tokens.Free;
     109  inherited Destroy;
    97110end;
    98111
     
    144157end;
    145158
    146 procedure TBaseParser.Log(Text: string);
    147 const
    148   LogFileName = 'ParseLog.txt';
    149 var
    150   LogFile: TFileStream;
    151 begin
    152   try
    153     if FileExistsUTF8(LogFileName) { *Converted from FileExists*  } then
    154       LogFile := TFileStream.Create(LogFileName, fmOpenWrite)
    155     else
    156       LogFile := TFileStream.Create(LogFileName, fmCreate);
    157     if Length(Text) > 0 then
    158     begin
    159       LogFile.Write(Text[1], Length(Text));
    160       LogFile.Write(#13#10, 2);
    161     end;
    162   finally
    163     LogFile.Free;
    164   end;
    165 end;
    166 
    167 procedure TBaseParser.Init;
    168 begin
    169   CodePosition := Point(1, 1);
     159procedure TBaseParser.Process;
     160var
     161  NewToken: TToken;
     162begin
     163  CodePosition := Point(0, 1);
    170164  CurrentChar := #0;
    171165  PreviousChar := #0;
     
    173167  FNextTokenType := ttNone;
    174168  CodeStreamPosition := 1;
    175   GetNextToken;
     169  Tokens.Clear;
     170  TokenIndex := 0;
     171  while CodeStreamPosition < Length(SourceCodeText.Text) do begin
     172    NewToken := TToken.Create;
     173    GetNextToken;
     174    NewToken.CodePosition := TokenCodePosition;
     175    NewToken.TokenType := FNextTokenType;
     176    NewToken.Token := FNextToken;
     177    Tokens.Add(NewToken);
     178  end;
    176179end;
    177180
     
    184187  SpecChar: set of char = [';', '.', ',', ':', '(', ')', '[', ']',
    185188    '+', '-', '/', '*', '^', '=', '<', '>', '@'];
    186   DoubleSpecChar: array[0..6] of string = (':=', '..', '<=', '>=', '<>', '+=', '-=');
    187 begin
    188   LastTokenStart := LastTokenEnd;
    189   LastTokenEnd := CodePosition;
     189  DoubleSpecChar: array[0..6] of string = (':=', '..', '<=', '>=', '<>',
     190    '+=', '-=');
     191begin
    190192  FNextToken := '';
    191193  FNextTokenType := ttNone;
    192194  FParserState := psNone;
    193195  with SourceCodeText do
    194     while True do
    195     begin
     196    while True do begin
    196197      if CodeStreamPosition < Length(Text) then begin
    197198        CurrentChar := Text[CodeStreamPosition];
     
    204205
    205206      if FParserState = psNone then begin
     207        TokenCodePosition := CodePosition;
    206208        if IsWhiteSpace(CurrentChar) then
    207209          FParserState := psWhiteSpace
     
    293295        Inc(CodePosition.X);
    294296        if (CurrentChar = #13) then begin
    295           CodePosition.X := 1;
     297          CodePosition.X := 0;
    296298          Inc(CodePosition.Y);
    297299        end;
     
    305307function TBaseParser.ReadCode: string;
    306308begin
    307   Result := FNextToken;
    308   GetNextToken;
    309   Log('Read: ' + Result);
     309  if TokenIndex < Tokens.Count then begin
     310    Result := TToken(Tokens[TokenIndex]).Token;
     311    Inc(TokenIndex);
     312  end else Result := '';
    310313end;
    311314
    312315function TBaseParser.NextToken: string;
    313316begin
    314   Result := FNextToken;
     317  if TokenIndex < Tokens.Count then begin
     318    Result := TToken(Tokens[TokenIndex]).Token;
     319  end else Result := '';
    315320end;
    316321
    317322function TBaseParser.NextTokenType: TTokenType;
    318323begin
    319   Result := FNextTokenType;
     324  if TokenIndex < Tokens.Count then begin
     325    Result := TToken(Tokens[TokenIndex]).TokenType;
     326  end else Result := ttEndOfFile;
    320327end;
    321328
Note: See TracChangeset for help on using the changeset viewer.