コード例 #1
0
mresult_t ExpressionParser::parseExpression(ASTElement** dst,
  ASTElement* _left,
  int minPriority,
  bool isInsideExpression)
{
  ASTElement* left = _left;
  ASTElement* right = NULL;

  mresult_t result = MRESULT_OK;
  uint op = MOPERATOR_NONE;

  Token& token = _last;
  Token helper;

  for (;;)
  {
    _tokenizer.next(&token);

    switch (token.tokenType)
    {
      // ----------------------------------------------------------------------
      case MTOKEN_ERROR:
        _tokenizer.back(&token);
        result = MRESULT_INVALID_TOKEN;
        goto failure;
      // ----------------------------------------------------------------------

      // ----------------------------------------------------------------------
      case MTOKEN_COMMA:
      case MTOKEN_SEMICOLON:
        if (left == NULL)
        {
          return (isInsideExpression)
            ? MRESULT_UNEXPECTED_TOKEN
            : MRESULT_OK;
        }
        // ... fall through ...
      // ----------------------------------------------------------------------

      // ----------------------------------------------------------------------
      case MTOKEN_END_OF_INPUT:
        if (op != MOPERATOR_NONE)
        {
          // Operand expected
          result = MRESULT_EXPRESSION_EXPECTED;
          goto failure;
        }

        _tokenizer.back(&token);
        *dst = left;
        return MRESULT_OK;
      // ----------------------------------------------------------------------

      // ----------------------------------------------------------------------
      case MTOKEN_INTEGER:
      case MTOKEN_FLOAT:
        if (left != NULL && op == MOPERATOR_NONE)
        {
          // Expected operator or end of expression
          result = MRESULT_UNEXPECTED_TOKEN;
          goto failure;
        }

        right = new ASTConstant(_ctx.genId(), token.f);
        break;
      // ----------------------------------------------------------------------

      // ----------------------------------------------------------------------
      case MTOKEN_LPAREN:
        if (left != NULL && op == MOPERATOR_NONE)
        {
          // Expected operator or end of expression
          result = MRESULT_UNEXPECTED_TOKEN;
          goto failure;
        }

        result = parseExpression(&right, NULL, 0, true);
        if (result != MRESULT_OK)
          goto failure;

        _tokenizer.next(&token);
        if (token.tokenType != MTOKEN_RPAREN)
        {
          result = MRESULT_UNEXPECTED_TOKEN;
          goto failure;
        }

        break;
      // ----------------------------------------------------------------------

      // ----------------------------------------------------------------------
      case MTOKEN_RPAREN:
        if (op != MOPERATOR_NONE)
        {
          result = MRESULT_UNEXPECTED_TOKEN;
          goto failure;
        }

        if (left == NULL && isInsideExpression)
        {
          result = MRESULT_UNEXPECTED_TOKEN;
          goto failure;
        }

        _tokenizer.back(&token);
        *dst = left;
        return MRESULT_OK;
      // ----------------------------------------------------------------------

      // ----------------------------------------------------------------------
      case MTOKEN_OPERATOR:
        if (token.operatorType == MOPERATOR_ASSIGN)
        {
          /* Why not?
          // Assignment inside expression is not allowed.
          if (isInsideExpression)
          {
            result = MRESULT_ASSIGNMENT_INSIDE_EXPRESSION;
            goto failure;
          }
          */

          // Can assign only to a variable
          if (left == NULL || left->getElementType() != MELEMENT_VARIABLE)
          {
            result = MRESULT_ASSIGNMENT_TO_NON_VARIABLE;
            goto failure;
          }
        }

        if (op != MOPERATOR_NONE || left == NULL)
        {
          if (token.operatorType == MOPERATOR_PLUS)
            // Ignore unary plus
            continue;

          if (token.operatorType == MOPERATOR_MINUS)
          {
            // Unary minus
            result = parseExpression(&right, right, mpOperatorInfo[MOPERATOR_UMINUS].priority, true);
            if (result != MRESULT_OK)
              goto failure;

            if (right == NULL)
            {
              result = MRESULT_EXPRESSION_EXPECTED;
              goto failure;
            }

            ASTTransform* transform = new ASTTransform(_ctx.genId());
            transform->setTransformType(MTRANSFORM_NEGATE);
            transform->setChild(right);
            right = transform;
            break;
		  }
          result = MRESULT_UNEXPECTED_TOKEN;
          goto failure;
		}

        op = token.operatorType;
		if (mpOperatorInfo[op].priority < minPriority || (mpOperatorInfo[op].priority == minPriority && mpOperatorInfo[op].assoc == LeftAssoc))
        {
          _tokenizer.back(&token);

          *dst = left;
          return MRESULT_OK;
        }
        continue;
      // ----------------------------------------------------------------------

      // ----------------------------------------------------------------------
      case MTOKEN_SYMBOL:
      {
        if (left != NULL && op == MOPERATOR_NONE)
        {
          // Expected operator or end of expression
          result = MRESULT_UNEXPECTED_TOKEN;
          goto failure;
        }

        const char* symbolName = _tokenizer.beg + token.pos;
        size_t symbolLength = token.len;

        Token ttoken;
        bool isFunction = (_tokenizer.peek(&ttoken) == MTOKEN_LPAREN);

        // Parse function
        if (isFunction)
        {
          Function* function = _ctx._ctx->functions.get(symbolName, symbolLength);
          if (function == NULL)
          {
            result = MRESULT_INVALID_FUNCTION;
            goto failure;
          }

          // Parse LPAREN token again
          _tokenizer.next(&ttoken);

          Vector<ASTElement*> arguments;

          // Parse function arguments
          int numArgs = function->getArgumentsCount();
          int n = 0;
          for (;;++n)
          {
            _tokenizer.next(&ttoken);

            if (ttoken.tokenType == MTOKEN_ERROR)
            {
              mpDeleteAll(arguments);
              result = MRESULT_INVALID_TOKEN;
              goto failure;
            }

            // ')' - End of function call
            if (ttoken.tokenType == MTOKEN_RPAREN)
            {
              if (n == numArgs) break;

              mpDeleteAll(arguments);
              result = MRESULT_NOT_ENOUGH_ARGUMENTS;
              goto failure;
            }

            // ',' - Arguments delimiter
            if (n != 0)
            {
              if (ttoken.tokenType == MTOKEN_COMMA)
              {
                if (n >= numArgs)
                {
                  mpDeleteAll(arguments);
                  result = MRESULT_TOO_MANY_ARGUMENTS;
                  goto failure;
                }
              }
              else
              {
                mpDeleteAll(arguments);
                result = MRESULT_UNEXPECTED_TOKEN;
                goto failure;
              }
            }
            else
            {
              _tokenizer.back(&ttoken);
            }

            // Parse argument expression
            ASTElement* arg;
            if ((result = parseExpression(&arg, NULL, 0, true)) != MRESULT_OK)
            {
              mpDeleteAll(arguments);
              goto failure;
            }

            arguments.append(arg);
          }

          // Done
          ASTCall* call = new ASTCall(_ctx.genId(), function);
          call->swapArguments(arguments);
          right = call;
        }
        else
        // Parse variable
        {
          Variable* var = _ctx._ctx->variables.get(symbolName, symbolLength);
          if (var == NULL)
          {
            result = MRESULT_INVALID_SYMBOL;
            goto failure;
          }

          if (var->type == MVARIABLE_CONSTANT)
            right = new ASTConstant(_ctx.genId(), var->c.value);
          else
            right = new ASTVariable(_ctx.genId(), var);
        }

        break;
      }
      // ----------------------------------------------------------------------

      // ----------------------------------------------------------------------
      default:
        MP_ASSERT_NOT_REACHED();
      // ----------------------------------------------------------------------
    }

	MP_ASSERT(right != NULL);

    if (left)
    {
      _tokenizer.peek(&helper);

      if (helper.tokenType == MTOKEN_OPERATOR)
      {
        int lp = mpOperatorInfo[op].priority;
        int np = mpOperatorInfo[helper.operatorType].priority;
        if (lp < np || (lp == np && mpOperatorInfo[op].assoc == RightAssoc))
        {
          result = parseExpression(&right, right, lp, true);
          if (result != MRESULT_OK)
            goto failure;
        }
      }

      MP_ASSERT(op != MOPERATOR_NONE);
      ASTOperator* parent = new ASTOperator(_ctx.genId(), op);
      parent->setLeft(left);
      parent->setRight(right);

      left = parent;
      right = NULL;
      op = MOPERATOR_NONE;
    }
    else
    {
      left = right;
      right = NULL;
    }
  }

failure:
  if (left) delete left;
  if (right) delete right;

  *dst = NULL;
  return result;
}
コード例 #2
0
mresult_t ExpressionParser::parseExpression(ASTElement** dst,
  ASTElement* _left,
  int minPriority,
  bool isInsideExpression)
{
  ASTElement* left = _left;
  ASTElement* right = NULL;

  mresult_t result = MRESULT_OK;
  uint op = MOPERATOR_NONE;
  uint om = MOPERATOR_NONE;

  Token& token = _last;
  Token helper;

  for (;;)
  {
    _tokenizer.next(&token);

    switch (token.tokenType)
    {
      // ----------------------------------------------------------------------
      case MTOKEN_ERROR:
        _tokenizer.back(&token);
        result = MRESULT_INVALID_TOKEN;
        goto failure;
      // ----------------------------------------------------------------------

      // ----------------------------------------------------------------------
      case MTOKEN_COMMA:
      case MTOKEN_SEMICOLON:
        if (left == NULL)
        {
          return (isInsideExpression)
            ? MRESULT_UNEXPECTED_TOKEN
            : MRESULT_OK;
        }
        // ... fall through ...
      // ----------------------------------------------------------------------

      // ----------------------------------------------------------------------
      case MTOKEN_END_OF_INPUT:
        if (op != MOPERATOR_NONE)
        {
          // Expecting expression.
          result = MRESULT_EXPECTED_EXPRESSION;
          goto failure;
        }

        _tokenizer.back(&token);
        *dst = left;
        return MRESULT_OK;
      // ----------------------------------------------------------------------

      // ----------------------------------------------------------------------
      case MTOKEN_INTEGER:
      case MTOKEN_FLOAT:
        right = new ASTConstant(_ctx.genId(),
          om == MOPERATOR_MINUS ? -token.f : token.f);
        om = MOPERATOR_NONE;
        break;
      // ----------------------------------------------------------------------

      // ----------------------------------------------------------------------
      case MTOKEN_LPAREN:
        result = parseExpression(&right, NULL, 0, true);
        if (result != MRESULT_OK) goto failure;

        _tokenizer.next(&token);
        if (token.tokenType != MTOKEN_RPAREN)
        {
          result = MRESULT_UNEXPECTED_TOKEN;
          goto failure;
        }

        if (om == MOPERATOR_MINUS)
        {
          ASTTransform* transform = new ASTTransform(_ctx.genId());
          transform->setTransformType(MTRANSFORM_NEGATE);
          transform->setChild(right);
          right = transform;
        }

        om = MOPERATOR_NONE;
        break;
      // ----------------------------------------------------------------------

      // ----------------------------------------------------------------------
      case MTOKEN_RPAREN:
        if (op != MOPERATOR_NONE ||
            om != MOPERATOR_NONE)
        {
          result = MRESULT_UNEXPECTED_TOKEN;
          goto failure;
        }

        if (left == NULL && isInsideExpression)
        {
          result = MRESULT_UNEXPECTED_TOKEN;
          goto failure;
        }

        _tokenizer.back(&token);
        *dst = left;
        return MRESULT_OK;
      // ----------------------------------------------------------------------

      // ----------------------------------------------------------------------
      case MTOKEN_OPERATOR:
        if (token.operatorType == MOPERATOR_ASSIGN)
        {
          // Assignment inside expression is not allowed.
          if (isInsideExpression)
          {
            result = MRESULT_ASSIGNMENT_INSIDE_EXPRESSION;
            goto failure;
          }
          // Must be assigned to an variable.
          if (left == NULL || left->getElementType() != MELEMENT_VARIABLE)
          {
            result = MRESULT_ASSIGNMENT_TO_NON_VARIABLE;
            goto failure;
          }
        }

        if (op == MOPERATOR_NONE && left == NULL)
        {
          om = token.operatorType;
          if (om == MOPERATOR_PLUS || om == MOPERATOR_MINUS) continue;

          result = MRESULT_UNEXPECTED_TOKEN;
          goto failure;
        }

        op = token.operatorType;
        if (mpOperatorPriority[op] < minPriority)
        {
          _tokenizer.back(&token);

          *dst = left;
          return MRESULT_OK;
        }
        continue;
      // ----------------------------------------------------------------------

      // ----------------------------------------------------------------------
      case MTOKEN_SYMBOL:
      {
        const char* symbolName = _tokenizer.beg + token.pos;
        size_t symbolLength = token.len;

        Token ttoken;
        bool isFunction = (_tokenizer.peek(&ttoken) == MTOKEN_LPAREN);

        // Parse function.
        if (isFunction)
        {
          Function* function = _ctx._ctx->functions.get(symbolName, symbolLength);
          if (function == NULL)
          {
            result = MRESULT_NO_SYMBOL;
            goto failure;
          }

          // Parse LPAREN token again.
          _tokenizer.next(&ttoken);

          Vector<ASTElement*> arguments;
          bool first = true;

          // Parse function arguments.
          for (;;)
          {
            _tokenizer.next(&ttoken);

            if (ttoken.tokenType == MTOKEN_ERROR)
            {
              mpDeleteAll(arguments);
              result = MRESULT_INVALID_TOKEN;
              goto failure;
            }

            // ')' - End of function call.
            if (ttoken.tokenType == MTOKEN_RPAREN)
            {
              break;
            }

            // ',' - Arguments delimiter for non-first argument.
            if (!first)
            {
              if (ttoken.tokenType != MTOKEN_COMMA)
              {
                mpDeleteAll(arguments);
                result = MRESULT_EXPECTED_EXPRESSION;
                goto failure;
              }
            }
            else
            {
              _tokenizer.back(&ttoken);
            }

            // Expression.
            ASTElement* arg;
            if ((result = parseExpression(&arg, NULL, 0, true)) != MRESULT_OK)
            {
              mpDeleteAll(arguments);
              goto failure;
            }

            arguments.append(arg);
            first = false;
          }

          // Validate function arguments.
          if (function->getArguments() != arguments.getLength())
          {
            mpDeleteAll(arguments);
            result = MRESULT_ARGUMENTS_MISMATCH;
            goto failure;
          }

          // Done.
          ASTCall* call = new ASTCall(_ctx.genId(), function);
          call->swapArguments(arguments);
          right = call;
        }
        // Parse variable.
        else
        {
          Variable* var = _ctx._ctx->variables.get(symbolName, symbolLength);
          if (var == NULL)
          {
            result = MRESULT_NO_SYMBOL;
            goto failure;
          }

          if (var->type == MVARIABLE_CONSTANT)
            right = new ASTConstant(_ctx.genId(), var->c.value);
          else
            right = new ASTVariable(_ctx.genId(), var);
        }

        if (om == MOPERATOR_MINUS)
        {
          ASTTransform* transform = new ASTTransform(_ctx.genId());
          transform->setTransformType(MTRANSFORM_NEGATE);
          transform->setChild(right);
          right = transform;
        }

        om = MOPERATOR_NONE;
        break;
      }
      // ----------------------------------------------------------------------

      // ----------------------------------------------------------------------
      default:
        MP_ASSERT_NOT_REACHED();
      // ----------------------------------------------------------------------
    }

    if (left)
    {
      _tokenizer.peek(&helper);

      if (helper.tokenType == MTOKEN_OPERATOR && mpOperatorPriority[op] < mpOperatorPriority[helper.operatorType])
      {
        result = parseExpression(&right, right, mpOperatorPriority[helper.operatorType], true);
        if (result != MRESULT_OK) { right = NULL; goto failure; }
      }

      ASTOperator* parent = new ASTOperator(_ctx.genId(), op);
      parent->setLeft(left);
      parent->setRight(right);

      left = parent;
      right = NULL;
      op = MOPERATOR_NONE;
    }
    else
    {
      left = right;
      right = NULL;
    }
  }

failure:
  if (left) delete left;
  if (right) delete right;

  *dst = NULL;
  return result;
}