compiler.cpp

来自「FastDb是高效的内存数据库系统」· C++ 代码 · 共 2,195 行 · 第 1/4 页

CPP
2,195
字号
//-< COMPILE.CPP >---------------------------------------------------*--------*
// FastDB                    Version 1.0         (c) 1999  GARRET    *     ?  *
// (Main Memory Database Management System)                          *   /\|  *
//                                                                   *  /  \  *
//                          Created:     20-Nov-98    K.A. Knizhnik  * / [] \ *
//                          Last update: 15-Jan-99    K.A. Knizhnik  * GARRET *
//-------------------------------------------------------------------*--------*
// Conditional expresion compiler
//-------------------------------------------------------------------*--------*

#define INSIDE_FASTDB

#include <ctype.h>
#include "database.h"
#include "array.h"
#include "query.h"
#include "cursor.h"
#include "compiler.h"
#include "symtab.h"

nat1 const dbExprNode::nodeTypes[] =
  {
#define DBVM(cop, type, n_opernads, commutative) type,
#include "compiler.d"
    0
  };

nat1 const dbExprNode::nodeOperands[] =
  {
#define DBVM(cop, type, n_operands, commutative) n_operands,
#include "compiler.d"
    0
  };

nat1 const dbExprNode::commutativeOperator[] =
  {
#define DBVM(cop, type, n_operands, commutative) commutative,
#include "compiler.d"
    0
  };


bool        dbCompiler::initialized;

dbExprNodeAllocator dbExprNodeAllocator::instance;

dbExprNodeAllocator::~dbExprNodeAllocator()
{
  dbExprNodeSegment* segm = segmentList;

  while (segm != NULL)
  {
    dbExprNodeSegment* next = segm->next;
    delete segm;
    segm = next;
  }
}

inline dbExprNode* dbExprNodeAllocator::allocate()
{
  dbCriticalSection cs(mutex);
  dbExprNode* node = freeNodeList;

  if (node == NULL)
  {
    dbExprNodeSegment* seg = new dbExprNodeSegment;
    seg->next = segmentList;
    segmentList = seg;
    node = (dbExprNode*)seg->buf;
    dbExprNode* free = NULL;

    for (int i = dbExprNodeSegment::allocationQuantum; --i != 0;)
    {
      node->next = free;
      free = node++;
    }

    freeNodeList = free;
  }
  else
  {
    freeNodeList = node->next;
  }

  return node;
}

void dbExprNodeAllocator::deallocate(dbExprNode* node)
{
  if (node != NULL)
  {
    node->next = freeNodeList;
    freeNodeList = node;
  }
}

void dbExprNodeAllocator::reset()
{
  dbExprNode* free = NULL;

  for (dbExprNodeSegment* seg = segmentList; seg != NULL; seg = seg->next)
  {
    dbExprNode* node = (dbExprNode*)seg->buf;

    for (int i = dbExprNodeSegment::allocationQuantum; --i >= 0;)
    {
      node->next = free;
      free = node++;
    }
  }

  freeNodeList = free;
}

dbExprNode::dbExprNode(dbExprNode* node)
{
  memcpy(this, node, sizeof(*this));

  for (int i = nodeOperands[cop]; --i >= 0;)
  {
    operand[i] = new dbExprNode(operand[i]);
  }

  if (cop == dbvmLoadStringConstant)
  {
    char* s = new char[strlen(svalue.str)+1];
    strcpy(s, svalue.str);
    svalue.str = s;
  }
}

dbExprNode::~dbExprNode()
{
  if (cop == dbvmLoadStringConstant)
  {
    delete[] svalue.str;
  }
  else
  {
    for (int i = nodeOperands[cop]; --i >= 0; )
    {
      delete operand[i];
    }
  }
}

int dbCompiler::scan()
{
  char ch;
  char *p, *q;
  int  i, n, value;
  char buf[maxStrLen+1];

  if (hasToken)
  {
    hasToken = false;
    return lex;
  }

nextElement:

  if (queryElement == NULL)
  {
    return tkn_eof;
  }

  if (queryElement->type != dbQueryElement::qExpression)
  {
    varType = queryElement->type;
    varPtr = queryElement->ptr;
    varRefTable = queryElement->ref;
    queryElement = queryElement->next;
    return tkn_var;
  }

  p = q = (char*)queryElement->ptr + currPos;

  do
  {
    ch = *p++;

    if (ch == '\n')
    {
      offsetWithinStatement = (char*)queryElement->ptr - p;
      firstPos = 0;
    }
  }
  while (isspace(byte(ch)));

  currPos += p - q;

  switch (ch)
  {

  case '\0':

    if ((queryElement = queryElement->next) == NULL)
    {
      return tkn_eof;
    }

    currPos = 0;
    goto nextElement;

  case '+':
    return tkn_add;

  case '-':

    if (*p == '-')
    {
      // ANSI comments
      q = p;

      do
      {
        p += 1;
      }
      while (*p != '\n' && *p != '\0');

      currPos += p - q;

      goto nextElement;
    }

    return tkn_sub;

  case '*':
    return tkn_mul;

  case '/':
    return tkn_div;

  case '.':
    return tkn_dot;

  case ',':
    return tkn_comma;

  case '(':
    return tkn_lpar;

  case ')':
    return tkn_rpar;

  case '[':
    return tkn_lbr;

  case ']':
    return tkn_rbr;

  case ':':
    return tkn_col;

  case '^':
    return tkn_power;

  case '<':

    if (*p == '=')
    {
      currPos += 1;
      return tkn_le;
    }
    else if (*p == '>')
    {
      currPos += 1;
      return tkn_ne;
    }

    return tkn_lt;

  case '>':

    if (*p == '=')
    {
      currPos += 1;
      return tkn_ge;
    }

    return tkn_gt;

  case '=':
    return tkn_eq;

  case '!':

    if (*p != '=')
    {
      error("Invalid token '!'");
    }

    currPos += 1;
    return tkn_ne;

  case '|':

    if (*p != '|')
    {
      error("Invalid token '|'");
    }

    currPos += 1;
    return tkn_add;

  case '\'':
    q = p;
    i = 0;

    while (true)
    {
      if (*p == '\'')
      {
        if (*++p != '\'')
        {
          break;
        }
      }
      else if (*p == '\0')
      {
        error("Unterminated character constant");
      }

      if (i == maxStrLen)
      {
        error("String constant too long");
      }

      buf[i++] = *p++;
    }

    buf[i++] = '\0';
    currPos += p - q;
    svalue.str = new char[i];
    strcpy(svalue.str, buf);
    svalue.len = i;
    return tkn_sconst;

  case '0':

  case '1':

  case '2':

  case '3':

  case '4':

  case '5':

  case '6':

  case '7':

  case '8':

  case '9':
    value = ch - '0';

    for (q = p; isdigit(*(byte*)p); p++)
    {
      value = value*10 + *p - '0';
    }

    if (*p == '.' || *p == 'e' || *p == 'E')
    {
      if (sscanf(q-1, "%lf%n", &fvalue, &n) != 1)
      {
        error("Bad floating point constant");
      }

      currPos += n - 1;
      return tkn_fconst;
    }
    else if (p - q >= 9)
    {
      if (sscanf(q-1, INT8_FORMAT "%n", &ivalue, &n) != 1)
      {
        error("Bad integer constant");
      }

      currPos += n - 1;
      return tkn_iconst;
    }
    else
    {
      currPos += p - q;
      ivalue = value;
      return tkn_iconst;
    }

  default:

    if (isalpha(ch) || ch == '$' || ch == '_')
    {
      i = 0;

      do
      {
        if (i == maxStrLen)
        {
          error("Name too long");
        }

        buf[i++] = ch;
        ch = *p++;
      }
      while (isalnum(ch) || ch == '$' || ch == '_');

      buf[i] = '\0';

      name = buf;

      currPos += i - 1;
    }
    else
    {
      error("Invalid symbol");
    }

    return dbSymbolTable::add
             (name, tkn_ident);
  }
}

dbExprNode* dbCompiler::disjunction()
{
  dbExprNode* left = conjunction();

  if (lex == tkn_or)
  {
    int pos = currPos;
    dbExprNode* right = disjunction();

    if (left->type == tpInteger && right->type == tpInteger)
    {
      left = new dbExprNode(dbvmOrInt, left, right);
    }
    else if (left->type == tpBoolean && right->type == tpBoolean)
    {
      left = new dbExprNode(dbvmOrBool, left, right);
    }
    else
    {
      error("Bad operands for OR operator", pos);
    }
  }

  return left;
}

dbExprNode* dbCompiler::conjunction()
{
  dbExprNode* left = comparison();

  if (lex == tkn_and)
  {
    int pos = currPos;
    dbExprNode* right = conjunction();

    if (left->type == tpInteger && right->type == tpInteger)
    {
      left = new dbExprNode(dbvmAndInt, left, right);
    }
    else if (left->type == tpBoolean && right->type == tpBoolean)
    {
      left = new dbExprNode(dbvmAndBool, left, right);
    }
    else
    {
      error("Bad operands for AND operator", pos);
    }
  }

  return left;
}

inline dbExprNode* int2real(dbExprNode* expr)
{
  if (expr->cop == dbvmLoadIntConstant)
  {
    expr->fvalue = (real8)expr->ivalue;
    expr->cop = dbvmLoadRealConstant;
    expr->type = tpReal;
  }
  else
  {
    expr = new dbExprNode(dbvmIntToReal, expr);
  }

  return expr;
}

int dbCompiler::compare(dbExprNode* expr, dbExprNode* list)
{
  int n = 1;

  if (list->operand[0] != NULL)
  {
    n = compare(expr, list->operand[0]);
    expr = new dbExprNode(expr);
  }

  dbExprNode* elem = list->operand[1];
  int cop = dbvmVoid;
  int rawBinarySize = 0;
  void* rawBinaryComparator = NULL;

  if (expr->type == tpInteger)
  {
    if (elem->type == tpReal)
    {
      expr = int2real(expr);
      cop = dbvmEqReal;
    }
    else if (elem->type == tpReference)
    {
      expr = new dbExprNode(dbvmIntToReference, expr);
      cop = dbvmEqReference;
    }
    else if (elem->type == tpInteger)
    {
      cop = dbvmEqInt;
    }
  }
  else if (expr->type == tpReal)
  {
    if (elem->type == tpReal)
    {
      cop = dbvmEqReal;
    }
    else if (elem->type == tpInteger)
    {
      cop = dbvmEqReal;
      elem = int2real(elem);
    }
  }
  else if (expr->type == tpString && elem->type == tpString)
  {
    cop = dbvmEqString;
  }
  else if (expr->type == tpReference && (elem->type == tpReference || elem->type == tpInteger))
  {
    if (elem->type == tpInteger)
    {
      elem = new dbExprNode(dbvmIntToReference, elem);
    }

    cop = dbvmEqReference;

⌨️ 快捷键说明

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