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

📄 compiler.cpp

📁 实现内存数据库的源代码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
      case tkn_true:
	expr = new dbExprNode(dbvmLoadTrue);
	break;
      case tkn_null:
	expr = new dbExprNode(dbvmLoadNull);
	break;
      case tkn_iconst:
	expr = new dbExprNode(dbvmLoadIntConstant, ivalue);
	break;
      case tkn_fconst:
	expr = new dbExprNode(dbvmLoadRealConstant, fvalue);
	break;
      case tkn_sconst:
	expr = new dbExprNode(dbvmLoadStringConstant, svalue); 
	lex = scan();
	return field(expr, NULL, NULL);
      case tkn_var:
	expr = new dbExprNode(dbvmLoadVarBool + varType - 
			      dbQueryElement::qVarBool, varPtr);
	refTable = varRefTable;
	lex = scan();
	return field(expr, refTable, NULL);
      case tkn_abs:
      case tkn_length:
      case tkn_lower:
      case tkn_upper:
      case tkn_integer:
      case tkn_real:
      case tkn_string:
	pos = currPos;
	expr = term();
	switch (cop) {
	  case tkn_abs:
	    if (expr->type == tpInteger) { 
		cop = dbvmAbsInt;
	    } else if (expr->type == tpReal) { 
		cop = dbvmAbsReal;
	    } else { 
		error("ABS function can be applied only "
		      "to integer or real expression", pos);
	    }
	    break;
	  case tkn_length:
	    if (expr->type == tpArray) { 
		cop = dbvmLength;
	    } else if (expr->type == tpString) { 
		cop = dbvmStringLength;
	    } else { 
		error("LENGTH function is defined only for arrays and strings",
		      pos);
	    } 
	    break;
	  case tkn_integer:
	    if (expr->type == tpReal) { 
		cop = dbvmRealToInt;
	    } else { 
		error("INTEGER function can be applied only to "
		      "expression of real type", pos);
	    }
	    break;
	  case tkn_real:
	    if (expr->type == tpInteger) { 
		cop = dbvmIntToReal;
	    } else { 
		error("REAL function can be applied only to "
		      "expression of integer type", pos);
	    }
	    break;
	  case tkn_string:
	    if (expr->type == tpInteger) { 
		cop = dbvmIntToString;
	    } else if (expr->type == tpReal) { 
		cop = dbvmRealToString;
	    } else { 
		error("STRING function can be applied only "
		      "to integer or real expression", pos);
	    }
	    break;
	  case tkn_lower:
	    if (expr->type != tpString) { 
		error("LOWER function can be applied only to string argument",
		      pos);
	    } else { 
		cop = dbvmLowerString;
	    }
	    break;
	  case tkn_upper:
	    if (expr->type != tpString) { 
		error("UPPER function can be applied only to string argument",
		      pos);
	    } else { 
		cop = dbvmUpperString;
	    }
	    break;
	  default:
	    assert(false);
	}
	return field(new dbExprNode(cop, expr), NULL, NULL);
      case tkn_lpar:
        {
	    expr = disjunction();
	    dbExprNode* list = NULL;
	    while (lex == tkn_comma) { 
		list = new dbExprNode(dbvmList, list, expr);
		expr = disjunction();
	    }
	    if (lex != tkn_rpar) { 
		error("')' expected");
	    }
	    if (list != NULL) { 
		expr = new dbExprNode(dbvmList, list, expr);
	    }
	}
	break;
      case tkn_not:
	pos = currPos;
	expr = comparison();
	if (expr->type == tpInteger) { 
	    if (expr->cop == dbvmLoadIntConstant) { 
		expr->ivalue = ~expr->ivalue;
	    } else {
		expr = new dbExprNode(dbvmNotInt, expr);
	    } 
	    return expr;
	} else if (expr->type == tpBoolean) { 
	    return new dbExprNode(dbvmNotBool, expr);
	} else { 
	    error("NOT operator can be applied only to "
		  "integer or boolean expressions", pos);
	}
	break;
      case tkn_add:
	error("Using of unary plus operator has no sence");
	break;
      case tkn_sub:
	pos = currPos;
	expr = term();
	if (expr->type == tpInteger) { 
	    if (expr->cop == dbvmLoadIntConstant) { 
		expr->ivalue = -expr->ivalue;
	    } else { 
		expr = new dbExprNode(dbvmNegInt, expr);
	    }
	    return expr;
	} else if (expr->type == tpReal) { 
	    if (expr->cop == dbvmLoadRealConstant) { 
		expr->fvalue = -expr->fvalue;
	    } else { 
		expr = new dbExprNode(dbvmNegReal, expr);
	    }
	    return expr;
	} else { 
	    error("Unary minus can be applied only to "
		  "integer or real expressions", pos);
	}
      default:
	error("operand expected");
    }
    lex = scan();
    return expr;
}

void dbCompiler::error(const char* msg, int pos) 
{ 
    if (pos < 0) { 
	if ((pos = currPos-1) < 0) { 
	    pos = 0;
	}
    } else if (pos < firstPos) { 
	pos = firstPos;
    }
    if (pos + offsetWithinStatement >= 0) { 
	pos += offsetWithinStatement;
    }
    table->db->handleError(dbDatabase::QueryError, msg, pos);
    longjmp(abortCompilation, dbDatabase::QueryError);
}

void dbCompiler::compileStartFollowPart(dbQuery& query)
{
    if (lex != tkn_start) {	
	return;
    }
    int pos = currPos;
    if (scan() != tkn_from) { 
	error("FROM expected after START", pos);
    }
    pos = currPos;
    switch (scan()) { 
      case tkn_first:
	query.startFrom = dbCompiledQuery::StartFromFirst; 
	break;
      case tkn_last:
	query.startFrom = dbCompiledQuery::StartFromLast; 
	break;
      case tkn_var:
	if (varType == dbQueryElement::qVarReference) { 
	    if (varRefTable != table) { 
		error("Incompatiable type of reference variable");
	    }
	    query.startFrom = dbCompiledQuery::StartFromRef; 
	} else if (varType == dbQueryElement::qVarArrayOfRef) {
	    if (varRefTable != table) { 
		error("Incompatiable type of array of reference variable");
	    }
	    query.startFrom = dbCompiledQuery::StartFromArray; 
	} else if (varType == dbQueryElement::qVarArrayOfRefPtr) {
	    if (varRefTable != table) { 
		error("Incompatiable type of array of reference variable");
	    }
	    query.startFrom = dbCompiledQuery::StartFromArrayPtr; 
	} else { 
	    error("Reference or array of reference variable expected");
	}
	query.root = varPtr;
	break;
      default:
	error("FIRST, LAST or reference varaible expected", pos); 
    }
    if ((lex = scan()) == tkn_follow) { 
	pos = currPos;
	if (scan() != tkn_by) { 
	    error("BY expected after FOLLOW", pos);
	}
	do { 
	    pos = currPos;
	    if (scan() != tkn_ident) { 
		error("Field name expected", pos);
	    }
	    dbFieldDescriptor* fd;
	    if ((fd = table->find(name)) == NULL) { 
		error("Field not found");
	    }
	    while (fd->type == dbField::tpStructure) { 
		pos = currPos;
		if (scan() != tkn_dot) { 
		    error("'.' expected", pos);
		}
		pos = currPos;
		if (scan() != tkn_ident) { 
		    error("Field name expected", pos);
		}
		if ((fd = fd->find(name)) == NULL) { 
		    error("Field not found");
		}
	    }
	    if (!(fd->type == dbField::tpReference 
		  && fd->refTable == table) &&
		!(fd->type == dbField::tpArray 
		  && fd->components->type == dbField::tpReference
		  && fd->components->refTable == table)) 
	    { 
		error("Follow field should be of compatibale reference "
		      "or array of reference type");
	    }
	    dbFollowByNode* node = new dbFollowByNode;
	    node->field = fd;
	    node->next = query.follow; // list should be inverted
	    query.follow = node;
	} while ((lex = scan()) == tkn_comma); 
    }	
}

void dbCompiler::compileOrderByPart(dbQuery& query)
{
    dbOrderByNode** opp = &query.order;
    if (lex == tkn_order) {	
	int pos = currPos;
	if (scan() != tkn_by) { 
	    error("BY expected after ORDER", pos);
	}
	int parentheses = 0;
	bool length = false;
	dbFieldDescriptor* fd;

	while (true) { 
	    pos = currPos;
	    switch (scan()) { 
	      case tkn_lpar:
		parentheses += 1;
		continue;
	      case tkn_rpar:
		if (--parentheses < 0) { 
		    error("Unbalanced parentheses ");
		}
		continue;
	      case tkn_length:
		length = true;
		continue;
	      case tkn_ident:		
		if ((fd = table->find(name)) == NULL) { 
		    error("Field not found", pos);
		}
		while (fd->type == dbField::tpStructure) { 
		    if (scan() != tkn_dot) { 
			error("'.' expected");
		    }
		    if (scan() != tkn_ident) { 
			error("field name expected", pos);
		    }
		    if ((fd = fd->find(name)) == NULL) { 
			error("Field not found", pos);
		    }
		}
		if (fd->type > dbField::tpReference) { 
		    if (fd->type != dbField::tpRawBinary 
 			&& (fd->type != dbField::tpArray || !length)) 
		    { 
		        error("Sort key should be of scalar or string type", pos);
		    }
		} else if (length && fd->type != dbField::tpString) { 
		   error("Length in ORDER BY part can be applied only to arrays or strings", pos);
		}		  
		dbOrderByNode* node = new dbOrderByNode;
		node->field = fd;
		node->ascent = true;
				node->stringLength = length;
		*opp = node;
		opp = &node->next;
		*opp = NULL;
		int tkn = scan();
		while (tkn == tkn_rpar) { 
		    if (--parentheses < 0) { 
			error("Unbalanced parentheses");
		    }
		    tkn = scan();
		}
		if (tkn == tkn_desc) { 
		    node->ascent = false;
		    tkn = scan();
		} else if (tkn == tkn_asc) { 
		    tkn = scan();
		}
		while (tkn == tkn_rpar) { 
		    if (--parentheses < 0) { 
			error("Unbalanced parentheses");
		    }
		    tkn = scan();
		}
		if (tkn == tkn_eof) { 
		    if (parentheses != 0) {
			error("Unbalanced parentheses");
		    }
		    return;
		} else if (tkn != tkn_comma) { 
		    error("',' expected");
		}
	    }
	}
    } else if (lex != tkn_eof) { 
	error("ORDER BY expected");
    }
}


dbExprNode* dbCompiler::compileExpression(dbTableDescriptor* table, char const* expr, int startPos)
{
    TRACE_MSG(("Compile expression %s for table %s\n", table->name));    
    if (setjmp(abortCompilation) == 0) { 
	this->table = table;
	bindings = NULL;
	nFreeVars = 0;
	dbQueryElement elem(dbQueryElement::qExpression, expr, NULL); 
	queryElement = &elem;
	currPos = firstPos = 0;
	offsetWithinStatement = startPos;
	return disjunction(); 
    } else {
	return NULL;
    }
}

bool dbCompiler::compile(dbTableDescriptor* table, dbQuery& query)
{
    TRACE_MSG(("Compile query for table %s\n", table->name));
    query.destroy(); 
    if (setjmp(abortCompilation) == 0) { 
	this->table = table;
	bindings = NULL;
	nFreeVars = 0;
	queryElement = query.elements;
	currPos = firstPos = 0;
	offsetWithinStatement = query.pos;
	dbExprNode* expr = disjunction(); 
	if (expr->type != tpBoolean && expr->type != tpVoid) { 
	    table->db->handleError(dbDatabase::QueryError, "Conditional "
				   "expression should have boolean type\n", 0);
	    delete expr;
	    return false;
	}
	compileStartFollowPart(query); 
	compileOrderByPart(query); 
	query.tree  = expr;
	query.table = table;
	return true;
    } else { 
	for (dbOrderByNode *op = query.order, *nop; op != NULL; op = nop) {
	    nop = op->next;
	    delete op;
	}
	for (dbFollowByNode *fp = query.follow, *nfp; fp != NULL; fp = nfp) {
	    nfp = fp->next;
	    delete fp;
	}
	return false;
    }
}

dbCompiler::dbCompiler() {
    static struct { 
	char* name;
	int   tag;
    } keywords[] = { 
	{"abs",     tkn_abs},
	{"and",     tkn_and},
	{"asc",     tkn_asc},
	{"between", tkn_between},
	{"by",      tkn_by},
	{"current", tkn_current},
	{"desc",    tkn_desc},
	{"escape",  tkn_escape},
	{"exists",  tkn_exists},
	{"first",   tkn_first},
	{"false",   tkn_false},
	{"follow",  tkn_follow},
	{"from",    tkn_from},
	{"in",      tkn_in},
	{"is",      tkn_is},
	{"integer", tkn_integer},
	{"last",    tkn_last},
	{"length",  tkn_length},
	{"like",    tkn_like},
	{"lower",   tkn_lower},
	{"not",     tkn_not},
	{"null",    tkn_null},
	{"or",      tkn_or},
	{"order",   tkn_order},
	{"real",    tkn_real},
	{"start",   tkn_start},
	{"string",  tkn_string},
	{"true",    tkn_true},
	{"upper",   tkn_upper},
	{"where",   tkn_where}
    };
    if (!initialized) { 
	for (unsigned i = 0; i < items(keywords); i++) { 
	    dbSymbolTable::add(keywords[i].name, keywords[i].tag, FASTDB_CLONE_ANY_IDENTIFIER);    
	}
	initialized = true;
    }
}

void dbInheritedAttribute::removeTemporaries()
{
    for (dbStringValue *next, *s = tempStrings; s != NULL; s = next) { 
	next = s->next;
	delete s;
    }
}

void dbTrace(char* message, ...) 
{
    va_list args;
    va_start (args, message);
    vfprintf(stderr, message, args);
    va_end(args);
}


⌨️ 快捷键说明

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