⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 unitparser.pas

📁 Delphi的另一款钢琴软件
💻 PAS
📖 第 1 页 / 共 2 页
字号:
    raise EParser.Create('Unexpected #else');
  SkipLine;
end;

procedure TCPreProcessor.DoEndif;
begin
  if fIfLevel > 0 then
  begin
    Dec (fIfLevel);
    SkipLine;
  end
  else
    raise EParser.Create('Unexpected endif');

end;

procedure TCPreProcessor.DoError;
begin
  GetRestOfLine;
  if IncludeFile = '' then
    raise EErrorPragma.CreateFmt ('#Error in line %d %s', [fLineNo, fToken])
  else
    raise EErrorPragma.CreateFmt ('#Error in line %d:s %s', [fLineNo, IncludeFile, fToken])
end;

procedure TCPreProcessor.DoIf;
var
  expr : string;
  val : TValue;
begin
  GetRestOfLine;
  expr := fToken;

  CalcExpression (expr, fIdentifiers, val);

  if (val.tp <> vInteger) then
   raise EParser.Create('Must be an integer expression');

  Inc (fIfLevel);

  if val.iVal = 0 then
    SkipIfElseBlock;
  SkipLine;
end;

procedure TCPreProcessor.DoIfDef;
begin
  NextIdentifier ('Identifier expected in ifdef');
  Inc (fIfLevel);
  SkipLine;

  if not Defined (fToken) then
    SkipIfElseBlock;
  SkipLine;
end;

procedure TCPreProcessor.DoIfNDef;
begin
  NextIdentifier ('Identifier expected in ifdef');
  Inc (fIfLevel);
  SkipLine;

  if Defined (fToken) then
    SkipIfElseBlock;
  SkipLine;
end;

procedure TCPreProcessor.DoInclude;
var
  oldReader : TStreamTextReader;
  oldLinePos, oldLineNo, oldIfLevel : Integer;
  oldLineBuf : string;
  oldSOL : boolean;
  oldCh : char;
  oldPathName : string;
  r : TStreamTextReader;
  f : TFileStream;
  fName : string;
begin
  NextFileString ('File name expected');

  oldReader := fReader;
  oldLinePos := fLinePos;
  oldLineNo := fLineNo;
  oldLineBuf := fLineBuf;
  oldIfLevel := fIfLevel;
  oldSol := fSOL;
  oldCh := fCh;
  oldPathName := PathName;

  r := Nil;
  fName := GetIncludePathName (fToken);
  f := TFileStream.Create(fName, fmOpenRead or fmShareDenyWrite);
  try
    r := TStreamTextReader.Create(f);
    fLinePos := 0;
    fLineNo := 0;
    fReader := r;
    fSOL := True;
    fFirstChar := True;
    fLineBuf := '';
    fIfLevel := 0;
    PathName := ExtractFilePath (fName);
    IncludeFile := ExtractFileName (fName);

    Parse;
  finally
    fReader := oldReader;
    fLinePos := oldLinePos;
    fLineNo := oldLineNo;
    fFirstChar := False;
    fLineBuf := oldLineBuf;
    fIfLevel := oldIfLevel;
    fSOL := oldSOL;
    fCh := oldCh;
    fPathName := oldPathName;
    r.Free;
    f.Free
  end;
  SkipLine;
end;

procedure TCPreProcessor.DoPragma;
begin
  HandlePragma (GetRestOfLine);
end;

procedure TCPreProcessor.DoUndef;
var
  id : string;
begin
  NextIdentifier ('Identifier expected in #undef');
  id := fToken;
  GetRestOfLine;

  DeleteIdentifier (id);
end;

procedure TCPreProcessor.ExpectChar(ch: char);
begin
  inherited;

end;

function TCPreProcessor.ExpectInteger(const errMsg: string): Integer;
begin
  if TokenType = ttIdentifier then
    Resolve (fTokenType, fToken);

  result := inherited ExpectInteger (errMsg);
end;

function TCPreProcessor.ExpectString(const errMsg: string): string;
begin
  if TokenType = ttIdentifier then
    Resolve (fTokenType, fToken);

  result := inherited ExpectString (errMsg);
end;

function TCPreProcessor.GetIncludePathName(const FileName: string): string;
var
  st, p : string;
  ch : char;
