bool SqlParser::parseSimpleTableNameAndAlias(int start, int end, StringVector &tableNames, StringVector &aliases) const { if (end - start == 1) { if (getTokenId(start) == TK_LITERAL) { tableNames.push_back(getTokenStr(start)); aliases.push_back(""); return true; } } else if (end - start == 2) { if (getTokenId(start) == TK_LITERAL && getTokenId(start + 1) == TK_LITERAL) { tableNames.push_back(getTokenStr(start)); aliases.push_back(getTokenStr(start + 1)); return true; } } else if (end - start == 3 && getTokenId(start + 1) == TK_SQL_AS) { if (getTokenId(start) == TK_LITERAL && getTokenId(start + 2) == TK_LITERAL) { tableNames.push_back(getTokenStr(start)); aliases.push_back(getTokenStr(start + 2)); return true; } } return false; }
bool SqlParser::setDefaultLimit() { static const char *defaultLimit = NULL; if (defaultLimit == NULL) { defaultLimit = get_config_string("DEFAULT_SELECT_LIMIT"); if (defaultLimit == NULL) defaultLimit = "500"; } int limitPos; if (!findToken(1, getTokensLen(), TK_SQL_LIMIT, &limitPos)) { g_string_append(inputSql, " LIMIT "); g_string_append(inputSql, defaultLimit); network_mysqld_proto_set_header_len((unsigned char *) (inputSql->str), inputSql->len - NET_HEADER_SIZE); return true; } if (limitPos + 3 > getTokensLen() - 1) // no offset return true; if (limitPos + 3 < getTokensLen() - 1) { printTokens("only queries with LIMIT at the last field is supported now!"); return false; } int offset, rowCount; if (getTokenId(limitPos + 2) == TK_COMMA) { offset = atoi(getTokenStr(limitPos + 1).c_str()); rowCount = atoi(getTokenStr(limitPos + 3).c_str()); } else if (getTokenId(limitPos + 2) == TK_SQL_OFFSET) { offset = atoi(getTokenStr(limitPos + 3).c_str()); rowCount = atoi(getTokenStr(limitPos + 1).c_str()); } else { printTokens("Unrecognized LIMIT OFFSET format:"); return false; } // TODO: the tokenizer needs to have the field offset info // for now, we search LIMIT from the end char *p = inputSql->str + inputSql->len - 1; while (toupper(*p) != 'L') p--; // remove the old LIMIT OFFSET info // g_string_truncate(inputSql, p - inputSql->str); // add new LIMIT OFFSET info char buff[128]; snprintf(buff, sizeof (buff), "LIMIT %d", offset + rowCount); g_string_append(inputSql, buff); network_mysqld_proto_set_header_len((unsigned char *) (inputSql->str), inputSql->len - NET_HEADER_SIZE); return true; }
bool outputProductsTree(const char fileName[]) { int curIndent=0,curPro; Token tk; initReadOneToken(); string tmpStr=""; std::vector<Symbol> symvct; std::vector<int> symIndentVct; symvct.push_back(Symbol::Program); symIndentVct.push_back(curIndent); FILE * fn=fopen(fileName,"w"); if(!fn) return false; for(int pseq=0;pseq<productsSequence.size();) { if(isTerminalSymbol(symvct.back())) { if(!ReadOneToken(tk)) printf("something is wrong when get new token."); tmpStr=_getBlankStr_(symIndentVct.back())+getTokenStr(tk.type)+" "+tk.name; fprintf(fn,"%s\n",tmpStr.c_str()); symvct.pop_back(); symIndentVct.pop_back(); } else { curIndent=symIndentVct.back(); tmpStr=_getBlankStr_(curIndent)+getTokenStr(symvct.back()); fprintf(fn,"%s\n",tmpStr.c_str()); curIndent+=2; curPro=productsSequence[pseq++]; //printf("%d ",curPro); symIndentVct.pop_back(); symvct.pop_back(); for(int i=(products[curPro].size())-1;i>0;i--) if(products[curPro][i]!=Symbol::LAMBDA) { symvct.push_back(products[curPro][i]); symIndentVct.push_back(curIndent); } else { tmpStr=_getBlankStr_(curIndent)+"LAMBDA"; fprintf(fn,"%s\n",tmpStr.c_str()); } } } fclose(fn); initReadOneToken(); return true; }
void pushProduct(int num)/**将产生式右部入栈**/ { productsSequence.push_back(num); for(int i=int(products[num].size())-1; i>0; i--) if(products[num][i]!=Symbol::LAMBDA)///lambda 不用入符号栈 symbolStack.push_back(products[num][i]); #ifdef LL1OUTPUTPRODUCT /**输出调试信息**/ printf(": %-3d ",num); for(Symbol tmp:products[num]) printf("%-8s ",getTokenStr(tmp).c_str()); puts(""); #endif // LL1OUTPUTPRODUCT #ifdef LL1OUTSYMBOLSTACK /**输出调试信息**/ puts("Rest Symbol in Stack is:"); for(Symbol tmp:symbolStack) printf("%-8s ",getTokenStr(tmp).c_str()); puts(""); #endif // LL1OUTSYMBOLSTACK }
void SqlParser::printTokens(const char *str) const { std::string msg(str ? str : ""); if (inputSql) { msg.append("\""); msg.append(inputSql->str + NET_HEADER_SIZE + 1, inputSql->len - NET_HEADER_SIZE - 1); msg.append("\"."); } log_warning(msg.c_str()); for (size_t i = 0; i < tokens->len; i++) { log_debug("SQL Tokens: %2d %20s: \"%s\"\n", i, sql_token_get_name(getTokenId(i)), getTokenStr(i).c_str()); } }
db_lookup_retval_t SqlParser::parseSql(std::set<std::string> &dbs, int *txLevel, bool parseMaster) { dbs.clear(); StringVector tables, aliases; if (getTokensLen() <= 0) { log_warning("empty sql for dababase lookup!\n"); return RET_ERROR_UNPARSABLE; } switch (getTokenId(0)) { case TK_SQL_SELECT: { int usemaster = 0; if (parseMaster) usemaster = 1; // special handling for our get unique id function call. if (getTokensLen() > 1 && getTokenStr(1) == "get_next_id") return RET_USE_DEFAULT_DATABASE; int fromStart, fromEnd; if (!getSqlFrom(0, &fromStart, &fromEnd)) { if ((getTokensLen() > 3 && getTokenId(1) == TK_LITERAL && getTokenId(2) == TK_OBRACE) || (getTokensLen() == 2 && getTokenId(1) == TK_LITERAL)) { // for special stored procedures return RET_USE_ALL_PARTITIONS; } printTokens("no FROM found, using default db: "); return RET_USE_DEFAULT_DATABASE; } if (!parseTableNameAndAlias(fromStart, fromEnd, tables, aliases)) { printTokens("could not parse table alias, using default db: "); return RET_USE_DEFAULT_DATABASE; } // for non-partitioned tables, we can use any db // since each db should have a view of it bool partitioned = false; for (size_t i = 0; i < tables.size(); i++) { if (dbPart->isPartitionedTable(tables[i])) { partitioned = true; break; } } if (!setDefaultLimit()) { printTokens("error in modifying LIMIT: "); return RET_ERROR_UNPARSABLE; } /* if (!partitioned) return ((*txLevel) > 0 ? RET_USE_DEFAULT_DATABASE : RET_USE_ANY_PARTITION); */ int whereStart, whereEnd; if (!getSqlWhere(fromEnd, &whereStart, &whereEnd)) { // add LIMIT, change the offset to 0 if needed uint64_t aa = 0; dbPart->getPartitionNum(tables[0], &aa); for (size_t i = 0; i < aa; i++) { std::string db; getDbMapping(tables[0], "", i, db, usemaster, 0); if (!db.empty()) dbs.insert(db); } return RET_USE_ALL_PARTITIONS; } for (size_t i = 0; i < tables.size(); i++) { std::string partitionKey; getPartitionKey(tables[i], partitionKey); if (partitionKey.empty()) { std::string db; getDbMapping(tables[i], "", 0, db, usemaster, 0); if (!db.empty()) dbs.insert(db); continue; } std::vector<uint64_t> keyValues; if (!findPartitionKeyValue(whereStart, whereEnd, tables[i], aliases[i], partitionKey, keyValues)) { printTokens("unrecognized key ranges: "); return RET_ERROR_UNPARSABLE; } if (keyValues.size() == 0) { uint64_t aa = 0; dbPart->getPartitionNum(tables[0], &aa); for (size_t i = 0; i < aa; i++) { std::string db; getDbMapping(tables[0], "", i, db, usemaster, 0); if (!db.empty()) dbs.insert(db); } return RET_USE_ALL_PARTITIONS; } // find the db partition for all the IDs for (size_t k = 0; k < keyValues.size(); k++) { std::string db; getDbMapping(tables[i], partitionKey, keyValues[k], db, usemaster, 0); if (!db.empty()) dbs.insert(db); } } if (dbs.empty()) return RET_USE_ALL_PARTITIONS; return RET_DB_LOOKUP_SUCCESS; } case TK_SQL_UPDATE: { int setPos; if (!findToken(0, getTokensLen(), TK_SQL_SET, &setPos)) { printTokens("could not find SET in UPDATE: "); return RET_ERROR_UNPARSABLE; }; if (getTokenId(setPos - 1) != TK_LITERAL) { printTokens("expecting table name before SET: "); return RET_ERROR_UNPARSABLE; } std::string table = getTokenStr(setPos - 1); // for nonpartitioned tables, update the default master db if (!(dbPart->isPartitionedTable(table))) { std::string db; getDbMapping(table, "", 0, db, 1, 0); if (!db.empty()) dbs.insert(db); return RET_USE_ALL_PARTITIONS; } int whereStart, whereEnd; if (!getSqlWhere(setPos + 1, &whereStart, &whereEnd)) { printTokens("no WHERE found: "); return RET_ERROR_UNPARSABLE; } std::string partitionKey; getPartitionKey(table, partitionKey); g_assert(!partitionKey.empty()); std::vector<uint64_t> keyValues; if (!findPartitionKeyValue(whereStart, whereEnd, table, "", partitionKey, keyValues)) { printTokens("unrecognized ranges: "); return RET_ERROR_UNPARSABLE; } // find the db partition for all the IDs for (size_t k = 0; k < keyValues.size(); k++) { std::string db; getDbMapping(table, partitionKey, keyValues[k], db, 1, 0); if (!db.empty()) dbs.insert(db); } if (dbs.empty()) return RET_USE_ALL_PARTITIONS; return RET_DB_LOOKUP_SUCCESS; } case TK_SQL_INSERT: { // support format: INSERT ... <table> (...) VALUES (....) int pos; uint64_t insertid = 0; if (!findToken(1, getTokensLen(), TK_LITERAL, &pos)) { printTokens("could not find table name: "); return RET_ERROR_UNPARSABLE; } std::string table = getTokenStr(pos); std::string partitionKey; getPartitionKey(table, partitionKey); if (getTokenId(++pos) != TK_OBRACE) { printTokens("unrecognized INSERT: "); return RET_ERROR_UNPARSABLE; } pos++; std::string autoIncrementColumn; dbPart->getAutoIncrementColumn(table, autoIncrementColumn); int keyPos = -1; int autoColPos = -1; for (int i = pos; i < getTokensLen(); i++) { if ((getTokenId(i) == TK_CBRACE) || (autoColPos >= 0 && keyPos >= 0)) break; if (getTokenId(i) == TK_LITERAL && tokComp(i, partitionKey) == 0) { keyPos = i - pos; continue; } if (getTokenId(i) == TK_LITERAL && tokComp(i, autoIncrementColumn) == 0) { autoColPos = i - pos; } } if ((!partitionKey.empty()) && keyPos == -1 && partitionKey != autoIncrementColumn) { log_warning("could not find the partition key %s:", partitionKey.c_str()); printTokens(); return RET_ERROR_UNPARSABLE; } if ((!partitionKey.empty()) && keyPos == -1) { // special handling for the case in which partition key type is auto increment. // need to get the id first and then modify the INSERT uint64_t id; if (!dbPart->getNextUniqueId(table, &id)) { log_warning("could not get next unique id for %s", partitionKey.c_str()); printTokens(); return RET_DB_LOOKUP_ERROR; } insertid = id; std::string db; getDbMapping(table, partitionKey, id, db, 1, id); if (!db.empty()) dbs.insert(db); else { printTokens("could not find db for id %d: "); return RET_DB_LOOKUP_ERROR; } if (modifySqlForInsert(partitionKey, id)) { if (partitionKey == autoIncrementColumn || autoIncrementColumn.empty()) return RET_DB_LOOKUP_SUCCESS; } else { log_warning("could not insert id for %s ", partitionKey.c_str()); printTokens(); return RET_DB_LOOKUP_ERROR; } } if (!autoIncrementColumn.empty() && autoColPos < 0 && (partitionKey != autoIncrementColumn)) { // need to get unique ids for auto increment columns uint64_t id; if (!dbPart->getNextUniqueId(table, &id)) { log_warning("could not get next unique id for %s", autoIncrementColumn.c_str()); printTokens(); return RET_DB_LOOKUP_ERROR; } insertid = id; if (modifySqlForInsert(autoIncrementColumn, id)) { // for nonparitioned table INSERT, use the default master db if (partitionKey.empty()) return RET_USE_DEFAULT_DATABASE; if (keyPos == -1) return RET_DB_LOOKUP_SUCCESS; } else { log_warning("could not insert id for %s ", autoIncrementColumn.c_str()); printTokens(); return RET_DB_LOOKUP_ERROR; } } // for nonparitioned table INSERT, use the default master db if (partitionKey.empty()) { std::string db; getDbMapping(table, "", 0, db, 1, insertid); if (!db.empty()) dbs.insert(db); return RET_USE_ALL_PARTITIONS; } pos += keyPos; int valPos; if (!findToken(pos, getTokensLen(), TK_SQL_VALUES, &valPos)) { printTokens("VALUES is not found: "); return RET_ERROR_UNPARSABLE; } if (getTokenId(valPos + 1) != TK_OBRACE) { printTokens("expecting '(' after VALUES: "); return RET_ERROR_UNPARSABLE; } pos = valPos + 2 + keyPos; if (pos < getTokensLen()) {//dqm //if (pos < getTokensLen() && getTokenId(pos) == TK_INTEGER) { uint64_t id = tokenToUint64(pos); std::string db; getDbMapping(table, partitionKey, id, db, 1, insertid); if (!db.empty()) dbs.insert(db); if (dbs.empty()) { printTokens("could not find db mapping: "); return RET_ERROR_UNPARSABLE; } return RET_DB_LOOKUP_SUCCESS; } else { log_warning("could not recognize value for %s:", partitionKey.c_str()); printTokens(); return RET_ERROR_UNPARSABLE; } break; } case TK_SQL_REPLACE: { // support format: replace ... <table> (...) VALUES (....) int pos; uint64_t insertid = 0; if (!findToken(1, getTokensLen(), TK_LITERAL, &pos)) { printTokens("could not find table name: "); return RET_ERROR_UNPARSABLE; } std::string table = getTokenStr(pos); std::string partitionKey; getPartitionKey(table, partitionKey); if (getTokenId(++pos) != TK_OBRACE) { printTokens("unrecognized INSERT: "); return RET_ERROR_UNPARSABLE; } pos++; std::string autoIncrementColumn; dbPart->getAutoIncrementColumn(table, autoIncrementColumn); int keyPos = -1; int autoColPos = -1; for (int i = pos; i < getTokensLen(); i++) { if ((getTokenId(i) == TK_CBRACE) || (autoColPos >= 0 && keyPos >= 0)) break; if (getTokenId(i) == TK_LITERAL && tokComp(i, partitionKey) == 0) { keyPos = i - pos; continue; } if (getTokenId(i) == TK_LITERAL && tokComp(i, autoIncrementColumn) == 0) { autoColPos = i - pos; } } if ((!partitionKey.empty()) && keyPos == -1 && partitionKey != autoIncrementColumn) { log_warning("could not find the partition key %s:", partitionKey.c_str()); printTokens(); return RET_ERROR_UNPARSABLE; } if ((!partitionKey.empty()) && keyPos == -1) { // special handling for the case in which partition key type is auto increment. // need to get the id first and then modify the INSERT uint64_t id; if (!dbPart->getNextUniqueId(table, &id)) { log_warning("could not get next unique id for %s", partitionKey.c_str()); printTokens(); return RET_DB_LOOKUP_ERROR; } insertid = id; std::string db; getDbMapping(table, partitionKey, id, db, 1, id); if (!db.empty()) dbs.insert(db); else { printTokens("could not find db for id %d: "); return RET_DB_LOOKUP_ERROR; } if (modifySqlForInsert(partitionKey, id)) { if (partitionKey == autoIncrementColumn || autoIncrementColumn.empty()) return RET_DB_LOOKUP_SUCCESS; } else { log_warning("could not insert id for %s ", partitionKey.c_str()); printTokens(); return RET_DB_LOOKUP_ERROR; } } if (!autoIncrementColumn.empty() && autoColPos < 0 && (partitionKey != autoIncrementColumn)) { // need to get unique ids for auto increment columns uint64_t id; if (!dbPart->getNextUniqueId(table, &id)) { log_warning("could not get next unique id for %s", autoIncrementColumn.c_str()); printTokens(); return RET_DB_LOOKUP_ERROR; } insertid = id; if (modifySqlForInsert(autoIncrementColumn, id)) { // for nonparitioned table INSERT, use the default master db if (partitionKey.empty()) return RET_USE_DEFAULT_DATABASE; if (keyPos == -1) return RET_DB_LOOKUP_SUCCESS; } else { log_warning("could not insert id for %s ", autoIncrementColumn.c_str()); printTokens(); return RET_DB_LOOKUP_ERROR; } } // for nonparitioned table INSERT, use the default master db if (partitionKey.empty()) { std::string db; getDbMapping(table, "", 0, db, 1, insertid); if (!db.empty()) dbs.insert(db); return RET_USE_ALL_PARTITIONS; } pos += keyPos; int valPos; if (!findToken(pos, getTokensLen(), TK_SQL_VALUES, &valPos)) { printTokens("VALUES is not found: "); return RET_ERROR_UNPARSABLE; } if (getTokenId(valPos + 1) != TK_OBRACE) { printTokens("expecting '(' after VALUES: "); return RET_ERROR_UNPARSABLE; } pos = valPos + 2 + keyPos; if (pos < getTokensLen()) {//dqm //if (pos < getTokensLen() && getTokenId(pos) == TK_INTEGER) { uint64_t id = tokenToUint64(pos); std::string db; getDbMapping(table, partitionKey, id, db, 1, insertid); if (!db.empty()) dbs.insert(db); if (dbs.empty()) { printTokens("could not find db mapping: "); return RET_ERROR_UNPARSABLE; } return RET_DB_LOOKUP_SUCCESS; } else { log_warning("could not recognize value for %s:", partitionKey.c_str()); printTokens(); return RET_ERROR_UNPARSABLE; } break; } case TK_SQL_ALTER: { std::string tableName; if (getTokensLen() >= 3 && getTokenId(1) == TK_SQL_TABLE) { tableName = getTokenStr(2); } else if (getTokensLen() >= 4 && getTokenId(1) == TK_SQL_IGNORE && getTokenId(2) == TK_SQL_TABLE) { tableName = getTokenStr(3); } else break; if (dbPart->isPartitionedTable(tableName)) return RET_USE_ALL_PARTITIONS; else return RET_USE_DEFAULT_DATABASE; } case TK_SQL_CALL: { return RET_USE_ALL_PARTITIONS; } case TK_SQL_SHOW: { if (getTokensLen() == 4 && getTokenId(2) == TK_SQL_FROM && strcasecmp(getTokenStr(1).c_str(), "fields") == 0) { if (dbPart->isPartitionedTable(getTokenStr(3))) { return RET_USE_ANY_PARTITION; } return RET_USE_DEFAULT_DATABASE; } if (getTokensLen() == 2 && strcasecmp(getTokenStr(1).c_str(), "tables") == 0) { //special handling for show tables; // std::string sql = "select table_name "; sql.append(" from kind_setting order by table_name"); g_string_truncate(inputSql, NET_HEADER_SIZE + 1); g_string_append_len(inputSql, sql.data(), sql.size()); network_mysqld_proto_set_header_len((unsigned char *) (inputSql->str), inputSql->len - NET_HEADER_SIZE); return RET_USE_DEFAULT_DATABASE; } else return RET_USE_DEFAULT_DATABASE; break; } case TK_SQL_DELETE: { int fromPos; if (!findToken(1, getTokensLen(), TK_SQL_FROM, &fromPos)) { printTokens("could not find FROM in DELETE: "); return RET_ERROR_UNPARSABLE; }; if (fromPos >= getTokensLen() - 1) { printTokens("could not find table name in DELETE: "); return RET_ERROR_UNPARSABLE; } std::string table = getTokenStr(fromPos + 1); // for nonpartitioned tables, update the default master db if (!(dbPart->isPartitionedTable(table))) { std::string db; getDbMapping(table, "", 0, db, 1, 0); if (!db.empty()) dbs.insert(db); return RET_USE_ALL_PARTITIONS; } int whereStart, whereEnd; if (!getSqlWhere(fromPos + 1, &whereStart, &whereEnd)) { printTokens("no WHERE found: "); return RET_ERROR_UNPARSABLE; } std::string partitionKey; getPartitionKey(table, partitionKey); g_assert(!partitionKey.empty()); std::vector<uint64_t> keyValues; if (!findPartitionKeyValue(whereStart, whereEnd, table, "", partitionKey, keyValues)) { printTokens("unrecognized ranges: "); return RET_ERROR_UNPARSABLE; } // find the db partition for all the IDs for (size_t k = 0; k < keyValues.size(); k++) { std::string db; getDbMapping(table, partitionKey, keyValues[k], db, 1, 0); if (!db.empty()) dbs.insert(db); } if (dbs.empty()) return RET_USE_ALL_PARTITIONS; return RET_DB_LOOKUP_SUCCESS; } case TK_SQL_DESC: case TK_SQL_DESCRIBE: { if (getTokensLen() >= 2) { std::string tableName = getTokenStr(1); if (dbPart->isPartitionedTable(tableName)) return RET_USE_ANY_PARTITION; else return RET_USE_DEFAULT_DATABASE; } return RET_ERROR_UNPARSABLE; } case TK_SQL_SET: { if ((getTokensLen() >= 4) && (getTokenId(1) == TK_SQL_AUTOCOMMIT) && (getTokenStr(3).compare("0") == 0)) { (*txLevel)++; } return RET_USE_ALL_DATABASES; } case TK_SQL_START: case TK_SQL_BEGIN: { (*txLevel)++; return RET_USE_ALL_DATABASES; } case TK_SQL_COMMIT: case TK_SQL_ROLLBACK: { (*txLevel)--; return RET_USE_ALL_DATABASES; } default: { break; } } printTokens("unrecognized query, using default master db: "); return RET_USE_DEFAULT_DATABASE; }
bool parserLL1()/***语法分析主函数,返回真假值表示是否出现了语法错误***/ { /***init***/ if(!isInitFuncs) { initParserLL1Funcs(); isInitFuncs=true; } deleteParserLL1Tree(); expflag=0; getExpResult2=false; getExpResult=true; savePtr=NULL; errors.clear(); CreatLL1Table(); symbolStack.clear(); operatorStack.clear(); numStack.clear(); syntaxStack.clear(); productsSequence.clear(); symbolStack.push_back(Symbol::Program); rt=new TreeNode(0,NodeKinds::ProK);///根节点 for(int i=2; i>=0; i--) syntaxStack.push_back(&(rt->son[i])); /***init***/ ReadOneToken(currentToken); while(!symbolStack.empty()) { if(isTerminalSymbol(symbolStack.back()))///终极符 { if(currentToken.type==symbolStack.back()) { symbolStack.pop_back(); #ifdef LL1CURTERMINALSYMBOL /**输出调试信息**/ printf(">>>>>> Pop Terminal Symbol %s\n",currentToken.name.c_str()); #endif // LL1CURTERMINALSYMBOL ReadOneToken(currentToken); } else { sprintf(strError,"syntax error : unexpected tokentype= '%s' name= %s found at line %d,\n\ expected Token type is %s.\n", getTokenStr(currentToken.type).c_str(),currentToken.name.c_str(), currentToken.lineNum,getTokenStr(symbolStack.back()).c_str()); insertError(strError); #ifdef LL1OUTSYMBOLSTACK /**输出调试信息**/ puts("Rest Symbol in Stack is:"); for(Symbol tmp:symbolStack) printf("%-8s ",getTokenStr(tmp).c_str()); puts(""); #endif // LL1OUTSYMBOLSTACK return false; } } else///非终极符 { int pnum=LL1Table[int(symbolStack.back())][int(currentToken.type)];///取得对应的产生式 printf("LL1 List %s %s \n",getTokenStr(symbolStack.back()).c_str(),getTokenStr(currentToken.type).c_str()); Symbol tsym=symbolStack.back(); symbolStack.pop_back(); if(!chooseFunc(pnum))///没有对应的产生式 { printf("ok shit???????????"); sprintf(strError,"syntax error : unexpected tokentype= '%s' name= %s found at line %d.\n maybe missed one of these: %s", getTokenStr(currentToken.type).c_str(),currentToken.name.c_str(), currentToken.lineNum,getPredictStr(tsym).c_str()); insertError(strError); return false; } } } if(currentToken.type!=TokenType::DOT)/***匹配结束符 . ***/ { sprintf(strError,"syntax error : unexpected token found at line %d,Expected Dot\n",currentToken.lineNum); insertError(strError); return false; } else if(!ReadOneToken(currentToken))/***有结束符 . 则读入下一个TOKEN EOF***/ { sprintf(strError,"syntax error : Token ends Before Code or File end\n"); insertError(strError); return false; } if(currentToken.type==TokenType::ENDFILE) return true; else { sprintf(strError,"syntax error : unexpected token '%s' found at line %d,Expected EOF\n" ,getTokenStr(currentToken.type).c_str(),currentToken.lineNum); insertError(strError); return false; } return errors.size()==0; }
char *staticGetTokenStr(pToken t, int useTargetLang) { static char buffer[MAX_PRINT_TOKEN_SIZE]; return getTokenStr(t, useTargetLang, buffer); }