📄 compiler.cpp
字号:
//-< 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};dbExprNode* dbExprNode::freeNodeList;dbMutex& dbExprNode::mutex = *new dbMutex;bool dbCompiler::initialized;dbExprNodeSegment* dbExprNode::segmentList;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; } }void* dbExprNode::operator new(size_t) { dbCriticalSection cs(mutex); dbExprNode* node = freeNodeList; if (node == NULL) { dbExprNodeSegment* seg = new dbExprNodeSegment; seg->next = segmentList; segmentList = seg; node = (dbExprNode*)seg->buf; dbExprNode* freeNode = NULL; for (int i = dbExprNodeSegment::allocationQuantum; --i != 0;) { node->next = freeNode; freeNode = node++; } freeNodeList = freeNode; } else { freeNodeList = node->next; } return node;}void dbExprNode::cleanup(){ dbExprNode* freeNode = NULL; for (dbExprNodeSegment* seg = segmentList; seg != NULL; seg = seg->next) { dbExprNode* node = (dbExprNode*)seg->buf; for (int i = dbExprNodeSegment::allocationQuantum; --i >= 0;) { node->next = freeNode; freeNode = node++; } } freeNodeList = freeNode;}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]; 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 == 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) { cop = dbvmEqReference; } else if (expr->type == tpBoolean && elem->type == tpBoolean) { cop = dbvmEqBool; } else if (expr->type == tpRawBinary && elem->type == tpRawBinary) { cop = dbvmEqBinary; if ((expr->cop == dbvmLoadSelfRawBinary || expr->cop == dbvmLoadRawBinary) && expr->ref.field != NULL) { rawBinarySize = expr->ref.field->dbsSize; rawBinaryComparator = (void*)expr->ref.field->comparator; } else if ((elem->cop == dbvmLoadSelfRawBinary || elem->cop == dbvmLoadRawBinary) && elem->ref.field != NULL) { rawBinarySize = elem->ref.field->dbsSize; rawBinaryComparator = (void*)elem->ref.field->comparator; } else { error("Operations with raw binary types should include at least one record field"); } } if (cop == dbvmVoid) { char buf[256]; sprintf(buf, "Expression %d in right part of IN operator have " "incompatible type", n); error(buf); } else { list->type = tpBoolean; if (list->operand[0] != NULL) { expr = new dbExprNode(cop, expr, elem, rawBinarySize); expr->func.fptr = rawBinaryComparator; list->operand[1] = expr; list->cop = dbvmOrBool; } else { list->operand[0] = expr; list->cop = cop; list->offs = rawBinarySize; list->func.fptr = rawBinaryComparator; } } return ++n;}dbExprNode* dbCompiler::comparison(){ int leftPos = currPos; dbExprNode *left, *right; left = addition(); int cop = lex; if (cop == tkn_eq || cop == tkn_ne || cop == tkn_gt || cop == tkn_ge || cop == tkn_le || cop == tkn_lt || cop == tkn_between || cop == tkn_like || cop == tkn_not || cop == tkn_is || cop == tkn_in) { int rightPos = currPos; bool notOp = false; if (cop == tkn_not) { notOp = true; cop = scan(); if (cop != tkn_like && cop != tkn_between && cop != tkn_in) { error("LIKE, BETWEEN or IN expected", rightPos); } rightPos = currPos; } else if (cop == tkn_is) { if (left->type != tpReference) { error("IS [NOT] NULL predicate can be applied only to " "references", rightPos); } rightPos = currPos; if ((cop = scan()) == tkn_null) { left = new dbExprNode(dbvmIsNull, left); } else if (cop == tkn_not) { rightPos = currPos; if (scan() == tkn_null) { left = new dbExprNode(dbvmNotBool, new dbExprNode(dbvmIsNull, left)); } else { error("NULL expected", rightPos); } } else { error("[NOT] NULL expected", rightPos); } lex = scan(); return left; } right = addition(); if (cop == tkn_in) { int type; switch (right->type) { case tpArray: type = (right->cop == dbvmLoadVarArray || right->cop == dbvmLoadVarArrayPtr) ? dbField::tpReference : right->ref.field->components->type; if ((left->type == tpBoolean && type == dbField::tpBool) || (left->type == tpInteger && (type == dbField::tpInt1 || type == dbField::tpInt2 || type == dbField::tpInt4 || type == dbField::tpInt8)) || (left->type == tpReal && (type == dbField::tpReal4 || type == dbField::tpReal8)) || (left->type == tpString && type == dbField::tpString) || (left->type == tpReference && type == dbField::tpReference)) { left = new dbExprNode(dbvmInArrayBool + type, left, right); } else { error("Type of selective expression of IN operator doesn't" " match type of the array"); } break; case tpString: if (left->type == tpString) { left = new dbExprNode(dbvmInString, left, right); } else { error("Left operand of IN expression hasn't string type"); } break; case tpList: compare(left, right); left = right; break; default: error("List of expressions or array expected", rightPos); } } else if (cop == tkn_between) { int andPos = currPos; if (lex != tkn_and) { error("AND expected"); } dbExprNode* right2 = addition(); if (left->type == tpReal || right->type == tpReal || right2->type == tpReal) { if (left->type == tpInteger) { left = int2real(left); } else if (left->type != tpReal) { error("operand of BETWEEN operator should be of " "integer, real or string type", leftPos); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -