📄 compiler.cpp
字号:
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 + -