mirror of
https://github.com/eclipse-openvehicle-api/openvehicle-api.git
synced 2026-02-05 15:18:45 +00:00
321 lines
11 KiB
C++
321 lines
11 KiB
C++
#include "environment.h"
|
|
#include "lexer.h"
|
|
#include "codepos.h"
|
|
#include "token.h"
|
|
#include "codepos.h"
|
|
#include "lexer.h"
|
|
#include <cuchar>
|
|
#include <iostream>
|
|
#include <cstdio>
|
|
#include <algorithm>
|
|
|
|
CIdlCompilerEnvironment::CIdlCompilerEnvironment()
|
|
{}
|
|
|
|
CIdlCompilerEnvironment::CIdlCompilerEnvironment(const std::vector<std::string>& rvecArgs) :
|
|
m_cmdln(static_cast<uint32_t>(CCommandLine::EParseFlags::no_assignment_character))
|
|
{
|
|
// Create a classic argument array
|
|
std::vector<const char*> vecArgPtrs;
|
|
for (const std::string& rssArg : rvecArgs)
|
|
vecArgPtrs.push_back(rssArg.c_str());
|
|
|
|
// Call the constructor
|
|
*this = CIdlCompilerEnvironment(vecArgPtrs.size(), &vecArgPtrs.front());
|
|
}
|
|
|
|
sdv::interface_t CIdlCompilerEnvironment::GetInterface(sdv::interface_id idInterface)
|
|
{
|
|
if (idInterface == sdv::GetInterfaceId<sdv::IInterfaceAccess>())
|
|
return static_cast<sdv::IInterfaceAccess*>(this);
|
|
if (idInterface == sdv::GetInterfaceId<sdv::idl::ICompilerOption>())
|
|
return static_cast<sdv::idl::ICompilerOption*>(this);
|
|
return nullptr;
|
|
}
|
|
|
|
std::filesystem::path CIdlCompilerEnvironment::GetNextFile()
|
|
{
|
|
m_iFileIndex++;
|
|
if (static_cast<size_t>(m_iFileIndex) >= m_vecFileNames.size()) return std::filesystem::path();
|
|
return m_vecFileNames[static_cast<size_t>(m_iFileIndex)];
|
|
}
|
|
|
|
void CIdlCompilerEnvironment::AddDefinition(const char* szDefinition)
|
|
{
|
|
CCodePos code(szDefinition);
|
|
SLexerDummyCallback sCallback;
|
|
CLexer lexer(&sCallback, CaseSensitiveTypeExtension());
|
|
|
|
// Read the macro name
|
|
CToken sNameToken = lexer.GetToken(code, nullptr);
|
|
if (!sNameToken || sNameToken.GetType() != ETokenType::token_identifier)
|
|
throw CCompileException(code.GetLocation(), "Definition name missing.");
|
|
|
|
// Check for the next character. If there is no space in between and the next token is a left parenthesis, there are
|
|
// parameters.
|
|
bool bHasParam = false;
|
|
std::vector<std::string> vecParams;
|
|
CToken sSymbolToken;
|
|
if (*code == '(')
|
|
{
|
|
// Get the left parenthesis as a token.
|
|
sSymbolToken = lexer.GetToken(code, nullptr);
|
|
|
|
// Parameter bracket has been provided
|
|
bHasParam = true;
|
|
if (sSymbolToken != "(")
|
|
throw CCompileException(sSymbolToken, "Invalid character for macro definition; expecting '('.");
|
|
|
|
// Read zero or more parameter
|
|
bool bDone = false;
|
|
bool bInitial = true;
|
|
while (!bDone)
|
|
{
|
|
// Check for closing bracket
|
|
sSymbolToken = lexer.GetToken(code, nullptr);
|
|
if (bInitial && sSymbolToken == ")")
|
|
bDone = true;
|
|
else if (sSymbolToken.GetType() != ETokenType::token_identifier)
|
|
throw CCompileException(sSymbolToken, "Expecting a parameter name.");
|
|
|
|
bInitial = false;
|
|
if (!bDone)
|
|
{
|
|
// The token should represent an identifier
|
|
CToken sIdentifierToken = sSymbolToken;
|
|
|
|
// Check for duplicates
|
|
if (std::find(vecParams.begin(), vecParams.end(), static_cast<std::string>(sIdentifierToken)) != vecParams.end())
|
|
throw CCompileException(sSymbolToken, "Duplicate parameter names for macro definition.");
|
|
|
|
// Add the parameter to the list
|
|
vecParams.push_back(sIdentifierToken);
|
|
|
|
// Check for a comma or a right parenthesis
|
|
sSymbolToken = lexer.GetToken(code, nullptr);
|
|
if (sSymbolToken == ")")
|
|
bDone = true;
|
|
else if (sSymbolToken != ",")
|
|
throw CCompileException(sSymbolToken, "Unexpected symbol in parameter list.");
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check for an equal sign
|
|
sSymbolToken = lexer.GetToken(code, nullptr);
|
|
std::string ssValue;
|
|
if (sSymbolToken)
|
|
{
|
|
// Expect assignment symbol
|
|
if (sSymbolToken != "=")
|
|
throw CCompileException(sSymbolToken, "Invalid format.");
|
|
ssValue = static_cast<std::string>(code.GetLocation());
|
|
} else
|
|
{
|
|
// Expect no more code
|
|
if (!code.HasEOF())
|
|
throw CCompileException(sSymbolToken, "Invalid format.");
|
|
}
|
|
|
|
// Create and store the macro structure
|
|
CMacro macro(static_cast<std::string>(sNameToken).c_str(), bHasParam ? &vecParams : nullptr, ssValue.c_str());
|
|
|
|
// Add the macro
|
|
AddDefinition(code.GetLocation(), macro);
|
|
}
|
|
|
|
void CIdlCompilerEnvironment::AddDefinition(const CToken& rtoken, const CMacro& rMacro)
|
|
{
|
|
// Check for the macro to exist already; if so and different, throw exception. If not, add to macro map.
|
|
CMacroMap::iterator itMacro = m_mapMacros.find(rMacro.GetName());
|
|
if (itMacro != m_mapMacros.end())
|
|
{
|
|
if (itMacro->second != rMacro)
|
|
throw CCompileException(rtoken, "Redefinition of macro with different content.");
|
|
} else
|
|
m_mapMacros.emplace(std::move(CMacroMap::value_type(rMacro.GetName(), rMacro)));
|
|
}
|
|
|
|
void CIdlCompilerEnvironment::RemoveDefinition(const char* szMacro)
|
|
{
|
|
if (!szMacro) return;
|
|
CMacroMap::iterator itMacro = m_mapMacros.find(szMacro);
|
|
if (itMacro != m_mapMacros.end())
|
|
m_mapMacros.erase(itMacro);
|
|
}
|
|
|
|
bool CIdlCompilerEnvironment::Defined(const char* szMacro) const
|
|
{
|
|
if (!szMacro) return false;
|
|
return m_mapMacros.find(szMacro) != m_mapMacros.end();
|
|
}
|
|
|
|
bool CIdlCompilerEnvironment::TestAndExpand(const std::string& rssIdentifier, CCodePos& rcode, bool bInMacroExpansion /*= false*/,
|
|
CUsedMacroSet& rsetPreviousExpanded /*= CUsedMacroSet()*/) const
|
|
{
|
|
if (rssIdentifier.empty()) return false;
|
|
|
|
// Which macro set to use?
|
|
CUsedMacroSet& rsetUsedMacros = rsetPreviousExpanded.empty() ? m_setMacrosUsedInExpansion : rsetPreviousExpanded;
|
|
|
|
// If the provided identifier was created as part of a previous macro expansion (bInMacroExpansion is true) or the macro is
|
|
// part of the current expansion (rsetPreviousExpanded is not empty), check whether the identifier defines a macro that was
|
|
// used in the previous expansion, which is not allowed.
|
|
// If no previous expansion took place or current expansion takes place, clear the expansion set.
|
|
if (bInMacroExpansion || !rsetPreviousExpanded.empty())
|
|
{
|
|
if (rsetUsedMacros.find(rssIdentifier) != rsetUsedMacros.end())
|
|
return false;
|
|
} else
|
|
rsetUsedMacros.clear();
|
|
|
|
// Test for the existence of a macro.
|
|
CMacroMap::const_iterator itMacro = m_mapMacros.find(rssIdentifier);
|
|
if (itMacro == m_mapMacros.end()) return false;
|
|
|
|
// Does the macro need parameters?
|
|
CToken token = rcode.GetLocation();
|
|
std::vector<std::string> vecParams;
|
|
if (itMacro->second.ExpectParameters())
|
|
{
|
|
// Peek for left parenthesis. If not available, this is not an error. Do not deal with the macro
|
|
CCodePos codeTemp(rcode);
|
|
SLexerDummyCallback sCallback;
|
|
CLexer lexer(&sCallback, CaseSensitiveTypeExtension());
|
|
if (lexer.GetToken(codeTemp, nullptr) != "(")
|
|
return false;
|
|
|
|
// Get the parenthesis once more.
|
|
lexer.GetToken(rcode, nullptr);
|
|
|
|
std::string ssParam;
|
|
CToken locationParam = rcode.GetLocation();
|
|
auto fnTrimCheckAndAdd = [&]()
|
|
{
|
|
// Erase the whitespace from the beginning of the string
|
|
std::string::iterator itStart = std::find_if(ssParam.begin(), ssParam.end(),
|
|
[](char c)
|
|
{ return !std::isspace<char>(c, std::locale::classic()); });
|
|
ssParam.erase(ssParam.begin(), itStart);
|
|
|
|
// Ersase the whitespace form the end of the string
|
|
std::string::reverse_iterator itEnd = std::find_if(ssParam.rbegin(), ssParam.rend(),
|
|
[](char c)
|
|
{ return !std::isspace<char>(c, std::locale::classic()); });
|
|
ssParam.erase(itEnd.base(), ssParam.end());
|
|
|
|
// Check for a non-empty string
|
|
if (ssParam.empty())
|
|
throw CCompileException(locationParam, "Missing parameter for macro");
|
|
|
|
// Add the parameter to the vector.
|
|
vecParams.emplace_back(std::move(ssParam));
|
|
|
|
// Set the token for the new parameter
|
|
locationParam = rcode.GetLocation();
|
|
};
|
|
|
|
bool bDone = false;
|
|
size_t nInsideParenthesis = 0;
|
|
while (!bDone)
|
|
{
|
|
switch(*rcode)
|
|
{
|
|
case '(':
|
|
nInsideParenthesis++;
|
|
ssParam += *rcode;
|
|
token = rcode.GetLocation();
|
|
break;
|
|
case ')':
|
|
if (nInsideParenthesis)
|
|
{
|
|
nInsideParenthesis--;
|
|
ssParam += *rcode;
|
|
} else
|
|
{
|
|
fnTrimCheckAndAdd();
|
|
bDone = true;
|
|
}
|
|
break;
|
|
case ',':
|
|
if (nInsideParenthesis)
|
|
ssParam += *rcode;
|
|
else
|
|
fnTrimCheckAndAdd();
|
|
break;
|
|
case '\0':
|
|
throw CCompileException(rcode.GetLocation(), "Unexpected end of file while parsing macro parameters.");
|
|
break;
|
|
default:
|
|
ssParam += *rcode;
|
|
break;
|
|
}
|
|
++rcode;
|
|
}
|
|
}
|
|
|
|
// The macro will be expanded, add it to the expansion set
|
|
rsetUsedMacros.insert(rssIdentifier);
|
|
|
|
// Expand the macro and prepend the string to the code.
|
|
rcode.PrependCode(itMacro->second.Expand(*this, token, vecParams, rsetUsedMacros));
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CIdlCompilerEnvironment::ResolveConst() const
|
|
{
|
|
return m_bResolveConst;
|
|
}
|
|
|
|
bool CIdlCompilerEnvironment::NoProxyStub() const
|
|
{
|
|
return m_bNoPS;
|
|
}
|
|
|
|
const std::string& CIdlCompilerEnvironment::GetProxStubCMakeTarget() const
|
|
{
|
|
return m_ssProxyStubLibName;
|
|
}
|
|
|
|
sdv::u8string CIdlCompilerEnvironment::GetOption(const sdv::u8string& rssOption) const
|
|
{
|
|
return GetOptionN(rssOption, 0);
|
|
}
|
|
|
|
uint32_t CIdlCompilerEnvironment::GetOptionCnt(const sdv::u8string& rssOption) const
|
|
{
|
|
if (rssOption.empty()) return 0;
|
|
if (rssOption == sdv::idl::ssOptionDevEnvDir)
|
|
return 1;
|
|
else if (rssOption == sdv::idl::ssOptionOutDir)
|
|
return 1;
|
|
else if (rssOption == sdv::idl::ssOptionFilename)
|
|
return 1;
|
|
else if (rssOption == sdv::idl::ssOptionFilePath)
|
|
return 1;
|
|
else if (rssOption == sdv::idl::ssOptionCodeGen)
|
|
return 10;
|
|
return 0;
|
|
}
|
|
|
|
sdv::u8string CIdlCompilerEnvironment::GetOptionN(const sdv::u8string& rssOption, uint32_t nIndex) const
|
|
{
|
|
if (rssOption.empty()) return sdv::u8string();
|
|
if (nIndex >= GetOptionCnt(rssOption)) return sdv::u8string();
|
|
|
|
sdv::u8string ssValue;
|
|
if (rssOption == sdv::idl::ssOptionDevEnvDir)
|
|
ssValue = m_pathCompilerPath.parent_path().generic_u8string();
|
|
else if (rssOption == sdv::idl::ssOptionOutDir)
|
|
ssValue = "";
|
|
else if (rssOption == sdv::idl::ssOptionFilename)
|
|
ssValue = "";
|
|
else if (rssOption == sdv::idl::ssOptionFilePath)
|
|
ssValue = "";
|
|
else if (rssOption == sdv::idl::ssOptionCodeGen)
|
|
ssValue = "";
|
|
return ssValue;
|
|
}
|
|
|