mirror of
https://github.com/tars-node/tars2node.git
synced 2024-03-22 13:10:56 +08:00
632 lines
14 KiB
C++
632 lines
14 KiB
C++
/**
|
|
* Tencent is pleased to support the open source community by making Tars available.
|
|
*
|
|
* Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
|
|
*
|
|
* Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
|
|
* in compliance with the License. You may obtain a copy of the License at
|
|
*
|
|
* https://opensource.org/licenses/BSD-3-Clause
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software distributed
|
|
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
* specific language governing permissions and limitations under the License.
|
|
*/
|
|
|
|
#include "parse.h"
|
|
#include "tars.tab.hpp"
|
|
#include <errno.h>
|
|
#include <fstream>
|
|
#include <string.h>
|
|
#include "util/tc_common.h"
|
|
#include "util/tc_file.h"
|
|
|
|
TarsParsePtr g_parse = new TarsParse();
|
|
|
|
void yyerror(char const *msg)
|
|
{
|
|
g_parse->error(msg);
|
|
}
|
|
|
|
TarsParse::TarsParse()
|
|
{
|
|
_bWithTars = false;
|
|
_bUseCurrentPath = false;
|
|
_itab = 0;
|
|
_bUseCurrentPathFirst = false;
|
|
initScanner();
|
|
}
|
|
|
|
void TarsParse::setTars(bool bWithTars)
|
|
{
|
|
_bWithTars = bWithTars;
|
|
}
|
|
|
|
void TarsParse::setHeader(const string &sHeader)
|
|
{
|
|
_sHeader = sHeader;
|
|
}
|
|
|
|
void TarsParse::setCurrentPriority(bool bFlag)
|
|
{
|
|
_bUseCurrentPathFirst = bFlag;
|
|
}
|
|
|
|
string TarsParse::getHeader()
|
|
{
|
|
if(_sHeader.empty())
|
|
return _sHeader;
|
|
return _sHeader + "/";
|
|
}
|
|
|
|
void TarsParse::clear()
|
|
{
|
|
while(!_contexts.empty()) _contexts.pop();
|
|
while(!_contains.empty()) _contains.pop();
|
|
_vcontexts.clear();
|
|
_structs.clear();
|
|
_enums.clear();
|
|
_namespaces.clear();
|
|
}
|
|
|
|
void TarsParse::parse(const string& sFileName)
|
|
{
|
|
if (_bUseCurrentPath)
|
|
{
|
|
std::string sTemp = sFileName;
|
|
bool isExist = tars::TC_File::isFileExist(sFileName);
|
|
|
|
if (!isExist)
|
|
{
|
|
sTemp = tars::TC_File::extractFileName(sFileName);
|
|
}
|
|
|
|
clear();
|
|
|
|
_contains.push(new Container(""));
|
|
if(!(yyin = fopen(sTemp.c_str(), "r")))
|
|
{
|
|
error("open file '" + sFileName + "(" + sTemp + ")" + "' error :" + string(strerror(errno)));
|
|
}
|
|
|
|
pushFile(sFileName);
|
|
|
|
yyparse();
|
|
|
|
return ;
|
|
}
|
|
|
|
if (_bUseCurrentPathFirst)
|
|
{
|
|
std::string sTemp = tars::TC_File::extractFileName(sFileName);
|
|
bool isExist = tars::TC_File::isFileExist(sTemp);
|
|
|
|
if (!isExist)
|
|
{
|
|
sTemp = sFileName;
|
|
}
|
|
|
|
clear();
|
|
|
|
_contains.push(new Container(""));
|
|
if(!(yyin = fopen(sTemp.c_str(), "r")))
|
|
{
|
|
error("open file '" + sFileName + "(" + sTemp + ")" + "' error :" + string(strerror(errno)));
|
|
}
|
|
|
|
pushFile(sFileName);
|
|
|
|
yyparse();
|
|
|
|
return ;
|
|
}
|
|
|
|
{
|
|
clear();
|
|
|
|
_contains.push(new Container(""));
|
|
if(!(yyin = fopen(sFileName.c_str(), "r")))
|
|
{
|
|
error("open file '" + sFileName + "' error :" + string(strerror(errno)));
|
|
}
|
|
|
|
pushFile(sFileName);
|
|
|
|
yyparse();
|
|
}
|
|
}
|
|
|
|
void TarsParse::pushFile(const string &file)
|
|
{
|
|
ContextPtr c = new Context(file);
|
|
_contexts.push(c);
|
|
_vcontexts.push_back(c);
|
|
}
|
|
|
|
ContextPtr TarsParse::popFile()
|
|
{
|
|
ContextPtr c = _contexts.top();
|
|
_contexts.pop();
|
|
return c;
|
|
}
|
|
|
|
bool TarsParse::getFilePath(const string &s, string &file)
|
|
{
|
|
if (_bUseCurrentPath)
|
|
{
|
|
if(s.length() < 2 || s[0] != '\"' || s[s.length()-1] != '\"')
|
|
{
|
|
error("#include need \"FILENAME\"");
|
|
}
|
|
|
|
file = s.substr(1, s.length() - 2);
|
|
|
|
std::string sTemp = file;
|
|
bool isExist = tars::TC_File::isFileExist(file);
|
|
|
|
if (!isExist)
|
|
{
|
|
file = tars::TC_File::extractFileName(file);
|
|
}
|
|
|
|
for(size_t i = 0; i < _vcontexts.size(); i++)
|
|
{
|
|
if(_vcontexts[i]->getFileName() == file)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
if(_bUseCurrentPathFirst)
|
|
{
|
|
if(s.length() < 2 || s[0] != '\"' || s[s.length()-1] != '\"')
|
|
{
|
|
error("#include need \"FILENAME\"");
|
|
}
|
|
|
|
file = s.substr(1, s.length() - 2);
|
|
|
|
std::string sTemp = tars::TC_File::extractFileName(file);
|
|
bool isExist = tars::TC_File::isFileExist(sTemp);
|
|
|
|
if (isExist)
|
|
{
|
|
file = sTemp;
|
|
}
|
|
|
|
for(size_t i = 0; i < _vcontexts.size(); i++)
|
|
{
|
|
if(_vcontexts[i]->getFileName() == file)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
if(s.length() < 2 || s[0] != '\"' || s[s.length()-1] != '\"')
|
|
{
|
|
error("#include need \"FILENAME\"");
|
|
}
|
|
|
|
file = s.substr(1, s.length() - 2);
|
|
|
|
if (!tars::TC_File::isFileExist(file))
|
|
{
|
|
for (size_t i = 0; i < _vIncludePath.size(); i++)
|
|
{
|
|
if (tars::TC_File::isFileExist(_vIncludePath[i] + "/" + file))
|
|
{
|
|
file = _vIncludePath[i] + "/" + file;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
for(size_t i = 0; i < _vcontexts.size(); i++)
|
|
{
|
|
if(_vcontexts[i]->getFileName() == file)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
string TarsParse::getCurrFileName()
|
|
{
|
|
return _contexts.top()->getFileName();
|
|
}
|
|
|
|
void TarsParse::nextLine()
|
|
{
|
|
_contexts.top()->nextLine();
|
|
}
|
|
|
|
ContextPtr TarsParse::currentContextPtr()
|
|
{
|
|
return _contexts.top();
|
|
}
|
|
|
|
void TarsParse::error(const string &msg)
|
|
{
|
|
cerr << _contexts.top()->getFileName() << ": " << _contexts.top()->getCurrLine() << ": error: " << msg << endl;
|
|
exit(-1);
|
|
}
|
|
|
|
int TarsParse::checkKeyword(const string& s)
|
|
{
|
|
std::map<std::string, int>::const_iterator it = _keywordMap.find(s);
|
|
if(it != _keywordMap.end())
|
|
{
|
|
return it->second;
|
|
}
|
|
|
|
if(!_bWithTars)
|
|
{
|
|
string sPrefix = "tars";
|
|
//不能以tars开头
|
|
if((s.length() >= sPrefix.length()) && (s.substr(0, sPrefix.length()) == sPrefix))
|
|
{
|
|
error("identifier can't start with 'tars'");
|
|
}
|
|
}
|
|
|
|
return TARS_IDENTIFIER;
|
|
}
|
|
|
|
void TarsParse::initScanner()
|
|
{
|
|
_keywordMap["void"] = TARS_VOID;
|
|
_keywordMap["struct"] = TARS_STRUCT;
|
|
_keywordMap["bool"] = TARS_BOOL;
|
|
_keywordMap["byte"] = TARS_BYTE;
|
|
_keywordMap["short"] = TARS_SHORT;
|
|
_keywordMap["int"] = TARS_INT;
|
|
_keywordMap["double"] = TARS_DOUBLE;
|
|
_keywordMap["float"] = TARS_FLOAT;
|
|
_keywordMap["long"] = TARS_LONG;
|
|
_keywordMap["string"] = TARS_STRING;
|
|
_keywordMap["vector"] = TARS_VECTOR;
|
|
_keywordMap["map"] = TARS_MAP;
|
|
_keywordMap["key"] = TARS_KEY;
|
|
_keywordMap["routekey"] = TARS_ROUTE_KEY;
|
|
_keywordMap["module"] = TARS_NAMESPACE;
|
|
_keywordMap["interface"]= TARS_INTERFACE;
|
|
_keywordMap["out"] = TARS_OUT;
|
|
_keywordMap["require"] = TARS_REQUIRE;
|
|
_keywordMap["optional"] = TARS_OPTIONAL;
|
|
_keywordMap["false"] = TARS_FALSE;
|
|
_keywordMap["true"] = TARS_TRUE;
|
|
_keywordMap["enum"] = TARS_ENUM;
|
|
_keywordMap["const"] = TARS_CONST;
|
|
_keywordMap["unsigned"] = TARS_UNSIGNED;
|
|
}
|
|
|
|
string TarsParse::getTab()
|
|
{
|
|
ostringstream s;
|
|
for(int i = 0; i < _itab; i++)
|
|
{
|
|
s << " ";
|
|
}
|
|
|
|
return s.str();
|
|
}
|
|
|
|
BuiltinPtr TarsParse::createBuiltin(Builtin::Kind kind,bool isUnsigned)
|
|
{
|
|
return new Builtin(kind,isUnsigned);
|
|
}
|
|
|
|
VectorPtr TarsParse::createVector(const TypePtr &ptr)
|
|
{
|
|
return new Vector(ptr);
|
|
}
|
|
|
|
MapPtr TarsParse::createMap(const TypePtr &pleft, const TypePtr &pright)
|
|
{
|
|
return new Map(pleft, pright);
|
|
}
|
|
|
|
void TarsParse::addNamespacePtr(const NamespacePtr &nPtr)
|
|
{
|
|
_namespaces.push_back(nPtr);
|
|
}
|
|
|
|
NamespacePtr TarsParse::findNamespace(const string &id)
|
|
{
|
|
for(size_t i = 0; i < _namespaces.size(); i++)
|
|
{
|
|
if(_namespaces[i]->getId() == id)
|
|
{
|
|
return _namespaces[i];
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
NamespacePtr TarsParse::currentNamespace()
|
|
{
|
|
return _namespaces.back();
|
|
}
|
|
|
|
void TarsParse::addStructPtr(const StructPtr &sPtr)
|
|
{
|
|
_structs.push_back(sPtr);
|
|
}
|
|
|
|
void TarsParse::addEnumPtr(const EnumPtr &ePtr)
|
|
{
|
|
_enums.push_back(ePtr);
|
|
}
|
|
|
|
StructPtr TarsParse::findStruct(const string &sid)
|
|
{
|
|
string ssid = sid;
|
|
|
|
//在当前namespace中查找
|
|
NamespacePtr np = currentNamespace();
|
|
if(ssid.find("::") == string::npos)
|
|
{
|
|
ssid = np->getId() + "::" + ssid;
|
|
}
|
|
|
|
for(size_t i = 0; i < _structs.size(); i++)
|
|
{
|
|
if(_structs[i]->getSid() == ssid)
|
|
{
|
|
return _structs[i];
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
EnumPtr TarsParse::findEnum(const string &sid)
|
|
{
|
|
string ssid = sid;
|
|
|
|
//在当前namespace中查找
|
|
NamespacePtr np = currentNamespace();
|
|
if(ssid.find("::") == string::npos)
|
|
{
|
|
ssid = np->getId() + "::" + sid;
|
|
}
|
|
|
|
for(size_t i = 0; i < _enums.size(); i++)
|
|
{
|
|
if(_enums[i]->getSid() == ssid)
|
|
{
|
|
return _enums[i];
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
bool TarsParse::checkEnum(const string &idName)
|
|
{
|
|
for(size_t i = 0; i < _enums.size(); i++)
|
|
{
|
|
vector<TypeIdPtr> & list = _enums[i]->getAllMemberPtr();
|
|
|
|
for (size_t j = 0; j < list.size(); j++)
|
|
{
|
|
if (list[j]->getId() == idName)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
void TarsParse::checkConflict(const string &sid)
|
|
{
|
|
//是否和枚举重名
|
|
if(findEnum(sid))
|
|
{
|
|
error("conflicts with enum '" + sid + "'");
|
|
}
|
|
|
|
//是否和结构重名
|
|
if(findStruct(sid))
|
|
{
|
|
error("conflicts with struct '" + sid + "'");
|
|
}
|
|
}
|
|
|
|
TypePtr TarsParse::findUserType(const string &sid)
|
|
{
|
|
StructPtr sPtr = findStruct(sid);
|
|
if(sPtr) return sPtr;
|
|
|
|
EnumPtr ePtr = findEnum(sid);
|
|
if(ePtr) return ePtr;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
ContainerPtr TarsParse::currentContainer()
|
|
{
|
|
return _contains.top();
|
|
}
|
|
|
|
void TarsParse::pushContainer(const ContainerPtr &c)
|
|
{
|
|
_contains.push(c);
|
|
NamespacePtr np = NamespacePtr::dynamicCast(c);
|
|
if(np)
|
|
{
|
|
addNamespacePtr(np);
|
|
}
|
|
}
|
|
|
|
ContainerPtr TarsParse::popContainer()
|
|
{
|
|
ContainerPtr c = _contains.top();
|
|
_contains.pop();
|
|
|
|
return c;
|
|
}
|
|
|
|
void TarsParse::checkTag(int i)
|
|
{
|
|
if(i >= 256)
|
|
{
|
|
error("struct memeber tag can't beyond 256");
|
|
}
|
|
if(i < 0)
|
|
{
|
|
error("struct memeber tag can't less then 0");
|
|
}
|
|
}
|
|
|
|
void TarsParse::checkSize(int i)
|
|
{
|
|
if(i >= 1024*1024)
|
|
{
|
|
error("struct memeber size can't beyond 1M");
|
|
}
|
|
if(i < 1)
|
|
{
|
|
error("struct memeber size can't less than 1");
|
|
}
|
|
}
|
|
|
|
void TarsParse::checkArrayVaid(TypePtr &tPtr,int size)
|
|
{
|
|
checkSize(size);
|
|
//只有string/vector可以为array类型
|
|
//vector不可以嵌套array类型 例如不允许vector<string:8>:2;
|
|
|
|
VectorPtr vPtr = VectorPtr::dynamicCast(tPtr);
|
|
if(vPtr )
|
|
{
|
|
if(vPtr->getTypePtr()->isArray())
|
|
{
|
|
error("fixed array type can not be nested");
|
|
}
|
|
return;
|
|
}
|
|
BuiltinPtr bPtr = BuiltinPtr::dynamicCast(tPtr);
|
|
if(bPtr && bPtr->kind()== Builtin::KindString)
|
|
{
|
|
return;
|
|
}
|
|
error("only string or vector can use fix array");
|
|
}
|
|
|
|
void TarsParse::checkPointerVaid(TypePtr &tPtr)
|
|
{
|
|
//必须为vector<Byte>类型
|
|
|
|
VectorPtr vPtr = VectorPtr::dynamicCast(tPtr);
|
|
if(vPtr)
|
|
{
|
|
BuiltinPtr bPtr = BuiltinPtr::dynamicCast(vPtr->getTypePtr());
|
|
if( bPtr && bPtr->kind()== Builtin::KindByte)
|
|
return;
|
|
}
|
|
error("only 'byte *' can be pointer type");
|
|
}
|
|
|
|
void TarsParse::checkConstValue(TypeIdPtr &tPtr, int c)
|
|
{
|
|
//只有内建类型才能有缺省值
|
|
BuiltinPtr bPtr = BuiltinPtr::dynamicCast(tPtr->getTypePtr());
|
|
EnumPtr ePtr = EnumPtr::dynamicCast(tPtr->getTypePtr());
|
|
if(!bPtr && !ePtr)
|
|
{
|
|
error("only base/enum type can have default value");
|
|
}
|
|
|
|
if (ePtr)
|
|
{
|
|
if (c != ConstGrammar::VALUE && c != ConstGrammar::ENUM)
|
|
{
|
|
error("default value of enum only be int or enum_type");
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
int b = bPtr->kind();
|
|
|
|
if(c == ConstGrammar::VALUE)
|
|
{
|
|
if(b == Builtin::KindBool)
|
|
{
|
|
error("default value of bool can only be true or false");
|
|
}
|
|
if(b == Builtin::KindString)
|
|
{
|
|
error("default value of string can only be \"string\"");
|
|
}
|
|
}
|
|
else if(c == ConstGrammar::BOOL)
|
|
{
|
|
if(b != Builtin::KindBool)
|
|
{
|
|
error("only bool type can be true or false");
|
|
}
|
|
}
|
|
else if(c == ConstGrammar::STRING)
|
|
{
|
|
if(b != Builtin::KindString)
|
|
{
|
|
error("only string type can be \"string\"");
|
|
}
|
|
}
|
|
}
|
|
|
|
string TarsParse::printHeaderRemark()
|
|
{
|
|
ostringstream s;
|
|
s << "// **********************************************************************" << endl;
|
|
s << "// This file was generated by a TARS parser!" << endl;
|
|
s << "// TARS version " << TARS_VERSION << "." << endl;
|
|
s << "// **********************************************************************" << endl;
|
|
s << endl;
|
|
|
|
return s.str();
|
|
}
|
|
|
|
string TarsParse::getFileName(const string &fileName)
|
|
{
|
|
string tmpFileName = fileName;
|
|
string::size_type pos = tmpFileName.rfind('/');
|
|
if(pos != string::npos)
|
|
{
|
|
tmpFileName = tmpFileName.substr(pos + 1);
|
|
}
|
|
else
|
|
{
|
|
pos = tmpFileName.rfind('\\');
|
|
if(pos != string::npos)
|
|
{
|
|
tmpFileName = tmpFileName.substr(pos + 1);
|
|
}
|
|
}
|
|
|
|
return tars::TC_File::excludeFileExt(tmpFileName);
|
|
}
|
|
|
|
string TarsParse::replaceFileName(const string &fileName, const string &ext)
|
|
{
|
|
return tars::TC_File::excludeFileExt(getFileName(fileName)) + "." + ext;
|
|
}
|
|
|
|
string TarsParse::getAbsoluteFileName(const string &baseDir, const string &fileName)
|
|
{
|
|
return baseDir + FILE_SEP + fileName;
|
|
}
|