excelparser.pas

来自「该程序把Excel公式分解为Token序列。」· PAS 代码 · 共 670 行 · 第 1/2 页

PAS
670
字号
      continue;
    end;

    // error values
    // end marks a token, determined from absolute list of values
    if (inError) then begin
      token := token + currentChar(offset);
      offset := offset + 1;
      if pos(',' + token + ',', ',#NULL!,#DIV/0!,#VALUE!,#REF!,#NAME?,#NUM!,#N/A,') <> 0 then begin
        inError := false;
        tokens.addToken(token, TOK_TYPE_OPERAND, TOK_SUBTYPE_ERROR);
        token := '';
      end;
      continue;
    end;

    // scientific notation check

    if pos(currentChar(offset), '+-') <> 0 then begin
      if (length(token) > 1) then begin
        if ExecRegExpr('^[1-9]{1}(\.[0-9]+)?E{1}$', token) then begin
          token := token + currentChar(offset);
          offset := offset + 1;
          continue;
        end;
      end;
    end;

    // independent character evaulation (order not important)

    // establish state-dependent character evaluations

    if (currentChar(Offset) = '"') then begin
      if (length(token) > 0) then begin
        // not expected
        tokens.addToken(token, TOK_TYPE_UNKNOWN, '');
        token := '';
      end;
      inString := true;
      offset := offset + 1;
      continue;
    end;

    if (currentChar(Offset) = '''') then begin
      if (length(token) > 0) then begin
        // not expected
        tokens.addToken(token, TOK_TYPE_UNKNOWN, '');
        token := '';
      end;
      inPath := true;
      offset := offset + 1;
      continue;
    end;

    if (currentChar(Offset) = '[') then begin
      inRange := true;
      token := token + currentChar(Offset);
      offset := offset + 1;
      continue;
    end;

    if (currentChar(Offset) = '#') then begin
      if (length(token) > 0) then begin
        // not expected
        tokens.addToken(token, TOK_TYPE_UNKNOWN, '');
        token := '';
      end;
      inError := true;
      token := token + currentChar(Offset);
      offset := offset + 1;
      continue;
    end;

    // mark start and end of arrays and array rows

    if (currentChar(Offset) = '{') then begin
      if (length(token) > 0) then begin
        // not expected
        tokens.addToken(token, TOK_TYPE_UNKNOWN, '');
        token := '';
      end;
      tokenStack.push(tokens.addToken('ARRAY', TOK_TYPE_FUNCTION, TOK_SUBTYPE_START));
      tokenStack.push(tokens.addToken('ARRAYROW', TOK_TYPE_FUNCTION, TOK_SUBTYPE_START));
      offset := offset + 1;
      continue;
    end;

    if (currentChar(Offset) = ';') then begin
      if (length(token) > 0) then begin
        tokens.addToken(token, TOK_TYPE_OPERAND, '');
        token := '';
      end;
      tokens.addref(tokenStack.pop);
      tokens.addToken(',', TOK_TYPE_ARGUMENT, '');
      tokenStack.push(tokens.addToken('ARRAYROW', TOK_TYPE_FUNCTION, TOK_SUBTYPE_START));
      offset := offset + 1;
      continue;
    end;

    if (currentChar(Offset) = '}') then begin
      if (length(token) > 0) then begin
        tokens.addToken(token, TOK_TYPE_OPERAND, '');
        token := '';
      end;
      tokens.addRef(tokenStack.pop);
      tokens.addRef(tokenStack.pop);
      offset := offset + 1;
      continue;
    end;

    // trim white-space

    if (currentChar(offset) = ' ') then begin
      if (length(token) > 0) then begin
        tokens.addToken(token, TOK_TYPE_OPERAND, '');
        token := '';
      end;
      tokens.addToken('', TOK_TYPE_WSPACE, '');
      offset := offset + 1;
      while ((currentChar(offset) = ' ') and (not EOF(offset))) do begin
        offset := offset + 1;
      end;
      continue;
    end;

    // multi-character comparators
    if pos(',' + doubleChar(Offset) + ',', ',>=,<=,<>,') <> 0 then begin
      if (length(token) > 0) then begin
        tokens.addToken(token, TOK_TYPE_OPERAND, '');
        token := '';
      end;
      tokens.addToken(doubleChar(Offset), TOK_TYPE_OP_IN, TOK_SUBTYPE_LOGICAL);
      offset := offset + 2;
      continue;
    end;

    // standard infix operators
    if pos(currentChar(offset), '+-*/^&=><') <> 0 then begin
      if (length(token) > 0) then begin
        tokens.addToken(token, TOK_TYPE_OPERAND, '');
        token := '';
      end;
      tokens.addToken(currentChar(offset), TOK_TYPE_OP_IN, '');
      offset := offset + 1;
      continue;
    end;

    // standard postfix operators
    if pos(currentChar(offset), '%') <> 0 then begin
      if (length(token) > 0) then begin
        tokens.addtoken(token, TOK_TYPE_OPERAND, '');
        token := '';
      end;
      tokens.addtoken(currentChar(offset), TOK_TYPE_OP_POST, '');
      offset := offset + 1;
      continue;
    end;

    // start subexpression or function

    if (currentChar(offset) = '(') then begin
      if (length(token) > 0) then begin
        tokenStack.push(tokens.addtoken(token, TOK_TYPE_FUNCTION, TOK_SUBTYPE_START));
        token := '';
      end else begin
        tokenStack.push(tokens.addtoken('', TOK_TYPE_SUBEXPR, TOK_SUBTYPE_START));
      end;
      offset := offset + 1;
      continue;
    end;

    // function, subexpression, array parameters

    if (currentChar(offset) = ',') then begin
      if (length(token) > 0) then begin
        tokens.addtoken(token, TOK_TYPE_OPERAND, '');
        token := '';
      end;
      //ShowMessage(inttostr(tokenstack.count));
      if (not (tokenStack.TokenType = TOK_TYPE_FUNCTION)) then begin
        tokens.addToken(currentChar(offset), TOK_TYPE_OP_IN, TOK_SUBTYPE_UNION);
      end else begin
        tokens.addToken(currentChar(offset), TOK_TYPE_ARGUMENT, '');
      end;
      offset := offset + 1;
      continue;
    end;

    // stop subexpression

    if (currentChar(offset) = ')') then begin
      if (length(token) > 0) then begin
        tokens.addtoken(token, TOK_TYPE_OPERAND, '');
        token := '';
      end;
      if tokenStack.Count > 0 then begin
        tokens.addRef(tokenStack.pop);
        offset := offset + 1;
        continue;
      end else
      begin
        ShowMessage('"' + currentChar(offset) + '" Error');
        break;
      end;
    end;

    // token accumulation

    token := token + currentChar(offset);
    offset := offset + 1;

  end; {while}

  // dump remaining accumulation

  if (length(token) > 0) then tokens.addtoken(token, TOK_TYPE_OPERAND, '');
  if tokenStack.Count > 0 then ShowMessage('Error tokenStack.Count>0');

  // move all tokens to a new collection, excluding all unnecessary white-space tokens

  tokens2 := TTokens.Create;

  while (tokens.moveNext) do begin

    Atoken := tokens.current;

    if (Atoken.TokenType = TOK_TYPE_WSPACE) then begin
      if ((tokens.BOF()) or (tokens.EOF())) then begin end
      else if (not (
        ((tokens.previous.TokenType = TOK_TYPE_FUNCTION) and (tokens.previous.subtype = TOK_SUBTYPE_STOP)) or
        ((tokens.previous.TokenType = TOK_TYPE_SUBEXPR) and (tokens.previous.subtype = TOK_SUBTYPE_STOP)) or
        (tokens.previous.TokenType = TOK_TYPE_OPERAND)
        )
        ) then begin end
      else if (not (
        ((tokens.next.TokenType = TOK_TYPE_FUNCTION) and (tokens.next.subtype = TOK_SUBTYPE_START)) or
        ((tokens.next.TokenType = TOK_TYPE_SUBEXPR) and (tokens.next.subtype = TOK_SUBTYPE_START)) or
        (tokens.next.TokenType = TOK_TYPE_OPERAND)
        )
        ) then begin end
      else
        tokens2.addtoken(Atoken.value, TOK_TYPE_OP_IN, TOK_SUBTYPE_INTERSECT);
      continue;
    end;

    tokens2.addRef(Atoken);

  end;

  // switch infix "-" operator to prefix when appropriate, switch infix "+" operator to noop when appropriate, identify operand
  // and infix-operator subtypes, pull "@" from in front of function names

  while (tokens2.moveNext) do begin

    Atoken := tokens2.current;

    if ((Atoken.tokentype = TOK_TYPE_OP_IN) and (atoken.value = '-')) then begin
      if (tokens2.BOF) then
        atoken.tokentype := TOK_TYPE_OP_PRE
      else if (
        ((tokens2.previous.tokentype = TOK_TYPE_FUNCTION) and (tokens2.previous.subtype = TOK_SUBTYPE_STOP)) or
        ((tokens2.previous.tokentype = TOK_TYPE_SUBEXPR) and (tokens2.previous.subtype = TOK_SUBTYPE_STOP)) or
        (tokens2.previous.tokentype = TOK_TYPE_OP_POST) or
        (tokens2.previous.tokentype = TOK_TYPE_OPERAND)
        ) then
        atoken.subtype := TOK_SUBTYPE_MATH
      else
        atoken.Tokentype := TOK_TYPE_OP_PRE;
      continue;
    end;

    if ((atoken.Tokentype = TOK_TYPE_OP_IN) and (atoken.value = '+')) then begin
      if (tokens2.BOF) then
        atoken.Tokentype := TOK_TYPE_NOOP
      else if (
        ((tokens2.previous.Tokentype = TOK_TYPE_FUNCTION) and (tokens2.previous.subtype = TOK_SUBTYPE_STOP)) or
        ((tokens2.previous.Tokentype = TOK_TYPE_SUBEXPR) and (tokens2.previous.subtype = TOK_SUBTYPE_STOP)) or
        (tokens2.previous.Tokentype = TOK_TYPE_OP_POST) or
        (tokens2.previous.Tokentype = TOK_TYPE_OPERAND)
        ) then
        atoken.subtype := TOK_SUBTYPE_MATH
      else
        atoken.Tokentype := TOK_TYPE_NOOP;
      continue;
    end;

    if ((atoken.Tokentype = TOK_TYPE_OP_IN) and (length(atoken.subtype) = 0)) then begin
      if pos(leftstr(AToken.Value, 1), '<>=') <> 0 then
        atoken.subtype := TOK_SUBTYPE_LOGICAL
      else if (atoken.value = '&') then
        atoken.subtype := TOK_SUBTYPE_CONCAT
      else
        atoken.subtype := TOK_SUBTYPE_MATH;
      continue;
    end;

    if ((atoken.Tokentype = TOK_TYPE_OPERAND) and (length(atoken.subtype) = 0)) then begin
      if not TextToFloat(PChar(atoken.value), tempf, fvExtended) then
        if ((atoken.value = 'TRUE') or (atoken.value = 'FALSE')) then
          atoken.subtype := TOK_SUBTYPE_LOGICAL
        else
          atoken.subtype := TOK_SUBTYPE_RANGE
      else
        atoken.subtype := TOK_SUBTYPE_NUMBER;
      continue;
    end;

    if (atoken.tokentype = TOK_TYPE_FUNCTION) then begin
      if (leftstr(atoken.value, 1) = '@') then
        atoken.value := RightStr(atoken.value, length(atoken.Value) - 1);
      continue;
    end;

  end;

  tokens2.reset;

  // move all tokens to a new collection, excluding all noops

  tokens.Clear;
  tokens.Reset;

  while (tokens2.moveNext) do begin
    if (tokens2.current.tokentype <> TOK_TYPE_NOOP) then
      tokens.addRef(tokens2.current);
  end;

  tokens.reset;
  result := tokens;
  tokenStack.Free;
end;

end.

⌨️ 快捷键说明

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