begin
  result := PathName + fileName;

  if not FileExists (result) then
  begin
    st := IncludePath;
    if st = '' then
      st := GetEnvironmentVariable ('include');

    while st <> '' do
    begin
      p := SplitString (';', st);

      if p <> '' then
      begin
        ch := p [Length (p)];
        if (ch <> '\') and (ch <> ':') then
          p := p + '\';

        result := p + fileName;
        if FileExists (result) then
          Exit
      end
    end;

    result := FileName
  end
end;

function TCPreProcessor.GetRestOfLine: string;
begin
  result := '';
  if fSol then
  begin
    fToken := '';
    exit;
  end;
  SkipWhitespace;
  fToken := '';
  repeat
    if fCh = '/' then
      if GetChar = '/' then
      begin
        SkipLine;
        break
      end
      else
        if fCh = '*' then
        begin
          GetChar;
          repeat
            if fLinePos >= Length (fLineBuf) then
              break;

            if fCh = '*' then
            begin
              if GetChar = '/' then
                break
            end
            else
              GetChar
          until fLinePos >= Length (fLineBuf)
        end
        else
          fToken := fToken + '/' + fCh
    else
      fToken := fToken + fCh;
    if fLinePos = Length (fLineBuf) then
    begin
      GetChar;
      break
    end;
    GetChar
  until False;
  fToken := Trim (fToken);
  result := fToken;
end;

function TCPreProcessor.GetToken: boolean;
var
  retry : boolean;
begin
  result := True;
  retry := True;
  while retry do
  begin
    retry := False;
    result := inherited GetToken;
    if not result then
    begin
      if fIfLevel <> 0 then
        raise EParser.Create('Unexpected end of file');
      Exit;
    end;

    if TokenType = ttChar then
    case fTokenChar of
      '/' : if fCh = '/' then
            begin
              SkipLine;
              retry := True;
            end
            else
            if fCh = '*' then
            begin
              repeat
                if GetChar = #0 then break;
                if (fCh = '*') and (GetChar = '/') then
                  break;
              until fCh = #0;
              GetChar;
              retry := True;
            end
            else
              fTokenType := ttOpDiv;
      '#' :
            if fTokenSOL then
            begin
              inherited GetToken;
              if fTokenType <> ttIdentifier then
                raise EParserError.Create('Syntax error in directive');
              HandleDirective;
              retry := True;
            end;
      '"' : begin
              fToken := '';
              while fCh <> #0 do
              begin
                case fCh of
                  '"' : break;
                  '\' :
                    case GetChar of
                      '"' : fToken := fToken + '"';
                      'n' : fToken := fToken + #10;
                      'r' : fToken := fToken + #13;
                      't' : fToken := fToken + #9;
                      '\' : fToken := fToken + '\';
                      '0' : fToken := fToken + #0;
                      else
                        raise EParserError.Create('Invalid escape sequence');
                    end;
                  else
                    fToken := fToken + fCh
                end;
                GetChar
              end;
              fTokenType := ttString;
              GetChar;
            end;
    end
  end
end;

procedure TCPreProcessor.HandleDirective;
var
  idx : Integer;
begin
  idx := fDirectives.IndexOf(LowerCase (fToken));
  if idx >= 0 then
  case Integer (fDirectives.Objects [idx]) of
    dtInclude : DoInclude;
    dtDefine  : DoDefine;
    dtIfDef   : DoIfDef;
    dtIfnDef  : DoIfNDef;
    dtEndif   : DoEndif;
    dtUndef   : DoUndef;
    dtElse    : DoElse;
    dtIf      : DoIf;
    dtPragma  : DoPragma;
    dtError   : DoError;
    else
      raise EParser.Create('Unknown directive #' + fToken)
  end
  else
    raise EParser.Create('Unknown directive #' + fToken)
end;

procedure TCPreProcessor.HandlePragma(const st: string);
begin

end;

function TCPreProcessor.IsIdentifier(const id: string): boolean;
begin
  result := fIdentifiers.IndexOf(id) >= 0
end;

procedure TCPreProcessor.NextFileString(const errMsg: string);
begin
  GetChar;
  if fCh = '<' then
  begin
    GetChar;
    fToken := '';
    while fCh <> #0 do
    begin
      case fCh of
        '>' : break;
        else
          fToken := fToken + fCh
      end;
      GetChar
    end;
    fTokenType := ttString
  end
  else
    if ch = '"' then
    begin
      GetChar;
      fToken := '';
      while fCh <> #0 do
      begin
        case fCh of
          '"' : break;
          else
            fToken := fToken + fCh
        end;
        GetChar
      end;
      fTokenType := ttString
    end
    else
      GetToken;

  if TokenType <> ttString then
    raise EParser.Create(errMsg);
end;

function TCPreProcessor.Resolve(var TokenType : Integer; var st: string): TValue;
begin
  if (TokenType = ttIdentifier) and IsIdentifier (st) then
  begin
    CalcExpression (st, fIdentifiers, result);

    case result.tp of
      vString  : begin st := result.sVal; tokenType := ttString; end;
      vInteger : begin st := IntToStr (result.iVal); tokenType := ttNumber; end;
      vReal    : begin st := FloatToStr (result.rVal); tokenType := ttNumber; end;
    end
  end
end;

function TCPreProcessor.ResolveToken: TValue;
begin
  if (TokenType = ttNumber) or (TokenType = ttIdentifier) then
    result := Calc (Token)
  else
    if TokenType = ttString then
    begin
      result.tp := vString;
      result.sVal := Token
    end
    else
      raise EParser.Create('Value expected');

end;

procedure TCPreProcessor.SkipIfElseBlock;
var
  level : Integer;
begin
  level := 0;
  repeat
    SkipWhitespace;
    if fCh = #0 then Break;
    if fCh = '#' then
    begin
      GetChar;
      inherited GetToken;
      if fToken = 'endif' then
        if level = 0 then
          break
        else
          Dec (level)
      else
        if (fToken = 'ifdef') or (ftoken = 'ifndef') or (ftoken = 'if') then
          Inc (level)
    end
    else
      fSOL := False;
    SkipLine
  until False;
  Dec (fIfLevel)
end;

end.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -