PL/0语言编译程序整理实现:(3)、词法分析

来源:互联网 发布:到处微博转发点赞数据 编辑:程序博客网 时间:2024/05/22 13:45

unit uSymbol;

interface

uses
    SysUtils,uSymbolType,uError;

type
    TSymbolAnalyzer = class
    private
        FScript: string;
        FChar: char;
        FCharPos: integer;
        FSymbol: TSymbol;
        FError: TError;
    public
        constructor Create(const AScript: string; const AError: TError = nil);
        //---
        procedure GetSymbol;
        //---
        property Symbol: TSymbol read FSymbol;
    end;

implementation

uses uErrorInfo;

constructor TSymbolAnalyzer.Create(const AScript: string; const AError: TError
    = nil);
begin
    FScript := LowerCase(AScript);
    FChar := ' ';
    FCharPos := 0;
    //---
    FError := AError;
end;

procedure TSymbolAnalyzer.GetSymbol;
    //---
    procedure _ReportError(const AMsg: string);
    begin
        if Assigned(FError) then
            FError.ReportError(AMsg);
    end;
    //---获取字符
    procedure _GetChar;
    begin
        if FCharPos > length(FScript) then
            _ReportError(CNT_Error1)
        else
        begin
            inc(FCharPos);
            FChar := FScript[FCharPos];
        end;
    end;
    //---去掉空白字符
    procedure _SkipBlanks;
    begin
        while FChar in [' ',#9,#10,#13] do
            _GetChar;
    end;
    //---是否是关键字(二分法查找)
    function _IsKeyword: TSymbolType;
    var
        AMin,AMax,AMid: integer;
    begin
        AMin := Low(CNT_KeywordMap);
        AMax := high(CNT_KeywordMap);
        repeat
            AMid := (AMin + AMax) div 2;
            //---
            if FSymbol.Ident <= CNT_KeywordMap[AMid].Name then
                AMax := AMid - 1;
            if FSymbol.Ident >= CNT_KeywordMap[AMid].Name then
                AMin := AMid + 1;
        until AMin > AMax;
        //---
        if AMin - 1 > AMax then
            Result := TSymbolType(CNT_KeywordMap[AMid].Value)
        else
            Result := symIdent;
    end;
    //---
    procedure _GetIdent;
    var
        k: integer;
    begin
        with FSymbol do
        begin
            FillChar(Ident[1],Length(Ident), ' ');
            //---
            k := 0;
            repeat
                if k < CNT_Ident_MaxLen then
                begin
                    k := k + 1;
                    Ident[k] := FChar;
                end;
                //---
                _GetChar;
            until not (FChar in ['a'..'z', '0'..'9']);
        end;
        //---
        FSymbol.Kind := _IsKeyword;
    end;
    //---
    procedure _GetNumber;
    var
        ANumLen: integer;
    begin
        with FSymbol do
        begin
            Num := 0;
            ANumLen := 0;
            //---
            repeat
                Num := 10 * Num + (ord(FChar) - ord('0'));
                ANumLen := ANumLen + 1;
                //---
                _GetChar;
            until not (FChar in ['0'..'9']);
            //---
            if ANumLen > CNT_Number_MaxLen then
                _ReportError(CNT_Error2);
        end;
        //---
        FSymbol.Kind := symNumber;
    end;
    //---获取赋值符号':='
    procedure _GetBecomes;
    begin
        _GetChar;
        if FChar = '=' then
        begin
            FSymbol.Kind := symBecomes;
            _GetChar;
        end
        else
            FSymbol.Kind := symNull;
    end;
    //---
    procedure _GetLessOrEuqal;
    begin
        _GetChar;
        if FChar = '=' then
        begin
            FSymbol.Kind := symLeq;
            _GetChar;
        end
        else
            FSymbol.Kind := symLss;
    end;
    //---
    procedure _GetGreatOrEuqal;
    begin
        _GetChar;
        if FChar = '=' then
        begin
            FSymbol.Kind := symGeq;
            _GetChar;
        end
        else
            FSymbol.Kind := symGtr;
    end;
    //---
    procedure _GetEof;
    begin
        FSymbol.Kind := symEof;
    end;
    //---
    procedure _GetSign;
    begin
        FSymbol.Kind := SignMap[FChar];
        _GetChar;
        //---
        if FSymbol.Kind = symNull then
            _ReportError(CNT_Error3);
    end;
begin
    _SkipBlanks;
    //---
    case FChar of
        'a'..'z': _GetIdent;
        '0'..'9': _GetNumber;
        ':': _GetBecomes;
        '<': _GetLessOrEuqal;
        '>': _GetGreatOrEuqal;
        #0: _GetEof;
    else
        _GetSign;
    end;
end;

end.

 

原创粉丝点击