mirror of
https://github.com/ptitSeb/box64.git
synced 2024-11-23 06:30:22 +00:00
Wrapper helper (#1799)
* [WRAPPERHELPER] Added wrapperhelper v0.1, tested on libc * [WRAPPED] Removed updates to libc from this branch * [WRAPPERHELPER] Removed GPL header and added modified LGPL header, added notes about licensing issues
This commit is contained in:
parent
7dc59ac342
commit
6044feb7fd
12
.gitignore
vendored
12
.gitignore
vendored
@ -60,11 +60,13 @@ build*/
|
||||
src/git_head.h
|
||||
backup/
|
||||
|
||||
# LLVMprivateGenerator
|
||||
/LLVMprivateGenerator/*
|
||||
!/LLVMprivateGenerator/Makefile
|
||||
!/LLVMprivateGenerator/main.cpp
|
||||
!/LLVMprivateGenerator/registered_structs.cpp
|
||||
# Wrapper helper
|
||||
/wrapperhelper/bin
|
||||
/wrapperhelper/makedir
|
||||
/wrapperhelper/obj
|
||||
/wrapperhelper/sanaddress
|
||||
/wrapperhelper/sanleak
|
||||
/wrapperhelper/sanundefined
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
|
@ -1,12 +0,0 @@
|
||||
all: dumpSigs
|
||||
|
||||
dumpSigs: main.o registered_structs.o
|
||||
g++ -g3 -std=gnu++17 -fno-rtti main.o registered_structs.o -o dumpSigs "-L$(LLVM_install_dir)/lib" -lclang-cpp -lclangTooling -Wl,-rpath "-Wl,$(LLVM_install_dir)/lib"
|
||||
|
||||
main.o: main.cpp
|
||||
g++ -g3 -std=gnu++17 -fno-rtti -c main.cpp -Wfatal-errors "-I$(LLVM_install_dir)/include" -o main.o
|
||||
registered_structs.o: registered_structs.cpp
|
||||
g++ -g3 -std=gnu++17 -fno-rtti -c registered_structs.cpp -Wfatal-errors -o registered_structs.o
|
||||
|
||||
clean:
|
||||
$(RM) dumpSigs main.o registered_structs.o
|
@ -1,458 +0,0 @@
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <numeric>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <llvm/Support/raw_ostream.h>
|
||||
#include <clang/AST/ASTConsumer.h>
|
||||
#include <clang/AST/Decl.h>
|
||||
#include <clang/AST/Mangle.h>
|
||||
#include <clang/AST/PrettyPrinter.h>
|
||||
#include <clang/AST/RecursiveASTVisitor.h>
|
||||
#include <clang/Frontend/CompilerInstance.h>
|
||||
#include <clang/Frontend/FrontendActions.h>
|
||||
#include <clang/Tooling/CommonOptionsParser.h>
|
||||
#include <clang/Tooling/Tooling.h>
|
||||
|
||||
clang::MangleContext *mangler = nullptr;
|
||||
|
||||
std::unordered_map<std::string, std::pair<std::string, bool>> funMap;
|
||||
std::vector<std::string> funList;
|
||||
|
||||
bool isTypeTrivial(const clang::QualType &q, const clang::QualType *qorig);
|
||||
clang::QualType getPointedType(const clang::QualType q) {
|
||||
if (const clang::PointerType *p = q->getAs<clang::PointerType>())
|
||||
return getPointedType(p->getPointeeType());
|
||||
else if (const clang::ReferenceType *r = q->getAs<clang::ReferenceType>())
|
||||
return getPointedType(r->getPointeeType());
|
||||
else
|
||||
return q;
|
||||
}
|
||||
|
||||
std::string record2name(const clang::RecordDecl &q, const clang::QualType *qorig) {
|
||||
std::string s = q.getNameAsString();
|
||||
if (s == "") {
|
||||
if (!qorig) return "????.!";
|
||||
if (const clang::TypedefType *tt = (*qorig)->getAs<clang::TypedefType>()) {
|
||||
// Typedef
|
||||
if (clang::TypedefNameDecl *td = tt->getDecl()) {
|
||||
return td->getNameAsString();
|
||||
} else {
|
||||
return "<typedef with no declaration>";
|
||||
}
|
||||
} else {
|
||||
return std::string("<unknown type ") + (*qorig)->getTypeClassName() + ">";
|
||||
}
|
||||
} else {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
char ptr2char(const std::string &str) __attribute__((const));
|
||||
const char *ptr2str(const std::string &str) __attribute__((const));
|
||||
char type2char(const clang::QualType &qual /* Canonical */, const clang::QualType *qorig) {
|
||||
if (qual->isBuiltinType()) {
|
||||
switch (static_cast<const clang::BuiltinType&>(*qual).getKind()) {
|
||||
case clang::BuiltinType::Kind::Void:
|
||||
return 'v';
|
||||
case clang::BuiltinType::Kind::Bool:
|
||||
return 'i';
|
||||
case clang::BuiltinType::Kind::Char_U:
|
||||
return 'C';
|
||||
case clang::BuiltinType::Kind::Char_S:
|
||||
return 'c';
|
||||
case clang::BuiltinType::Kind::Char8:
|
||||
return 'c';
|
||||
case clang::BuiltinType::Kind::UChar:
|
||||
return 'C';
|
||||
case clang::BuiltinType::Kind::SChar:
|
||||
return 'c';
|
||||
case clang::BuiltinType::Kind::WChar_U:
|
||||
return 'W';
|
||||
case clang::BuiltinType::Kind::UShort:
|
||||
return 'W';
|
||||
case clang::BuiltinType::Kind::WChar_S:
|
||||
return 'w';
|
||||
case clang::BuiltinType::Kind::Char16:
|
||||
return 'w';
|
||||
case clang::BuiltinType::Kind::Short:
|
||||
return 'w';
|
||||
case clang::BuiltinType::Kind::UInt:
|
||||
return 'u';
|
||||
case clang::BuiltinType::Kind::Char32:
|
||||
return 'i';
|
||||
case clang::BuiltinType::Kind::Int:
|
||||
return 'i';
|
||||
case clang::BuiltinType::Kind::ULong:
|
||||
return 'L';
|
||||
case clang::BuiltinType::Kind::Long:
|
||||
return 'l';
|
||||
case clang::BuiltinType::Kind::ULongLong:
|
||||
return 'U';
|
||||
case clang::BuiltinType::Kind::LongLong:
|
||||
return 'I';
|
||||
case clang::BuiltinType::Kind::UInt128:
|
||||
return 'H';
|
||||
case clang::BuiltinType::Kind::Int128:
|
||||
return 'H';
|
||||
case clang::BuiltinType::Kind::Float:
|
||||
return 'f';
|
||||
case clang::BuiltinType::Kind::Double:
|
||||
return 'd';
|
||||
case clang::BuiltinType::Kind::LongDouble:
|
||||
return 'D';
|
||||
case clang::BuiltinType::Kind::NullPtr:
|
||||
return 'p'; // nullptr_t
|
||||
|
||||
case clang::BuiltinType::Kind::Half:
|
||||
case clang::BuiltinType::Kind::BFloat16:
|
||||
case clang::BuiltinType::Kind::ShortAccum:
|
||||
case clang::BuiltinType::Kind::Accum:
|
||||
case clang::BuiltinType::Kind::LongAccum:
|
||||
case clang::BuiltinType::Kind::UShortAccum:
|
||||
case clang::BuiltinType::Kind::UAccum:
|
||||
case clang::BuiltinType::Kind::ULongAccum:
|
||||
case clang::BuiltinType::Kind::ShortFract:
|
||||
case clang::BuiltinType::Kind::Fract:
|
||||
case clang::BuiltinType::Kind::LongFract:
|
||||
case clang::BuiltinType::Kind::UShortFract:
|
||||
case clang::BuiltinType::Kind::UFract:
|
||||
case clang::BuiltinType::Kind::ULongFract:
|
||||
case clang::BuiltinType::Kind::SatShortAccum:
|
||||
case clang::BuiltinType::Kind::SatAccum:
|
||||
case clang::BuiltinType::Kind::SatLongAccum:
|
||||
case clang::BuiltinType::Kind::SatUShortAccum:
|
||||
case clang::BuiltinType::Kind::SatUAccum:
|
||||
case clang::BuiltinType::Kind::SatULongAccum:
|
||||
case clang::BuiltinType::Kind::SatShortFract:
|
||||
case clang::BuiltinType::Kind::SatFract:
|
||||
case clang::BuiltinType::Kind::SatLongFract:
|
||||
case clang::BuiltinType::Kind::SatUShortFract:
|
||||
case clang::BuiltinType::Kind::SatUFract:
|
||||
case clang::BuiltinType::Kind::SatULongFract:
|
||||
case clang::BuiltinType::Kind::Float16:
|
||||
case clang::BuiltinType::Kind::Float128:
|
||||
case clang::BuiltinType::Kind::Overload:
|
||||
case clang::BuiltinType::Kind::BoundMember:
|
||||
case clang::BuiltinType::Kind::PseudoObject:
|
||||
case clang::BuiltinType::Kind::Dependent:
|
||||
case clang::BuiltinType::Kind::UnknownAny:
|
||||
case clang::BuiltinType::Kind::ARCUnbridgedCast:
|
||||
case clang::BuiltinType::Kind::BuiltinFn:
|
||||
case clang::BuiltinType::Kind::ObjCId:
|
||||
case clang::BuiltinType::Kind::ObjCClass:
|
||||
case clang::BuiltinType::Kind::ObjCSel:
|
||||
#define IMAGE_TYPE(it, id, si, a, s) case clang::BuiltinType::Kind::id:
|
||||
#include <clang/Basic/OpenCLImageTypes.def>
|
||||
#undef IMAGE_TYPE
|
||||
case clang::BuiltinType::Kind::OCLSampler:
|
||||
case clang::BuiltinType::Kind::OCLEvent:
|
||||
case clang::BuiltinType::Kind::OCLClkEvent:
|
||||
case clang::BuiltinType::Kind::OCLQueue:
|
||||
case clang::BuiltinType::Kind::OCLReserveID:
|
||||
case clang::BuiltinType::Kind::IncompleteMatrixIdx:
|
||||
case clang::BuiltinType::Kind::OMPArraySection:
|
||||
case clang::BuiltinType::Kind::OMPArrayShaping:
|
||||
case clang::BuiltinType::Kind::OMPIterator:
|
||||
#define EXT_OPAQUE_TYPE(et, id, e) case clang::BuiltinType::Kind::id:
|
||||
#include <clang/Basic/OpenCLExtensionTypes.def>
|
||||
#define SVE_TYPE(n, id, si) case clang::BuiltinType::Kind::id:
|
||||
#include <clang/Basic/AArch64SVEACLETypes.def>
|
||||
#define PPC_VECTOR_TYPE(n, id, s) case clang::BuiltinType::Kind::id:
|
||||
#include <clang/Basic/PPCTypes.def>
|
||||
#undef EXT_OPAQUE_TYPE
|
||||
#undef SVE_TYPE
|
||||
#undef PPC_VECTOR_TYPE
|
||||
return '!';
|
||||
default:
|
||||
return ':';
|
||||
}
|
||||
} else if (qual->isEnumeralType()) {
|
||||
const clang::EnumDecl *ed = qual->getAs<clang::EnumType>()->getDecl();
|
||||
if (!ed) {
|
||||
return 'i';
|
||||
} else {
|
||||
return type2char(ed->getIntegerType().getCanonicalType(), qorig);
|
||||
}
|
||||
} else if (qual->isFunctionPointerType()) {
|
||||
return '@';
|
||||
} else if (qual->isAnyPointerType() || qual->isReferenceType()) {
|
||||
const clang::QualType &pointed = getPointedType(qual);
|
||||
if (isTypeTrivial(pointed, qorig)) {
|
||||
return 'p';
|
||||
} else if (const clang::RecordType *rct = pointed->getAs<clang::RecordType>()) {
|
||||
clang::RecordDecl *rc = rct->getDecl();
|
||||
if (!rc) {
|
||||
return '!';
|
||||
} else if (!rc->isCompleteDefinition()) {
|
||||
return 'p';
|
||||
} else {
|
||||
std::string str;
|
||||
if (qorig) {
|
||||
const clang::QualType qpted = getPointedType(*qorig);
|
||||
str = record2name(*rc, &qpted);
|
||||
} else {
|
||||
str = record2name(*rc, nullptr);
|
||||
}
|
||||
char ret = ptr2char(str);
|
||||
if (ret) return ret;
|
||||
else {
|
||||
return '!';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return '!';
|
||||
}
|
||||
} else if (const clang::RecordType *rct = qual->getAs<clang::RecordType>()) {
|
||||
clang::RecordDecl *rc = rct->getDecl();
|
||||
if (!rc) {
|
||||
return '?';
|
||||
} else if (rc->getNameAsString() == "__builtin_va_list") {
|
||||
// va_list
|
||||
return 'A';
|
||||
} else {
|
||||
return '?';
|
||||
}
|
||||
} else {
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
bool isTypeTrivial(const clang::QualType &q, const clang::QualType *qorig) {
|
||||
const char c = type2char(q, qorig);
|
||||
#define GO(chr) || (c == chr)
|
||||
return (c == 'v')
|
||||
GO('i') GO('u')
|
||||
GO('I') GO('U')
|
||||
GO('l') GO('L')
|
||||
GO('f') GO('d')
|
||||
GO('D') GO('K')
|
||||
GO('0') GO('1')
|
||||
GO('C') GO('c')
|
||||
GO('W') GO('w')
|
||||
GO('H')
|
||||
GO('p');
|
||||
#undef GO
|
||||
}
|
||||
bool isTypeValid(const clang::QualType &q, const clang::QualType *qorig) {
|
||||
const char c = type2char(q, qorig);
|
||||
if (c == 'A') return false;
|
||||
if (c == 'V') return false;
|
||||
return ((c >= '0') && (c <= '9')) || ((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z'));
|
||||
}
|
||||
|
||||
const std::string type2string(const clang::QualType &qual, const clang::QualType *qorig) {
|
||||
if (qual->isBuiltinType()) {
|
||||
return std::string("(builtin) ") + static_cast<const clang::BuiltinType&>(*qual).getName(clang::PrintingPolicy{{}}).data();
|
||||
} else if (qual->isFunctionPointerType()) {
|
||||
return "Callback (function pointer)";
|
||||
} else if (qual->isAnyPointerType() || qual->isReferenceType()) {
|
||||
std::string prefix = qual->isAnyPointerType() ? "Pointer to " : "Reference to ";
|
||||
const clang::QualType &pointed = getPointedType(qual);
|
||||
if (isTypeTrivial(pointed, qorig)) {
|
||||
return prefix + "trivial object " + type2string(pointed, qorig) + " (" + type2char(pointed, qorig) + ")";
|
||||
} else if (const clang::RecordType *rct = pointed->getAs<clang::RecordType>()) {
|
||||
clang::RecordDecl *rc = rct->getDecl();
|
||||
if (!rc) {
|
||||
return prefix + "unknown record";
|
||||
} else if (!rc->isCompleteDefinition()) {
|
||||
return prefix + "incomplete record " + rc->getNameAsString();
|
||||
} else {
|
||||
std::string str;
|
||||
if (qorig) {
|
||||
const clang::QualType qpted = getPointedType(*qorig);
|
||||
str = record2name(*rc, &qpted);
|
||||
} else {
|
||||
str = record2name(*rc, nullptr);
|
||||
}
|
||||
const char *ret = ptr2str(str);
|
||||
if (ret[0] != '\0') {
|
||||
return prefix + ret;
|
||||
} else {
|
||||
if (mangler && mangler->shouldMangleDeclName(rc)) {
|
||||
std::string mangled;
|
||||
{
|
||||
llvm::raw_string_ostream strstr{mangled};
|
||||
mangler->mangleName(rc, strstr);
|
||||
}
|
||||
return prefix + "unknown record " + str + " (=== " + mangled + ")";
|
||||
} else {
|
||||
return prefix + "unknown record " + str;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return prefix + "non-trivial or typedef'ed object " + type2string(pointed, qorig) + " (" + type2char(pointed, qorig) + ")";
|
||||
//return "Pointer (maybe to callback)";
|
||||
}
|
||||
} else if (qual->isEnumeralType()) {
|
||||
const clang::EnumDecl *ed = qual->getAs<clang::EnumType>()->getDecl();
|
||||
if (!ed) {
|
||||
return "Enumeration with unknown underlying integer type (assuming int)";
|
||||
} else {
|
||||
return "Enumeration with underlying type " + type2string(ed->getIntegerType().getCanonicalType(), nullptr);
|
||||
}
|
||||
} else if (const clang::RecordType *rct = qual->getAs<clang::RecordType>()) {
|
||||
clang::RecordDecl *rc = rct->getDecl();
|
||||
if (!rc) {
|
||||
return "Unknown record";
|
||||
} else if (rc->getNameAsString() == "__builtin_va_list") {
|
||||
return "va_list";
|
||||
} else {
|
||||
return "Unknown record " + std::string(rc->getName().data());
|
||||
}
|
||||
} else {
|
||||
return std::string("??? ") + qual->getTypeClassName();
|
||||
}
|
||||
}
|
||||
|
||||
class Visitor : public clang::RecursiveASTVisitor<Visitor> {
|
||||
public:
|
||||
clang::ASTContext &context;
|
||||
|
||||
bool shouldVisitTemplateInstantiations() const /* override */ { return true; }
|
||||
|
||||
Visitor(clang::CompilerInstance &ci) : context(ci.getASTContext()) {
|
||||
if (!mangler) {
|
||||
mangler = clang::ItaniumMangleContext::create(context, ci.getDiagnostics());
|
||||
}
|
||||
}
|
||||
|
||||
~Visitor() {
|
||||
if (mangler) {
|
||||
delete mangler;
|
||||
mangler = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool VisitDecl(clang::Decl *decl) /* override */ {
|
||||
std::cerr << std::flush;
|
||||
if (!decl) return true;
|
||||
|
||||
if ((decl->getKind() >= clang::Decl::Kind::firstFunction) && (decl->getKind() <= clang::Decl::Kind::lastFunction)) {
|
||||
clang::DeclaratorDecl *ddecl = static_cast<clang::DeclaratorDecl*>(decl);
|
||||
std::cout << "Function detected!\n";
|
||||
|
||||
std::string funName{ddecl->getName()};
|
||||
|
||||
auto niceprint = [](const std::string &infotype, const auto &dat){ std::cout << " " << infotype << ": " << dat << "\n"; };
|
||||
niceprint("Function name", funName);
|
||||
if (mangler && mangler->shouldMangleDeclName(ddecl)) {
|
||||
std::string mangled;
|
||||
{
|
||||
llvm::raw_string_ostream strstr{mangled};
|
||||
mangler->mangleName(ddecl, strstr);
|
||||
}
|
||||
niceprint("Function mangled name", mangled);
|
||||
funName = std::move(mangled);
|
||||
}
|
||||
|
||||
bool valid;
|
||||
std::string funTypeStr{""};
|
||||
if (ddecl->getFunctionType()->isFunctionNoProtoType()) {
|
||||
const clang::FunctionNoProtoType *funType = static_cast<const clang::FunctionNoProtoType*>(ddecl->getFunctionType());
|
||||
const auto &retType = funType->getReturnType();
|
||||
|
||||
niceprint("Function return type", type2string(retType, &retType));
|
||||
niceprint("Canonical function return type",
|
||||
type2string(retType.getCanonicalType(), &retType) +
|
||||
" (" + type2char(retType.getCanonicalType(), &retType) + ")");
|
||||
niceprint("Is sugared", funType->isSugared());
|
||||
if (funType->isSugared()) {
|
||||
clang::QualType qft{funType, 0};
|
||||
niceprint("Desugared", type2string(funType->desugar(), &qft));
|
||||
}
|
||||
|
||||
funTypeStr = type2char(retType.getCanonicalType(), &retType) + std::string("Fv");
|
||||
valid = isTypeValid(retType.getCanonicalType(), &retType);
|
||||
} else {
|
||||
const clang::FunctionProtoType *funType = static_cast<const clang::FunctionProtoType*>(ddecl->getFunctionType());
|
||||
const auto &retType = funType->getReturnType();
|
||||
|
||||
niceprint("Function return type", type2string(retType, &retType));
|
||||
niceprint("Canonical function return type",
|
||||
type2string(retType.getCanonicalType(), &retType)
|
||||
+ " (" + type2char(retType.getCanonicalType(), &retType) + ")");
|
||||
niceprint("Parameter count", funType->getNumParams());
|
||||
for (const clang::QualType &type : funType->getParamTypes()) {
|
||||
niceprint(" " + type2string(type, &type),
|
||||
type2string(type.getCanonicalType(), &type) + " (" + type2char(type.getCanonicalType(), &type) + ")");
|
||||
}
|
||||
niceprint("Variadic function", funType->isVariadic() ? "yes" : "no");
|
||||
|
||||
funTypeStr =
|
||||
type2char(retType.getCanonicalType(), &retType) +
|
||||
((funType->getNumParams() == 0)
|
||||
? std::string("Fv") : std::accumulate(funType->getParamTypes().begin(), funType->getParamTypes().end(), std::string("F"),
|
||||
[](const std::string &acc, const clang::QualType &qual){ return acc + type2char(qual.getCanonicalType(), &qual); }));
|
||||
if (funType->isVariadic()) funTypeStr += "V";
|
||||
valid = !funType->isVariadic() &&
|
||||
std::accumulate(funType->getParamTypes().begin(), funType->getParamTypes().end(), isTypeValid(retType.getCanonicalType(), &retType),
|
||||
[](bool acc, const clang::QualType &qual){ return acc && isTypeValid(qual.getCanonicalType(), &qual); });
|
||||
}
|
||||
|
||||
niceprint("Conclusion", "");
|
||||
niceprint("Function final name", funName);
|
||||
niceprint("Function type", funTypeStr);
|
||||
niceprint("Valid function type", valid ? "yes" : "no");
|
||||
std::cout << "\n";
|
||||
|
||||
funMap[funName] = std::make_pair(funTypeStr, valid);
|
||||
funList.push_back(funName);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class Consumer : public clang::ASTConsumer {
|
||||
public:
|
||||
Visitor visitor;
|
||||
|
||||
Consumer(clang::CompilerInstance &ci) : visitor(ci) {
|
||||
}
|
||||
|
||||
void HandleTranslationUnit(clang::ASTContext &context) override {
|
||||
visitor.TraverseDecl(context.getTranslationUnitDecl());
|
||||
}
|
||||
};
|
||||
|
||||
class Action : public clang::ASTFrontendAction {
|
||||
public:
|
||||
virtual std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(clang::CompilerInstance &ci, llvm::StringRef inFile) override {
|
||||
return std::make_unique<Consumer>(ci);
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
if (argc < 2) {
|
||||
std::cerr << "Usage: " << argv[0] << " (filenames) -- [-I...]" << std::endl;
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*int fakeargc = argc + 1;
|
||||
const char **fakeargv = new const char*[fakeargc];
|
||||
memcpy(fakeargv, argv, argc * sizeof(char*));
|
||||
fakeargv[fakeargc - 1] = "--";*/
|
||||
llvm::cl::OptionCategory opcat{""};
|
||||
clang::tooling::CommonOptionsParser op{argc, argv, opcat};
|
||||
std::vector<std::string> paths; for (int i = 1; i < argc; ++i) paths.push_back(argv[i]);
|
||||
|
||||
clang::tooling::ClangTool tool{op.getCompilations(), paths};
|
||||
|
||||
tool.run(clang::tooling::newFrontendActionFactory<Action>().get());
|
||||
|
||||
std::cout << "Done, outputing output.h" << std::endl;
|
||||
std::sort(funList.begin(), funList.end());
|
||||
std::fstream file{"output.h", std::ios_base::out};
|
||||
for (const std::string &funName : funList) {
|
||||
if (!funMap[funName].second) {
|
||||
file << "//";
|
||||
}
|
||||
file << "GO(" << funName << ", " << funMap[funName].first << ")\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,267 +0,0 @@
|
||||
#include <string>
|
||||
|
||||
#define ALL START() \
|
||||
/* libc */ \
|
||||
STRUCT("_IO_FILE", "a FILE") \
|
||||
STRUCT("_G_fpos_t", "a file position") \
|
||||
STRUCT("sockaddr", "a socket address") \
|
||||
STRUCT("itimerspec", "an itimerspec") \
|
||||
STRUCT("timespec", "a timespec") \
|
||||
STRUCT("itimerval", "an itimerval") \
|
||||
STRUCT("timeval", "a timeval") \
|
||||
STRUCT("timex", "a timex") \
|
||||
STRUCT("timezone", "a timezone") \
|
||||
STRUCT("dirent", "a dirent") \
|
||||
STRUCT("dirent64", "a dirent64") \
|
||||
STRUCT("__dirstream", "a dir stream") \
|
||||
STRUCT("tm", "a time structure (tm)") \
|
||||
STRUCT("cmsghdr", "a cmsghdr") \
|
||||
STRUCT("msghdr", "a msghdr") \
|
||||
STRUCT("rpcent", "an rpcent") \
|
||||
STRUCT("random_data", "a random_data structure") \
|
||||
STRUCT("drand48_data", "a drand48_data structure") \
|
||||
STRUCT("termios", "a termios") \
|
||||
STRUCT("iovec", "an iovec") \
|
||||
STRUCT("file_handle", "a file handle") \
|
||||
STRUCT("lconv", "an lconv") \
|
||||
STRUCT("__locale_struct", "a locale structure") \
|
||||
STRUCT("aliasent", "an alias") \
|
||||
STRUCT("fstab", "an fstab") \
|
||||
STRUCT("group", "a group") \
|
||||
STRUCT("hostent", "a hostent") \
|
||||
STRUCT("protoent", "a protoent") \
|
||||
STRUCT("passwd", "a password") \
|
||||
STRUCT("spwd", "an spwd") \
|
||||
STRUCT("ttyent", "a ttyent") \
|
||||
STRUCT("utmp", "an utmp structure") \
|
||||
STRUCT("utmpx", "an utmpx structure") \
|
||||
STRUCT("ifaddrs", "an ifaddrs structure") \
|
||||
STRUCT("statfs", "a statfs structure") \
|
||||
STRUCT("statfs64", "a statfs64 structure") \
|
||||
STRUCT("statvfs", "a statvfs structure") \
|
||||
STRUCT("statvfs64", "a statvfs64 structure") \
|
||||
STRUCT("timeb", "a timeb structure") \
|
||||
STRUCT("_ftsent", "an _ftsent structure") \
|
||||
STRUCT("sysinfo", "a sysinfo structure") \
|
||||
STRUCT("rlimit", "an rlimit structure") \
|
||||
STRUCT("rlimit64", "an rlimit64 structure") \
|
||||
STRUCT("rusage", "an rusage structure") \
|
||||
STRUCT("entry", "an entry structure") \
|
||||
STRUCT("pollfd", "a pollfd structure") \
|
||||
STRUCT("re_pattern_buffer", "a re_pattern_buffer structure") \
|
||||
STRUCT("sembuf", "a sembuf structure") \
|
||||
STRUCT("tms", "a tms structure") \
|
||||
STRUCT("utsname", "an utsname structure") \
|
||||
STRUCT("utimbuf", "an utimbuf structure") \
|
||||
STRUCT2("__va_list_tag", "__va_list_tag (aka, a va_list)", 'A') \
|
||||
/* ncurses */ \
|
||||
STRUCT("_win_st", "a _win_st structure") \
|
||||
STRUCT("MEVENT", "an MEVENT structure") \
|
||||
TYPEDEF("cchar_t", "a cchar_t") \
|
||||
/* zlib */ \
|
||||
STRUCT("gz_header_s", "a gz_header_s structure") \
|
||||
STRUCT("gzFile_s", "a gzFile_s structure") \
|
||||
STRUCT("z_stream_s", "a z_stream_s structure") \
|
||||
\
|
||||
END()
|
||||
|
||||
#define START()
|
||||
#define STRUCT(s, ret) if (str == s) { return 'p'; } else
|
||||
#define STRUCT2(s, ret, c) if (str == s) { return c; } else
|
||||
#define TYPEDEF(s, ret) if (str == s) { return 'p'; } else
|
||||
#define END() { return 0; }
|
||||
char ptr2char(const std::string &str) {
|
||||
/*if ((str == "_IO_FILE")
|
||||
|| (str == "_G_fpos_t")
|
||||
|| (str == "sockaddr")
|
||||
|| (str == "itimerspec")
|
||||
|| (str == "timespec")
|
||||
|| (str == "itimerval")
|
||||
|| (str == "timeval")
|
||||
|| (str == "timex")
|
||||
|| (str == "timezone")
|
||||
|| (str == "dirent")
|
||||
|| (str == "dirent64")
|
||||
|| (str == "__dirstream")
|
||||
|| (str == "tm")
|
||||
|| (str == "cmsghdr")
|
||||
|| (str == "msghdr")
|
||||
|| (str == "rpcent")
|
||||
|| (str == "random_data")
|
||||
|| (str == "drand48_data")
|
||||
|| (str == "termios")
|
||||
|| (str == "iovec")
|
||||
|| (str == "file_handle")
|
||||
|| (str == "lconv")
|
||||
|| (str == "__locale_struct")
|
||||
|| (str == "aliasent")
|
||||
|| (str == "fstab")
|
||||
|| (str == "group")
|
||||
|| (str == "hostent")
|
||||
|| (str == "protoent")
|
||||
|| (str == "passwd")
|
||||
|| (str == "spwd")
|
||||
|| (str == "ttyent")
|
||||
|| (str == "utmp")
|
||||
|| (str == "utmpx")
|
||||
|| (str == "ifaddrs")
|
||||
|| (str == "statfs")
|
||||
|| (str == "statfs64")
|
||||
|| (str == "statvfs")
|
||||
|| (str == "timeb")
|
||||
|| (str == "_ftsent")
|
||||
|| (str == "sysinfo")
|
||||
|| (str == "rlimit")
|
||||
|| (str == "rlimit64")
|
||||
|| (str == "rusage")
|
||||
|| (str == "entry")
|
||||
|| (str == "pollfd")
|
||||
|| (str == "re_pattern_buffer")
|
||||
|| (str == "sembuf")
|
||||
|| (str == "tms")
|
||||
|| (str == "utsname")
|
||||
|| (str == "utimbuf")
|
||||
// ncurses
|
||||
|| (str == "_win_st")
|
||||
|
||||
|| (str == "cchar_t")
|
||||
) {
|
||||
// FILE*, fpos_t*, ...
|
||||
return 'p';
|
||||
} else if (str == "__va_list_tag") {
|
||||
return 'A';
|
||||
} else {
|
||||
return 0;
|
||||
}*/
|
||||
ALL
|
||||
}
|
||||
#undef END
|
||||
#undef TYPEDEF
|
||||
#undef STRUCT2
|
||||
#undef STRUCT
|
||||
#undef START
|
||||
|
||||
#define START()
|
||||
#define STRUCT(s, ret) if (str == s) { return ret; } else
|
||||
#define STRUCT2(s, ret, c) if (str == s) { return ret; } else
|
||||
#define TYPEDEF(s, ret) if (str == s) { return ret; } else
|
||||
#define END() return "";
|
||||
const char *ptr2str(const std::string &str) {
|
||||
/*if (str == "_IO_FILE") {
|
||||
return "a FILE";
|
||||
} else if (str == "_G_fpos_t") {
|
||||
return "a file position";
|
||||
} else if (str == "sockaddr") {
|
||||
return "a socket address";
|
||||
} else if (str == "itimerspec") {
|
||||
return "an itimerspec";
|
||||
} else if (str == "timespec") {
|
||||
return "a timespec";
|
||||
} else if (str == "itimerval") {
|
||||
return "an itimerval";
|
||||
} else if (str == "timeval") {
|
||||
return "a timeval";
|
||||
} else if (str == "timex") {
|
||||
return "a timex";
|
||||
} else if (str == "timezone") {
|
||||
return "a timezone";
|
||||
} else if (str == "dirent") {
|
||||
return "a dirent";
|
||||
} else if (str == "dirent64") {
|
||||
return "a dirent64";
|
||||
} else if (str == "__dirstream") {
|
||||
return "a dir stream";
|
||||
} else if (str == "tm") {
|
||||
return "a time structure (tm)";
|
||||
} else if (str == "cmsghdr") {
|
||||
return "a cmsghdr";
|
||||
} else if (str == "msghdr") {
|
||||
return "a msghdr";
|
||||
} else if (str == "rpcent") {
|
||||
return "an rpcent";
|
||||
} else if (str == "random_data") {
|
||||
return "a random_data structure";
|
||||
} else if (str == "drand48_data") {
|
||||
return "a drand48_data structure";
|
||||
} else if (str == "termios") {
|
||||
return "a termios";
|
||||
} else if (str == "iovec") {
|
||||
return "an iovec";
|
||||
} else if (str == "file_handle") {
|
||||
return "a file handle";
|
||||
} else if (str == "lconv") {
|
||||
return "an lconv";
|
||||
} else if (str == "__locale_struct") {
|
||||
return "a locale structure";
|
||||
} else if (str == "aliasent") {
|
||||
return "an alias";
|
||||
} else if (str == "fstab") {
|
||||
return "an fstab";
|
||||
} else if (str == "group") {
|
||||
return "a group";
|
||||
} else if (str == "hostent") {
|
||||
return "a hostent";
|
||||
} else if (str == "protoent") {
|
||||
return "a protoent";
|
||||
} else if (str == "passwd") {
|
||||
return "a password";
|
||||
} else if (str == "spwd") {
|
||||
return "an spwd";
|
||||
} else if (str == "ttyent") {
|
||||
return "a ttyent";
|
||||
} else if (str == "utmp") {
|
||||
return "an utmp structure";
|
||||
} else if (str == "utmpx") {
|
||||
return "an utmpx structure";
|
||||
} else if (str == "ifaddrs") {
|
||||
return "an ifaddrs structure";
|
||||
} else if (str == "statfs") {
|
||||
return "a statfs structure";
|
||||
} else if (str == "statfs64") {
|
||||
return "a statfs64 structure";
|
||||
} else if (str == "statvfs") {
|
||||
return "a statvfs structure";
|
||||
} else if (str == "statvfs64") {
|
||||
return "a statvfs64 structure";
|
||||
} else if (str == "timeb") {
|
||||
return "a timeb structure";
|
||||
} else if (str == "_ftsent") {
|
||||
return "an _ftsent structure";
|
||||
} else if (str == "sysinfo") {
|
||||
return "a sysinfo structure";
|
||||
} else if (str == "rlimit") {
|
||||
return "an rlimit structure";
|
||||
} else if (str == "rlimit64") {
|
||||
return "an rlimit64 structure";
|
||||
} else if (str == "rusage") {
|
||||
return "an rusage structure";
|
||||
} else if (str == "entry") {
|
||||
return "an entry structure";
|
||||
} else if (str == "pollfd") {
|
||||
return "a pollfd structure";
|
||||
} else if (str == "re_pattern_buffer") {
|
||||
return "a re_pattern_buffer structure";
|
||||
} else if (str == "sembuf") {
|
||||
return "a sembuf structure";
|
||||
} else if (str == "tms") {
|
||||
return "a tms structure";
|
||||
} else if (str == "utsname") {
|
||||
return "an utsname structure";
|
||||
} else if (str == "utimbuf") {
|
||||
return "an utimbuf structure";
|
||||
} else if (str == "__va_list_tag") {
|
||||
return "__va_list_tag (aka, a va_list)";
|
||||
// ncurses
|
||||
} else if (str == "_win_st") {
|
||||
return "a _win_st structure";
|
||||
|
||||
} else if (str == "cchar_t") {
|
||||
return "a cchar_t";
|
||||
} else return "";*/
|
||||
ALL
|
||||
}
|
||||
#undef END
|
||||
#undef TYPEDEF
|
||||
#undef STRUCT2
|
||||
#undef STRUCT
|
||||
#undef START
|
@ -1,7 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project("helper")
|
||||
find_package(Clang REQUIRED CONFIG)
|
||||
|
||||
add_executable(helper main.cpp gen.cpp)
|
||||
target_include_directories(helper SYSTEM PUBLIC ${CLANG_INCLUDE_DIRS})
|
||||
target_link_libraries(helper PUBLIC clang-cpp LLVM)
|
299
wrapperhelper/Makefile
Executable file
299
wrapperhelper/Makefile
Executable file
@ -0,0 +1,299 @@
|
||||
all:
|
||||
.PHONY: all
|
||||
|
||||
OPTIM?=2
|
||||
DEBUG?=1
|
||||
# FORCE_COLOR: set to non-empty, non 0 to force colorized output
|
||||
# ECHO: set to non-empty, non 0 to echo commands out
|
||||
|
||||
help:
|
||||
@echo 'Targets:'
|
||||
@echo ' help (current target)'
|
||||
@echo ' all (default target)'
|
||||
@echo ' [EXE] - wrapperhelper'
|
||||
@printf ' $(foreach obj,$(OBJLIST_wrapperhelper), [OBJ] - $(obj)\n)'
|
||||
@printf ' $(foreach test,$(TESTS), [TST] - $(test)\n)'
|
||||
@echo ' clean'
|
||||
@echo ' distclean'
|
||||
@echo ''
|
||||
@echo 'Options:'
|
||||
@echo ' OPTIM: GCC optimization level (-O is prepended) [default: 2]'
|
||||
@echo ' DEBUG: set to 0 for release build, set to non-0 for debug build [default: 1]'
|
||||
@echo ' FORCE_COLOR: set to non-0 to force colorized output'
|
||||
@echo ' ECHO: set to non-0 to echo out commands executed'
|
||||
@echo ''
|
||||
@echo 'Current flags:'
|
||||
@echo ' CPPFLAGS = $(CPPFLAGS)'
|
||||
@echo ' CFLAGS = $(CFLAGS)'
|
||||
# @echo ' CXXFLAGS = $(CXXFLAGS)' unused
|
||||
@echo ' LDFLAGS = $(LDFLAGS)'
|
||||
@echo ' LDLIBS = $(LDLIBS)'
|
||||
@echo ''
|
||||
@echo 'Sanitizers:'
|
||||
@echo " address ------------ `[ $(ASAN_ON) -eq 1 ] && printf '\033[92mON\033[m' || printf '\033[91mOFF\033[m'`"
|
||||
@echo " leak --------------- `[ $(LSAN_ON) -eq 1 ] && printf '\033[92mON\033[m' || printf '\033[91mOFF\033[m'`"
|
||||
@echo " undefined behavior - `[ $(USAN_ON) -eq 1 ] && printf '\033[92mON\033[m' || printf '\033[91mOFF\033[m'`"
|
||||
.PHONY: help
|
||||
|
||||
ifeq ($(ECHO:0=),)
|
||||
SILENCER:=@
|
||||
else
|
||||
SILENCER:=
|
||||
endif
|
||||
|
||||
ifneq ($(strip $(DEBUG)),0)
|
||||
CPPFLAGS+= -DDEBUG -D_NRELEASE
|
||||
CFLAGS+= -g
|
||||
CXXFLAGS+= -g
|
||||
LDFLAGS+= -g
|
||||
OBJDIR?=debug
|
||||
else
|
||||
CPPFLAGS+= -DRELEASE -D_NDEBUG
|
||||
OBJDIR?=release
|
||||
endif
|
||||
|
||||
COMMON_WARNINGS:=-Wfatal-errors -fanalyzer -Wall -Wextra
|
||||
COMMON_WARNINGS+= -Walloc-zero -Wcast-align=strict -Wcast-qual -Wconversion -Wdate-time
|
||||
COMMON_WARNINGS+= -Wdisabled-optimization -Wduplicated-branches -Wfloat-equal -Wformat-truncation=2
|
||||
COMMON_WARNINGS+= -Wimplicit-fallthrough=3 -Wlogical-op -Wmissing-format-attribute -Wmissing-include-dirs
|
||||
COMMON_WARNINGS+= -Wmissing-noreturn -Wnull-dereference -Wredundant-decls -Wundef -Wunreachable-code -Wshift-overflow=2
|
||||
COMMON_WARNINGS+= -Wstringop-overflow=4
|
||||
#COMMON_WARNINGS+= -Wstringop-overflow=4 -Wsuggest-attribute=cold -Wsuggest-attribute=const -Wsuggest-attribute=format
|
||||
#COMMON_WARNINGS+= -Wsuggest-attribute=malloc -Wsuggest-attribute=noreturn -Wsuggest-attribute=pure
|
||||
COMMON_WARNINGS+= -Wunknown-pragmas -Wunused-macros -Wwrite-strings
|
||||
COMMON_WARNINGS+= -Werror=attribute-alias=2 -Werror=duplicated-cond -Werror=format=2 -Werror=format-overflow=2
|
||||
COMMON_WARNINGS+= -Werror=format-signedness -Werror=pointer-arith
|
||||
COMMON_WARNINGS+= -Werror=return-type -Werror=shadow -Werror=strict-overflow -Werror=switch-enum
|
||||
CFLAGS_WARNINGS:=-Werror=implicit-function-declaration -Werror=jump-misses-init -Werror=strict-prototypes
|
||||
CXXFLAGS_WARNINGS:=-Werror=overloaded-virtual -fdiagnostics-show-template-tree -Wno-analyzer-use-of-uninitialized-value
|
||||
|
||||
CPPFLAGS+=
|
||||
CFLAGS:=$(COMMON_WARNINGS) $(CFLAGS_WARNINGS) $(CFLAGS) -std=gnu18 -O$(OPTIM)
|
||||
CXXFLAGS:=$(COMMON_WARNINGS) $(CXXFLAGS_WARNINGS) $(CXXFLAGS) -std=c++20 -O$(OPTIM)
|
||||
LDFLAGS+= -O$(OPTIM)
|
||||
|
||||
#CPPFLAGS+= -I/usr/include/SDL2 -D_REENTRANT -pthread
|
||||
#CFLAGS+= -pthread
|
||||
#CXXFLAGS+= -pthread
|
||||
#LDLIBS+= -pthread -lSDL2
|
||||
|
||||
ifeq (,$(wildcard $(CURDIR)/sanaddress))
|
||||
ASAN_ON:=0
|
||||
else
|
||||
ASAN_ON:=1
|
||||
CFLAGS+= -fsanitize=address
|
||||
CXXFLAGS+= -fsanitize=address
|
||||
LDFLAGS+= -fsanitize=address
|
||||
endif
|
||||
ifeq (,$(wildcard $(CURDIR)/sanleak))
|
||||
LSAN_ON:=0
|
||||
else
|
||||
LSAN_ON:=1
|
||||
CFLAGS+= -fsanitize=leak
|
||||
CXXFLAGS+= -fsanitize=leak
|
||||
LDFLAGS+= -fsanitize=leak
|
||||
endif
|
||||
ifeq (,$(wildcard $(CURDIR)/sanundefined))
|
||||
USAN_ON:=0
|
||||
else
|
||||
USAN_ON:=1
|
||||
CFLAGS+= -fsanitize=undefined
|
||||
CXXFLAGS+= -fsanitize=undefined
|
||||
LDFLAGS+= -fsanitize=undefined
|
||||
endif
|
||||
|
||||
# Default
|
||||
# .SUFFIXES: .out .a .ln .o .c .cc .C .cpp .p .f .F .m .r .y .l .ym .yl .s .S .mod
|
||||
# .sym .def .h .info .dvi .tex .texinfo .texi .txinfo .w .ch .web .sh .elc .el
|
||||
SUFFIXES =
|
||||
.SUFFIXES:
|
||||
.SECONDEXPANSION:
|
||||
|
||||
ifneq ($(MAKECMDGOALS:distclean=clean),clean)
|
||||
.: ;
|
||||
bin obj: ; $(SILENCER)test -d $@ || mkdir $@
|
||||
# $(eval $(call reproduce_tree,<base>))
|
||||
define reproduce_tree =
|
||||
$(1) $(1)/parser: | $$$$(@D) ; $(SILENCER)test -d $$@ || mkdir $$@
|
||||
endef
|
||||
$(eval $(call reproduce_tree,obj/$(OBJDIR)))
|
||||
$(eval $(call reproduce_tree,obj/$(OBJDIR)/tests))
|
||||
$(eval $(call reproduce_tree,makedir))
|
||||
$(eval $(call reproduce_tree,makedir/tests))
|
||||
$(eval $(call reproduce_tree,tests))
|
||||
endif
|
||||
|
||||
# Colors:
|
||||
# -------
|
||||
# +--------+-----+
|
||||
# | 3 | 9 |
|
||||
# +-+--------+-----+
|
||||
# |0| | | Black
|
||||
# |1| | RM | Red
|
||||
# |2| |[MSG]| Green
|
||||
# |3|Creating| | Yellow
|
||||
# |4| | CP | Blue
|
||||
# |5| | LD | Purple
|
||||
# |6| C++ | | Cyan
|
||||
# |7| | | Gray/white
|
||||
# +-+--------+-----+
|
||||
|
||||
# $(call colorize,<br_color>,<br_text>,<text_color>,<text>)
|
||||
ifdef $(if $(FORCE_COLOR:0=),FORCE_COLOR,MAKE_TERMOUT)
|
||||
CFLAGS:=$(CFLAGS) -fdiagnostics-color
|
||||
CXXFLAGS:=$(CFLAGS) -fdiagnostics-color
|
||||
colorize=@printf "\033[$(1)m[$(2)]\033[m \033[$(3)m$(4)\033[m\n"
|
||||
else
|
||||
ifeq ($(SILENCER),)
|
||||
colorize=
|
||||
else
|
||||
colorize=@echo "[$(2)] $(4)"
|
||||
endif
|
||||
endif
|
||||
|
||||
define newline :=
|
||||
|
||||
|
||||
endef
|
||||
|
||||
# $(call remove,<list of file names to remove>)
|
||||
define remove =
|
||||
$(call colorize,1;91,RM ,91,Removing $(1))
|
||||
$(SILENCER)$(RM) -r $(1)
|
||||
endef
|
||||
|
||||
# $(eval $(call add_deptree,<compiler with flags>,<output_filename_noext>,<input_filename_withoutsrc>))
|
||||
ifeq ($(MAKECMDGOALS),distclean)
|
||||
add_deptree=
|
||||
else
|
||||
define add_deptree =
|
||||
makedir/$(2).mk: | $$$$(@D)
|
||||
$(call colorize,95,DEP,33,Creating $(3) dependancies)
|
||||
$(SILENCER)set -e; $(1) -MM src/$(3) \
|
||||
| sed 's,\($$(notdir $$(basename $(3)))\)\.o[ :]*,$$(dir obj/$(OBJDIR)/$(3))\1.o: $$@'"\n"'$$(dir obj/$(OBJDIR)/$(3))\1.o $$@: ,g' >$$@
|
||||
include makedir/$(2).mk
|
||||
endef
|
||||
endif
|
||||
|
||||
OBJLIST=$(OBJLIST_wrapperhelper) $(foreach test,$(TESTS),$(call test_o,$(test)))
|
||||
OBJLIST_wrapperhelper:=
|
||||
TESTS:=
|
||||
|
||||
# $(call wrapperhelper_o,<base_dir>,<source_filename>,<output_filename>)
|
||||
wrapperhelper_o=obj/$(OBJDIR)/$(1)$(3).o
|
||||
# $(eval $(call compile_wrapperhelper_c,<base_dir>,<source_filename>,<output_filename>))
|
||||
define compile_wrapperhelper_c =
|
||||
$$(eval $$(call add_deptree,$$(CC) $$(CPPFLAGS) $$(CFLAGS),$(1)$(3),$(1)$(2).c))
|
||||
OBJLIST_wrapperhelper+= $(call wrapperhelper_o,$(1),$(2),$(3))
|
||||
$(call wrapperhelper_o,$(1),$(2),$(3)): src/$(1)$(2).c | $$$$(@D)
|
||||
$(call colorize,36, C ,92,Compiling $$@)
|
||||
$(SILENCER)$$(CC) $$(CPPFLAGS) $$(CFLAGS) -c src/$(1)$(2).c -o $$@
|
||||
endef
|
||||
# $(eval $(call compile_wrapperhelper_cxx,<base_dir>,<source_filename>,<output_filename>))
|
||||
define compile_wrapperhelper_cxx =
|
||||
$$(eval $$(call add_deptree,$$(CXX) $$(CPPFLAGS) $$(CXXFLAGS),$(1)$(3),$(1)$(2).cpp))
|
||||
OBJLIST_wrapperhelper+= $(call wrapperhelper_o,$(1),$(2),$(3))
|
||||
$(call wrapperhelper_o,$(1),$(2),$(3)): src/$(1)$(2).cpp | $$$$(@D)
|
||||
$(call colorize,36,C++,92,Compiling $$@)
|
||||
$(SILENCER)$$(CXX) $$(CPPFLAGS) $$(CXXFLAGS) -c src/$(1)$(2).cpp -o $$@
|
||||
endef
|
||||
|
||||
# $(eval $(call compile_test_c,<test_dir/name>))
|
||||
define compile_test_c =
|
||||
$$(eval $$(call add_deptree,$$(CC) $$(CPPFLAGS) -Isrc/tests -Isrc $$(CFLAGS),tests/$(1),tests/$(1).c))
|
||||
TESTS+= $(1)
|
||||
tests/$(1): obj/$(OBJDIR)/tests/$(1).o | $$$$(@D)
|
||||
$(call colorize,95,LD ,92,Linking $$@)
|
||||
$(SILENCER)$$(CC) $$(LDFLAGS) -o $$@ obj/$(OBJDIR)/tests/$(1).o $$(LDLIBS)
|
||||
|
||||
obj/$(OBJDIR)/tests/$(1).o: src/tests/$(1).c | $$$$(@D)
|
||||
$(call colorize,36,C++,92,Compiling $$@)
|
||||
$(SILENCER)$$(CC) $$(CPPFLAGS) -Isrc/tests -Isrc $$(CFLAGS) -c src/tests/$(1).c -o $$@
|
||||
endef
|
||||
# $(eval $(call compile_test_cxx,<test_dir/name>))
|
||||
define compile_test_cxx =
|
||||
$$(eval $$(call add_deptree,$$(CXX) $$(CPPFLAGS) -Isrc/tests -Isrc $$(CXXFLAGS),tests/$(1),tests/$(1).cpp))
|
||||
TESTS+= $(1)
|
||||
tests/$(1): obj/$(OBJDIR)/tests/$(1).o | $$$$(@D)
|
||||
$(call colorize,95,LD ,92,Linking $$@)
|
||||
$(SILENCER)$$(CXX) $$(LDFLAGS) -o $$@ obj/$(OBJDIR)/tests/$(1).o $$(LDLIBS)
|
||||
|
||||
obj/$(OBJDIR)/tests/$(1).o: src/tests/$(1).cpp | $$$$(@D)
|
||||
$(call colorize,36,C++,92,Compiling $$@)
|
||||
$(SILENCER)$$(CXX) $$(CPPFLAGS) -Isrc/tests -Isrc $$(CXXFLAGS) -c src/tests/$(1).cpp -o $$@
|
||||
endef
|
||||
|
||||
$(eval $(call compile_wrapperhelper_c,,cstring,cstring))
|
||||
$(eval $(call compile_wrapperhelper_c,,generator,generator))
|
||||
$(eval $(call compile_wrapperhelper_c,,lang,lang))
|
||||
$(eval $(call compile_wrapperhelper_c,,main,main))
|
||||
$(eval $(call compile_wrapperhelper_c,,parse,parse))
|
||||
$(eval $(call compile_wrapperhelper_c,,prepare,prepare))
|
||||
$(eval $(call compile_wrapperhelper_c,,preproc,preproc))
|
||||
$(eval $(call compile_wrapperhelper_c,,vector,vector))
|
||||
$(call wrapperhelper_o,,preproc,preproc): CFLAGS+= -fno-analyzer
|
||||
$(call wrapperhelper_o,,parse,parse): CFLAGS+= -fno-analyzer
|
||||
|
||||
#$(eval $(call compile_test_cxx,core/number))
|
||||
|
||||
bin/wrapperhelper: $$(OBJLIST_wrapperhelper) | $$(@D)
|
||||
$(call colorize,95,LD ,92,Linking $@)
|
||||
$(SILENCER)$(CXX) $(LDFLAGS) -o $@ $(OBJLIST_wrapperhelper) $(LDLIBS)
|
||||
|
||||
wrapperhelper: bin/wrapperhelper
|
||||
alltests: $(TESTS:%=tests/%)
|
||||
.PHONY: wrapperhelper alltests
|
||||
|
||||
all: wrapperhelper alltests
|
||||
|
||||
clean:
|
||||
$(call remove,$(OBJLIST))
|
||||
$(call remove,bin/wrapperhelper)
|
||||
$(call remove,$(TESTS:%=obj/$(OBJDIR)/tests/%.o))
|
||||
$(call remove,$(TESTS:%=tests/%))
|
||||
.PHONY: clean
|
||||
distclean:
|
||||
$(call remove,makedir)
|
||||
$(call remove,obj)
|
||||
$(call remove,bin tests)
|
||||
.PHONY: distclean
|
||||
|
||||
sanitize/help:
|
||||
@echo "Sanitizers:"
|
||||
@echo "- address (removes leak)"
|
||||
@echo "- leak (removes address)"
|
||||
@echo "- undefined behavior"
|
||||
@echo ""
|
||||
@echo "Currently active options:"
|
||||
@[ $(ASAN_ON) -eq 0 ] || echo "- address"
|
||||
@[ $(LSAN_ON) -eq 0 ] || echo "- leak"
|
||||
@[ $(USAN_ON) -eq 0 ] || echo "- undefined behavior"
|
||||
sanitize/address:
|
||||
@[ $(ASAN_ON) -eq 0 ] && echo "Not sanitizing address" || echo "Sanitizing address"
|
||||
sanitize/leak:
|
||||
@[ $(LSAN_ON) -eq 0 ] && echo "Not sanitizing leak" || echo "Sanitizing leak"
|
||||
sanitize/undefined:
|
||||
@[ $(USAN_ON) -eq 0 ] && echo "Not sanitizing undefined behavior" || echo "Sanitizing undefined behavior"
|
||||
sanitize/address/on:
|
||||
$(SILENCER)touch sanaddress
|
||||
$(SILENCER)$(RM) sanleak
|
||||
sanitize/leak/on:
|
||||
$(SILENCER)touch sanleak
|
||||
$(SILENCER)$(RM) sanaddress
|
||||
sanitize/undefined/on:
|
||||
$(SILENCER)touch sanundefined
|
||||
sanitize/address/off:
|
||||
$(SILENCER)$(RM) sanaddress
|
||||
sanitize/leak/off:
|
||||
$(SILENCER)$(RM) sanleak
|
||||
sanitize/undefined/off:
|
||||
$(SILENCER)$(RM) sanundefined
|
||||
.PHONY: sanitize/address sanitize/leak sanitize/undefined
|
||||
.PHONY: sanitize/address/on sanitize/leak/on sanitize/undefined/on
|
||||
.PHONY: sanitize/address/off sanitize/leak/off sanitize/undefined/off
|
||||
|
||||
tree:
|
||||
@tree src
|
||||
.PHONY: tree
|
||||
|
||||
.DELETE_ON_ERROR:
|
@ -1,99 +1,122 @@
|
||||
# Wrapper helper
|
||||
|
||||
**WARNING: There are still many problems with this tool. Please do NOT submit code generated directly by the tool, you should only use it as a preliminary reference.**
|
||||
This folder is semi-independent from the parent project (`box64`). This sub-project aims to (partially) automating the generation of the private headers in `src/wrapped`. This is, however, still a work-in-progress and in alpha.
|
||||
|
||||
As such, **this sub-project is mainly aimed at people who know how to read code and are familiar with the wrapped libraries part of `box64`**.
|
||||
|
||||
This tool is based on libclangtooling.
|
||||
## Licensing
|
||||
|
||||
It parses the AST of the library header files, generating the required structures of the wrapping library, including:
|
||||
- structure definitions,
|
||||
- export function signatures,
|
||||
- callback function wrapping,
|
||||
etc. Of course, this cannot completely automate everything, it can only be used as a reference.
|
||||
This program is under the MIT license. However, some system header files under the LGPL license (copied from a GNU libc Arch Linux installation) have been adapted into the `include-fixed` folder; these files are not copied into the output and simply serve as data. As such, I believe this falls under fair use, and does not lead to the output of this program (used in the parent `box64` project) being under the (L)GPL license.
|
||||
|
||||
At the same time, this tool is also quite rough, and may even have errors.
|
||||
## Compiling
|
||||
|
||||
## Build
|
||||
You need a C compiler and GNU Make. No library is required.
|
||||
|
||||
```
|
||||
sudo apt install libclang-14-dev
|
||||
cd wrapperhelper
|
||||
mkdir build; cd build; cmake ..
|
||||
make
|
||||
Go to this folder, then run the `make` command. This will produce a binary called `bin/wrapperhelper`.
|
||||
|
||||
This project has been compiled and tested with `GCC 14.2.1 20240805` on an `x86_64` machine, with no warning emitted.
|
||||
|
||||
You may also use the `make clean` and `make distclean` commands to remove output files (`clean`) and directories (`distclean`).
|
||||
|
||||
## Usage
|
||||
|
||||
To use the wrapper helper, run the following command in the folder containing this `README.md`:
|
||||
```sh
|
||||
bin/wrapperhelper "path_to_support_file" "path_to_private.h" "path_to_private.h"
|
||||
```
|
||||
|
||||
## Usage:
|
||||
The first file is a `C` file containing every declaration required. The second file is the "requests" input. The third file is the output file, which may be a different file.
|
||||
|
||||
helper <filename> <libname> [guest_triple] [host_triple] -- <clang_flags>
|
||||
<filename> : set the header file to be parsed
|
||||
<libname> : set libname required for wrapping func
|
||||
[guest_triple]: set guest triple: can be arm32/arm64/x86/x64, default is x64
|
||||
[host_triple] : set host triple: can be arm32/arm64/x86/x64, default is arm64
|
||||
-- : mandatory
|
||||
<clang_flags> : extra compiler flags
|
||||
|
||||
### Usage example:
|
||||
|
||||
`./helper /usr/include/jpeglib.h libjpeg x64 arm64 -- -I /usr/lib/gcc/x86_*/12.2.0/include --include /usr/lib/gcc/x86_*/12.2.0/include/stddef.h --include /usr/include/stdio.h`
|
||||
|
||||
You would see an output similar to the files `src/wrapped/wrappedlibjpeg.c` and `src/wrapped/wrappedlibjpeg_private.h`, should they exist.
|
||||
|
||||
If there are multiple header files to process, write them into a custom header file as input.
|
||||
|
||||
### Output sample
|
||||
|
||||
Using the command above, we get the following (trimmed) files:
|
||||
|
||||
In `wrappedlibjpeg_private.h`:
|
||||
The support file may contain pragma declarations of the form
|
||||
```c
|
||||
...
|
||||
GO(jpeg_quality_scaling, iFi)
|
||||
...
|
||||
GOM(jpeg_destroy, vFEp)
|
||||
...
|
||||
#pragma wrappers explicit_simple TYPE
|
||||
```
|
||||
where `TYPE` is a `typedef` to a structure. This marks the structure pointed to by `TYPE` as "simple", which means that functions taking such structures are not required to be `GOM`-like.
|
||||
|
||||
In `wrappedlibjpeg.c`:
|
||||
System headers included (directly or indirectly) by the support file are overriden by the files in `include-fixed`.
|
||||
|
||||
The first three lines of the input are ignored.
|
||||
|
||||
A "request" is a structure containing an object name and, eventually, a default value (`GO`, `GO2` with type `vFiV` to function `xxx`, `DATA`...) and/or a "solved" value (which is similar, but deduced from the support file).
|
||||
|
||||
Valid requests (in the reference file) are:
|
||||
```c
|
||||
...
|
||||
typedef struct jpeg_source_mgr {
|
||||
void *next_input_byte;
|
||||
unsigned long bytes_in_buffer;
|
||||
vFp_t init_source;
|
||||
iFp_t fill_input_buffer;
|
||||
vFpI_t skip_input_data;
|
||||
iFpi_t resync_to_restart;
|
||||
vFp_t term_source;
|
||||
} jpeg_source_mgr, *jpeg_source_mgr_ptr;
|
||||
...
|
||||
#define GO(A) \
|
||||
static uintptr_t my_term_source_fct_##A = 0; \
|
||||
void my_term_source_##A(struct jpeg_decompress_struct * a0) { \
|
||||
return RunFunction(my_context, my_term_source_fct_##A, 1, a0); \
|
||||
}
|
||||
SUPER()
|
||||
#undef GO
|
||||
static void* findterm_sourceFct(void* fct) {
|
||||
if(!fct) return fct;
|
||||
if(GetNativeFnc((uintptr_t)fct)) return GetNativeFnc((uintptr_t)fct);
|
||||
#define GO(A) if(my_term_source_fct_##A == (uintptr_t)fct) return my_term_source_##A;}
|
||||
SUPER()
|
||||
#undef GO
|
||||
#define GO(A) if(my_term_source_fct_##A == 0) {my_term_source_fct_##A = (uintptr_t)fct;return my_term_source_##A;}
|
||||
SUPER()
|
||||
#undef GO
|
||||
return NULL;
|
||||
}
|
||||
...
|
||||
EXPORT int my_jpeg_quality_scaling(void *emu, int quality) {
|
||||
libjpeg_my_t *my = (libjpeg_my_t*)my_lib->priv.w.p2;
|
||||
my->jpeg_quality_scaling(quality);
|
||||
}
|
||||
...
|
||||
EXPORT void my_jpeg_destroy(void *emu, struct jpeg_common_struct * cinfo) {
|
||||
// WARN: This function's arg has a structure ptr which is special, may need to wrap it for the host
|
||||
libjpeg_my_t *my = (libjpeg_my_t*)my_lib->priv.w.p2;
|
||||
my->jpeg_destroy(cinfo);
|
||||
}
|
||||
...
|
||||
{GO/GOM/GOW/GOWM} ( name , type )
|
||||
{GOD/GO2/GOWD/GOW2} ( name , type , name )
|
||||
// {GO/GOM/GOW/GOWM} ( name ,
|
||||
// {GO/GOM/GOW/GOWM} ( name , type )
|
||||
// {GOD/GO2/GOWD/GOW2} ( name ,
|
||||
// {GOD/GO2/GOWD/GOW2} ( name , type , name )
|
||||
DATA[V/B/M] ( name , int )
|
||||
// DATA[V/B/M] ( name ,
|
||||
// DATA[V/B/M] ( name , int )
|
||||
```
|
||||
(where `{A/B}` means `A` or `B` and `[A/B]` means `A`, `B` or nothing). All other comments are ignored.
|
||||
|
||||
If you want to explore the output of the different stages of the helper, you can use the following forms:
|
||||
```sh
|
||||
bin/wrapperhelper --prepare "path_to_support_file" # (1)
|
||||
bin/wrapperhelper --preproc "path_to_support_file" # (2)
|
||||
bin/wrapperhelper --proc "path_to_support_file" # (3)
|
||||
bin/wrapperhelper "path_to_support_file" # (3) as well
|
||||
```
|
||||
1. This form outputs the list of preprocessor tokens (the "post-prepare" phase).
|
||||
2. This form outputs the list of processor tokens (the "post-preprocessor" phase).
|
||||
3. This form outputs the list of constants, type definitions, structure definitions, and declarations (the "post-processor" phase).
|
||||
|
||||
### Example
|
||||
|
||||
To remake the `wrappedlibc_private.h` file, use the following command:
|
||||
```sh
|
||||
bin/wrapperhelper example-libc.h ../src/wrapped/wrappedlibc_private.h ../src/wrapped/wrappedlibc_private.h
|
||||
```
|
||||
This will emit a few marnings and (non-fatal) errors, then write the result directly in `wrappedlibc_private.h`.
|
||||
|
||||
## Maintaining
|
||||
|
||||
All of the source code is included in the `src` folder.
|
||||
|
||||
The `main` function is in `main.c`.
|
||||
|
||||
The first phase of compilation (steps 1-3 and a part of step 5 of the translation phases) is implemented in `prepare.c`.
|
||||
|
||||
The second phase of compilation (steps 4 and 6) is implemented in `preproc.c`.
|
||||
|
||||
The third phase of compilation (step 7) is implemented in `parse.c`, though no actual parsing of function definitions takes place.
|
||||
|
||||
The reading and writing of the `_private.h` files is implemented in `generator.c`.
|
||||
|
||||
## Known issues
|
||||
|
||||
This project only works for `box64`; more work is required for this to be compatible with `box32`.
|
||||
|
||||
Only native structures are read. This means that the current version of `wrapperhelper` does not detect an issue when a structure has different members or alignments in two different architectures.
|
||||
|
||||
The include paths are hard-coded. There should instead be a structure passed around containing all arch-dependent informations.
|
||||
|
||||
Similarly, structure letters (i.e. `S` for `struct _IO_FILE*`) are hard-coded. A pragma should be used instead (`#pragma wrappers type_letter IDENT type-name`, parsed as `PTOK_PRAGMA: Type is letter: <char>`, followed by `type-name`, followed by `PTOK_NEWLINE`).
|
||||
|
||||
Conditionals in the `_private.h` files are ignored, except for taking only the negative branch. Manual cleanup of the output is required.
|
||||
|
||||
Line numbers are missing entirely. For most errors, finding the corresponding file is difficult (though possible).
|
||||
|
||||
Phase 5 is partially implemented, but could be greatly improved.
|
||||
|
||||
The following features are missing from the generator:
|
||||
- Large structures as a parameter
|
||||
- Large structure as a return type (more than 16 bytes)
|
||||
- Atomic types
|
||||
|
||||
The following features are missing from the preprocessor:
|
||||
- Error display (`#error` will stop the compilation, but a generic error message will be written)
|
||||
- General token concatenation (though the concatenation of two `PTOK_IDENT` works without issue)
|
||||
- Stringify
|
||||
- Skipped unexpected token warnings
|
||||
- Proper out-of-memory error handling
|
||||
|
||||
The following features are missing from the parser:
|
||||
- `inline` and `_Noreturn`
|
||||
- `_Atomic(type-name)`
|
||||
- `_Alignas(type-name)` and `_Alignas(constant-expression)`
|
||||
- `(type-name){initializer-list}`
|
||||
- Function definitions are ignored, not parsed
|
||||
|
@ -1,189 +0,0 @@
|
||||
#pragma once
|
||||
#include <clang/AST/ASTConsumer.h>
|
||||
#include <clang/AST/Attr.h>
|
||||
#include <clang/AST/Decl.h>
|
||||
#include <clang/AST/Type.h>
|
||||
#include <clang/Tooling/Tooling.h>
|
||||
#include <clang/Tooling/CompilationDatabase.h>
|
||||
#include <clang/AST/RecursiveASTVisitor.h>
|
||||
#include <clang/Frontend/FrontendAction.h>
|
||||
#include <clang/Frontend/CompilerInstance.h>
|
||||
#include <clang/Tooling/CommonOptionsParser.h>
|
||||
|
||||
#include <ios>
|
||||
#include <llvm/Support/Casting.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
|
||||
#include "gen.h"
|
||||
#include "utils.h"
|
||||
|
||||
static void ParseParameter(clang::ASTContext* AST, WrapperGenerator* Gen, clang::QualType ParmType, FuncInfo* Func) {
|
||||
using namespace clang;
|
||||
(void)AST; (void)Func;
|
||||
if (ParmType->isFunctionPointerType()) {
|
||||
auto ProtoType = ParmType->getPointeeType()->getAs<FunctionProtoType>();
|
||||
for (unsigned i = 0; i < ProtoType->getNumParams(); i++) {
|
||||
ParseParameter(AST, Gen, ProtoType->getParamType(i), Func);
|
||||
}
|
||||
} else if (ParmType->isPointerType()) {
|
||||
auto PointeeType = ParmType->getPointeeType();
|
||||
if (PointeeType->isRecordType()) {
|
||||
if (Gen->records.find(StripTypedef(PointeeType)) == Gen->records.end()) {
|
||||
auto Record = &Gen->records[StripTypedef(PointeeType)];
|
||||
if (PointeeType->isUnionType()) {
|
||||
Record->is_union = true;
|
||||
}
|
||||
Record->type = StripTypedef(PointeeType);
|
||||
Record->decl = PointeeType->getAs<RecordType>()->getDecl();
|
||||
Record->type_name = Record->decl->getIdentifier() ? Record->decl->getIdentifier()->getName().str() : "<null identifier>";
|
||||
}
|
||||
} else if (PointeeType->isPointerType()) {
|
||||
PointeeType = PointeeType->getPointeeType();
|
||||
if (PointeeType->isRecordType()) {
|
||||
if (Gen->records.find(StripTypedef(PointeeType)) == Gen->records.end()) {
|
||||
auto Record = &Gen->records[StripTypedef(PointeeType)];
|
||||
if (PointeeType->isUnionType()) {
|
||||
Record->is_union = true;
|
||||
}
|
||||
|
||||
Record->type = StripTypedef(PointeeType);
|
||||
Record->decl = PointeeType->getAs<RecordType>()->getDecl();
|
||||
Record->type_name = Record->decl->getIdentifier() ? Record->decl->getIdentifier()->getName().str() : "<null identifier>";
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (ParmType->isRecordType()) {
|
||||
if (Gen->records.find(StripTypedef(ParmType)) == Gen->records.end()) {
|
||||
auto Record = &Gen->records[StripTypedef(ParmType)];
|
||||
if (ParmType->isUnionType()) {
|
||||
Record->is_union = true;
|
||||
}
|
||||
Record->type = StripTypedef(ParmType);
|
||||
Record->decl = ParmType->getAs<RecordType>()->getDecl();
|
||||
Record->type_name = Record->decl->getIdentifier() ? Record->decl->getIdentifier()->getName().str() : "<null identifier>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ParseFunction(clang::ASTContext* AST, WrapperGenerator* Gen, clang::FunctionDecl* Decl) {
|
||||
using namespace clang;
|
||||
auto Type = Decl->getType().getTypePtr();
|
||||
auto FuncInfo = &Gen->funcs[Type];
|
||||
FuncInfo->type = Type;
|
||||
FuncInfo->func_name = Decl->getNameAsString();
|
||||
FuncInfo->decl = Decl;
|
||||
FuncInfo->callback_args.resize(Decl->getNumParams());
|
||||
if (Decl->getAttr<WeakRefAttr>()) {
|
||||
FuncInfo->is_weak = true;
|
||||
}
|
||||
if (Decl->isVariadic()) {
|
||||
FuncInfo->is_variadaic = true;
|
||||
}
|
||||
for (unsigned i = 0; i < Decl->getNumParams(); i++) {
|
||||
auto ParmDecl = Decl->getParamDecl(i);
|
||||
if (ParmDecl->getType()->isFunctionPointerType()) {
|
||||
FuncInfo->callback_args[i] = ParmDecl->getType().getTypePtr();
|
||||
FuncInfo->has_callback_arg = true;
|
||||
} else {
|
||||
FuncInfo->callback_args[i] = nullptr;
|
||||
}
|
||||
ParseParameter(AST, Gen, ParmDecl->getType(), FuncInfo);
|
||||
}
|
||||
}
|
||||
|
||||
class MyASTVisitor : public clang::RecursiveASTVisitor<MyASTVisitor> {
|
||||
public:
|
||||
MyASTVisitor(clang::ASTContext* ctx) : Ctx(ctx) {}
|
||||
MyASTVisitor(clang::ASTContext* ctx, WrapperGenerator* gen) : Ctx(ctx), Gen(gen) {}
|
||||
|
||||
bool VisitFunctionDecl(clang::FunctionDecl* Decl) {
|
||||
ParseFunction(Ctx, Gen, Decl);
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
clang::ASTContext* Ctx;
|
||||
WrapperGenerator* Gen;
|
||||
};
|
||||
|
||||
class MyASTConsumer : public clang::ASTConsumer {
|
||||
public:
|
||||
MyASTConsumer(clang::ASTContext* Context, const std::string& libname, const std::string& host_triple, const std::string& guest_triple)
|
||||
: Visitor(Context, &Generator) {
|
||||
Generator.Init(libname, host_triple, guest_triple);
|
||||
}
|
||||
void HandleTranslationUnit(clang::ASTContext &Ctx) override {
|
||||
Visitor.TraverseDecl(Ctx.getTranslationUnitDecl());
|
||||
std::cout << "--------------- Libclangtooling parse complete -----------------\n";
|
||||
Generator.Prepare(&Ctx);
|
||||
std::cout << "--------------- Generator prepare complete -----------------\n";
|
||||
std::ofstream FuncDeclFile("wrapped" + Generator.libname + "_private.h", std::ios::out);
|
||||
FuncDeclFile << Generator.GenFuncDeclare(&Ctx);
|
||||
FuncDeclFile.close();
|
||||
std::ofstream FuncDefineFile("wrapped" + Generator.libname + ".c", std::ios::out);
|
||||
FuncDefineFile << "#include <stdio.h>\n"
|
||||
"#include <stdlib.h>\n"
|
||||
"#include <string.h>\n"
|
||||
"#define _GNU_SOURCE /* See feature_test_macros(7) */\n"
|
||||
"#include <dlfcn.h>\n"
|
||||
"\n"
|
||||
"#include \"wrappedlibs.h\"\n"
|
||||
"\n"
|
||||
"#include \"debug.h\"\n"
|
||||
"#include \"wrapper.h\"\n"
|
||||
"#include \"bridge.h\"\n"
|
||||
"#include \"x64emu.h\"\n"
|
||||
"#include \"box64context.h\"\n"
|
||||
"\n"
|
||||
"const char* " + Generator.libname + "Name = \"" + Generator.libname + "\";\n"
|
||||
"#define LIBNAME " + Generator.libname + "\n"
|
||||
"\n"
|
||||
"#define ADDED_FUNCTIONS() \\\n"
|
||||
"\n"
|
||||
"#include \"generated/wrapped" + Generator.libname + "types.h\"\n";
|
||||
FuncDefineFile << Generator.GenRecordDeclare(&Ctx);
|
||||
FuncDefineFile << Generator.GenRecordConvert(&Ctx);
|
||||
FuncDefineFile << Generator.GenCallbackWrap(&Ctx);
|
||||
FuncDefineFile << Generator.GenFuncDefine(&Ctx);
|
||||
FuncDefineFile.close();
|
||||
std::cout << "--------------- Generator gen complete -----------------\n";
|
||||
}
|
||||
private:
|
||||
MyASTVisitor Visitor;
|
||||
WrapperGenerator Generator;
|
||||
};
|
||||
|
||||
class MyGenAction : public clang::ASTFrontendAction {
|
||||
public:
|
||||
MyGenAction(const std::string& libname, const std::string& host_triple, const std::string& guest_triple) :
|
||||
libname(libname), host_triple(host_triple), guest_triple(guest_triple) {}
|
||||
std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(clang::CompilerInstance& Compiler, clang::StringRef file) override {
|
||||
(void)file;
|
||||
return std::make_unique<MyASTConsumer>(&Compiler.getASTContext(), libname, host_triple, guest_triple);
|
||||
}
|
||||
private:
|
||||
std::string libname;
|
||||
std::string host_triple;
|
||||
std::string guest_triple;
|
||||
};
|
||||
|
||||
class MyFrontendActionFactory : public clang::tooling::FrontendActionFactory {
|
||||
public:
|
||||
MyFrontendActionFactory(const std::string& libname, const std::string& host_triple, const std::string& guest_triple) :
|
||||
libname(libname), host_triple(host_triple), guest_triple(guest_triple) {}
|
||||
private:
|
||||
std::unique_ptr<clang::FrontendAction> create() override {
|
||||
return std::make_unique<MyGenAction>(libname, host_triple, guest_triple);
|
||||
}
|
||||
private:
|
||||
std::string libname;
|
||||
std::string host_triple;
|
||||
std::string guest_triple;
|
||||
};
|
170
wrapperhelper/example-libc.h
Normal file
170
wrapperhelper/example-libc.h
Normal file
@ -0,0 +1,170 @@
|
||||
#define __x86_64__
|
||||
#define __WCHAR_MAX__ 2147483647
|
||||
#define __WCHAR_MIN__ (-__WCHAR_MAX - 1)
|
||||
#define _GNU_SOURCE 1
|
||||
#define __USE_MISC 1
|
||||
#define PORTMAP
|
||||
#define __WORDSIZE 64
|
||||
|
||||
// Based on /usr/include/clang/Basic/TokenKinds.def
|
||||
// Alternate spelling for various tokens. There are GCC extensions in all
|
||||
// languages, but should not be disabled in strict conformance mode.
|
||||
#define __alignof__ __alignof
|
||||
#define __asm asm
|
||||
#define __asm__ asm
|
||||
#define __complex _Complex
|
||||
#define __complex__ _Complex
|
||||
#define __const const
|
||||
#define __const__ const
|
||||
#define __decltype decltype
|
||||
#define __imag__ __imag
|
||||
#define __inline inline
|
||||
#define __inline__ inline
|
||||
#define __nullptr nullptr
|
||||
#define __real__ __real
|
||||
#define __restrict restrict
|
||||
#define __restrict__ restrict
|
||||
#define __signed signed
|
||||
#define __signed__ signed
|
||||
#define __typeof typeof
|
||||
#define __typeof__ typeof
|
||||
#define __volatile volatile
|
||||
#define __volatile__ volatile
|
||||
|
||||
typedef __int128 __int128_t;
|
||||
typedef unsigned __int128 __uint128_t;
|
||||
|
||||
// TODO
|
||||
#define inline
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <aliases.h>
|
||||
#include <argp.h>
|
||||
#include <argz.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <arpa/nameser.h>
|
||||
#include <asm/prctl.h>
|
||||
#include <complex.h>
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
#include <envz.h>
|
||||
#include <err.h>
|
||||
#include <error.h>
|
||||
#include <execinfo.h>
|
||||
#include <event.h>
|
||||
#include <fcntl.h>
|
||||
#include <fmtmsg.h>
|
||||
#include <fnmatch.h>
|
||||
#include <fstab.h>
|
||||
#include <fts.h>
|
||||
#include <ftw.h>
|
||||
#include <gconv.h>
|
||||
#include <glob.h>
|
||||
#include <gnu/libc-version.h>
|
||||
#include <grp.h>
|
||||
#include <gshadow.h>
|
||||
#include <iconv.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <inttypes.h>
|
||||
#include <langinfo.h>
|
||||
#include <libgen.h>
|
||||
#include <libintl.h>
|
||||
#include <link.h>
|
||||
#include <linux/module.h>
|
||||
#include <locale.h>
|
||||
#include <math.h>
|
||||
#include <malloc.h>
|
||||
#include <mcheck.h>
|
||||
#include <mntent.h>
|
||||
#include <monetary.h>
|
||||
#include <netdb.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/ether.h>
|
||||
#include <netinet/in.h>
|
||||
#include <nl_types.h>
|
||||
#include <obstack.h>
|
||||
#include <poll.h>
|
||||
#include <printf.h>
|
||||
#include <pwd.h>
|
||||
#include <regex.h>
|
||||
#include <resolv.h>
|
||||
#include <rpc/auth.h>
|
||||
#include <rpc/des_crypt.h>
|
||||
#include <rpc/key_prot.h>
|
||||
#include <rpc/rpc.h>
|
||||
#include <sched.h>
|
||||
#include <search.h>
|
||||
#include <setjmp.h>
|
||||
#include <shadow.h>
|
||||
#include <signal.h>
|
||||
#include <spawn.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/auxv.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include <sys/fanotify.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/fsuid.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/io.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/klog.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/msg.h>
|
||||
#include <sys/personality.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/profil.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/quota.h>
|
||||
#include <sys/random.h>
|
||||
#include <sys/reboot.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/sem.h>
|
||||
#include <sys/sendfile.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/signal.h>
|
||||
#include <sys/signalfd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statfs.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <sys/swap.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/timeb.h>
|
||||
#include <sys/timerfd.h>
|
||||
#include <sys/times.h>
|
||||
#include <sys/timex.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/vfs.h>
|
||||
#include <sys/xattr.h>
|
||||
#include <syslog.h>
|
||||
#include <termios.h>
|
||||
#include <time.h>
|
||||
#include <threads.h>
|
||||
#include <ttyent.h>
|
||||
#include <uchar.h>
|
||||
#include <ucontext.h>
|
||||
#include <ulimit.h>
|
||||
#include <unistd.h>
|
||||
#include <unistdio.h>
|
||||
#include <utime.h>
|
||||
#include <utmp.h>
|
||||
#include <utmpx.h>
|
||||
#include <wait.h>
|
||||
#include <wchar.h>
|
||||
#include <wctype.h>
|
||||
#include <wordexp.h>
|
||||
|
||||
#pragma wrappers explicit_simple FTS
|
||||
#pragma wrappers explicit_simple FTS64
|
||||
#pragma wrappers explicit_simple glob_t
|
||||
#pragma wrappers explicit_simple glob64_t
|
File diff suppressed because it is too large
Load Diff
@ -1,144 +0,0 @@
|
||||
#pragma once
|
||||
#include <clang/AST/ASTContext.h>
|
||||
#include <clang/AST/Type.h>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
struct FuncDefinition {
|
||||
std::vector<const clang::Type*> arg_types;
|
||||
std::vector<std::string> arg_types_str;
|
||||
std::vector<std::string> arg_names;
|
||||
const clang::Type* ret;
|
||||
std::string ret_str;
|
||||
int arg_size;
|
||||
bool is_variadaic;
|
||||
};
|
||||
|
||||
struct FuncInfo {
|
||||
const clang::Type* type;
|
||||
clang::FunctionDecl* decl;
|
||||
std::string func_name;
|
||||
bool is_weak;
|
||||
bool is_variadaic;
|
||||
bool has_special_arg;
|
||||
bool has_special_ret;
|
||||
bool has_callback_arg;
|
||||
std::vector<const clang::Type*> callback_args;
|
||||
};
|
||||
|
||||
struct RecordInfo {
|
||||
const clang::Type* type;
|
||||
clang::RecordDecl* decl;
|
||||
std::string type_name;
|
||||
bool is_union;
|
||||
bool is_special;
|
||||
|
||||
uint64_t guest_size;
|
||||
uint64_t host_size;
|
||||
std::vector<const clang::Type*> callback_fields;
|
||||
};
|
||||
|
||||
struct ObjectInfo {
|
||||
const clang::Type* type;
|
||||
std::string object_name;
|
||||
};
|
||||
|
||||
struct WrapperGenerator {
|
||||
|
||||
void Init(const std::string& libname, const std::string& host_triple, const std::string& guest_triple) {
|
||||
this->host_triple = host_triple;
|
||||
this->guest_triple = guest_triple;
|
||||
this->libname = libname;
|
||||
this->my_lib_type = libname + "_my_t";
|
||||
this->my_lib = "my_lib";
|
||||
}
|
||||
|
||||
void Prepare(clang::ASTContext* Ctx);
|
||||
|
||||
std::string GenCallbackTypeDefs(clang::ASTContext* Ctx);
|
||||
|
||||
std::string GenFuncDeclare(clang::ASTContext* Ctx) {
|
||||
std::string res{};
|
||||
for (const auto& func : funcs) {
|
||||
res += GenDeclare(Ctx, func.second);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
std::string GenRecordDeclare(clang::ASTContext* Ctx) {
|
||||
std::string res{};
|
||||
for (const auto& st : records) {
|
||||
if (st.second.host_size == st.second.guest_size)
|
||||
res += GenDeclare(Ctx, st.second);
|
||||
else {
|
||||
res += GenDeclareDiffTriple(Ctx, st.second, guest_triple, host_triple);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string GenFuncDefine(clang::ASTContext* Ctx) {
|
||||
std::string res{};
|
||||
for (const auto& func : funcs) {
|
||||
res += GenDefine(Ctx, func.second);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string GenCallbackWrap(clang::ASTContext* Ctx) {
|
||||
std::string res{};
|
||||
for (const auto& func : funcs) {
|
||||
res += GenCallbackWrap(Ctx, func.second);
|
||||
}
|
||||
for (const auto& st : records) {
|
||||
res += GenCallbackWrap(Ctx, st.second);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string GenRecordConvert(clang::ASTContext* Ctx) {
|
||||
(void)Ctx;
|
||||
std::string res;
|
||||
for (const auto& record : records) {
|
||||
if (record.second.host_size != record.second.guest_size) {
|
||||
res += GenRecordConvert(record.second);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::map<const clang::Type*, FuncInfo> funcs;
|
||||
std::map<const clang::Type*, RecordInfo> records;
|
||||
std::map<const clang::Type*, ObjectInfo> objects;
|
||||
|
||||
std::map<const clang::Type*, std::string> callbacks;
|
||||
|
||||
std::string host_triple;
|
||||
std::string guest_triple;
|
||||
std::string libname;
|
||||
std::string my_lib_type;
|
||||
std::string my_lib;
|
||||
private:
|
||||
std::string GenRecordConvert(const RecordInfo& Record);
|
||||
std::string GenDeclare(clang::ASTContext* Ctx, const FuncInfo& Func);
|
||||
std::string GenDefine(clang::ASTContext* Ctx, const FuncInfo& Func);
|
||||
std::string GenCallbackWrap(clang::ASTContext* Ctx, const FuncInfo& Func);
|
||||
std::string GenDeclareDiffTriple(clang::ASTContext* Ctx, const RecordInfo& Record, const std::string& GuestTriple, const std::string& HostTriple);
|
||||
std::string GenDeclare(clang::ASTContext* Ctx, const RecordInfo& Struct);
|
||||
std::string GenCallbackWrap(clang::ASTContext* Ctx, const RecordInfo& Struct);
|
||||
|
||||
void ParseRecordRecursive(clang::ASTContext* Ctx, const clang::Type* Type, bool& Special, std::set<const clang::Type*>& Visited);
|
||||
std::string TypeStringify(const clang::Type* Type, clang::FieldDecl* FieldDecl, clang::ParmVarDecl* ParmDecl, std::string& PreDecl, std::string indent = "", std::string Name = "");
|
||||
std::string SimpleTypeStringify(const clang::Type* Type, clang::FieldDecl* FieldDecl, clang::ParmVarDecl* ParmDecl, std::string indent = "", std::string Name = "");
|
||||
std::string AnonRecordDecl(const clang::RecordType* Type, std::string& PreDecl, std::string indent);
|
||||
std::string SimpleAnonRecordDecl(const clang::RecordType* Type, std::string indent);
|
||||
FuncDefinition GetFuncDefinition(const clang::Type* Type);
|
||||
FuncDefinition GetFuncDefinition(clang::FunctionDecl* Decl);
|
||||
uint64_t GetRecordSize(const clang::Type* Type, const std::string& Triple);
|
||||
std::vector<uint64_t> GetRecordFieldOffDiff(const clang::Type* Type, const std::string& GuestTriple, const std::string& HostTriple, std::vector<uint64_t>& GuestFieldOff, std::vector<uint64_t>& HostFieldOff);
|
||||
clang::CharUnits::QuantityType GetRecordAlign(const clang::Type* Type, const std::string& Triple);
|
||||
|
||||
std::string GetFuncSig(clang::ASTContext* CTX, const FuncInfo& Decl);
|
||||
std::string GetFuncSig(clang::ASTContext* CTX, const clang::Type* Type);
|
||||
};
|
32
wrapperhelper/include-fixed/bits/stdint-intn.h
Normal file
32
wrapperhelper/include-fixed/bits/stdint-intn.h
Normal file
@ -0,0 +1,32 @@
|
||||
/* Define intN_t types.
|
||||
Copyright (C) 2017-2024 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
This file has been adapted to work with the 'wrapperhelper' project on the 09/06/2024.
|
||||
*/
|
||||
|
||||
#ifndef _BITS_STDINT_INTN_H
|
||||
#define _BITS_STDINT_INTN_H 1
|
||||
|
||||
#include <bits/types.h>
|
||||
|
||||
typedef __int8_t int8_t;
|
||||
typedef __int16_t int16_t;
|
||||
typedef __int32_t int32_t;
|
||||
typedef __int64_t int64_t;
|
||||
|
||||
#endif /* bits/stdint-intn.h */
|
39
wrapperhelper/include-fixed/bits/stdint-least.h
Normal file
39
wrapperhelper/include-fixed/bits/stdint-least.h
Normal file
@ -0,0 +1,39 @@
|
||||
/* Define int_leastN_t and uint_leastN types.
|
||||
Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
This file has been adapted to work with the 'wrapperhelper' project on the 09/06/2024.
|
||||
*/
|
||||
|
||||
#ifndef _BITS_STDINT_LEAST_H
|
||||
#define _BITS_STDINT_LEAST_H 1
|
||||
|
||||
#include <bits/types.h>
|
||||
|
||||
/* Signed. */
|
||||
typedef __int_least8_t int_least8_t;
|
||||
typedef __int_least16_t int_least16_t;
|
||||
typedef __int_least32_t int_least32_t;
|
||||
typedef __int_least64_t int_least64_t;
|
||||
|
||||
/* Unsigned. */
|
||||
typedef __uint_least8_t uint_least8_t;
|
||||
typedef __uint_least16_t uint_least16_t;
|
||||
typedef __uint_least32_t uint_least32_t;
|
||||
typedef __uint_least64_t uint_least64_t;
|
||||
|
||||
#endif /* bits/stdint-least.h */
|
32
wrapperhelper/include-fixed/bits/stdint-uintn.h
Normal file
32
wrapperhelper/include-fixed/bits/stdint-uintn.h
Normal file
@ -0,0 +1,32 @@
|
||||
/* Define uintN_t types.
|
||||
Copyright (C) 2017-2024 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
This file has been adapted to work with the 'wrapperhelper' project on the 09/06/2024.
|
||||
*/
|
||||
|
||||
#ifndef _BITS_STDINT_UINTN_H
|
||||
#define _BITS_STDINT_UINTN_H 1
|
||||
|
||||
#include <bits/types.h>
|
||||
|
||||
typedef __uint8_t uint8_t;
|
||||
typedef __uint16_t uint16_t;
|
||||
typedef __uint32_t uint32_t;
|
||||
typedef __uint64_t uint64_t;
|
||||
|
||||
#endif /* bits/stdint-uintn.h */
|
192
wrapperhelper/include-fixed/bits/types.h
Normal file
192
wrapperhelper/include-fixed/bits/types.h
Normal file
@ -0,0 +1,192 @@
|
||||
/* bits/types.h -- definitions of __*_t types underlying *_t types.
|
||||
Copyright (C) 2002-2024 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
This file has been adapted to work with the 'wrapperhelper' project on the 09/06/2024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Never include this file directly; use <sys/types.h> instead.
|
||||
*/
|
||||
|
||||
#ifndef _BITS_TYPES_H
|
||||
#define _BITS_TYPES_H 1
|
||||
|
||||
#include <features.h>
|
||||
#include <bits/wordsize.h>
|
||||
#include <bits/timesize.h>
|
||||
|
||||
/* Convenience types. */
|
||||
typedef unsigned char __u_char;
|
||||
typedef unsigned short int __u_short;
|
||||
typedef unsigned int __u_int;
|
||||
typedef unsigned long int __u_long;
|
||||
|
||||
/* Fixed-size types, underlying types depend on word size and compiler. */
|
||||
#pragma wrappers allow_ints_ext
|
||||
|
||||
/* Smallest types with at least a given width. */
|
||||
typedef __int8_t __int_least8_t;
|
||||
typedef __uint8_t __uint_least8_t;
|
||||
typedef __int16_t __int_least16_t;
|
||||
typedef __uint16_t __uint_least16_t;
|
||||
typedef __int32_t __int_least32_t;
|
||||
typedef __uint32_t __uint_least32_t;
|
||||
typedef __int64_t __int_least64_t;
|
||||
typedef __uint64_t __uint_least64_t;
|
||||
|
||||
/* quad_t is also 64 bits. */
|
||||
typedef __int64_t __quad_t;
|
||||
typedef __uint64_t __u_quad_t;
|
||||
|
||||
/* Largest integral types. */
|
||||
typedef __int64_t __intmax_t;
|
||||
typedef __uint64_t __uintmax_t;
|
||||
|
||||
|
||||
/* The machine-dependent file <bits/typesizes.h> defines __*_T_TYPE
|
||||
macros for each of the OS types we define below. The definitions
|
||||
of those macros must use the following macros for underlying types.
|
||||
We define __S<SIZE>_TYPE and __U<SIZE>_TYPE for the signed and unsigned
|
||||
variants of each of the following integer types on this machine.
|
||||
|
||||
16 -- "natural" 16-bit type (always short)
|
||||
32 -- "natural" 32-bit type (always int)
|
||||
64 -- "natural" 64-bit type (long or long long)
|
||||
LONG32 -- 32-bit type, traditionally long
|
||||
QUAD -- 64-bit type, traditionally long long
|
||||
WORD -- natural type of __WORDSIZE bits (int or long)
|
||||
LONGWORD -- type of __WORDSIZE bits, traditionally long
|
||||
|
||||
We distinguish WORD/LONGWORD, 32/LONG32, and 64/QUAD so that the
|
||||
conventional uses of `long' or `long long' type modifiers match the
|
||||
types we define, even when a less-adorned type would be the same size.
|
||||
This matters for (somewhat) portably writing printf/scanf formats for
|
||||
these types, where using the appropriate l or ll format modifiers can
|
||||
make the typedefs and the formats match up across all GNU platforms. If
|
||||
we used `long' when it's 64 bits where `long long' is expected, then the
|
||||
compiler would warn about the formats not matching the argument types,
|
||||
and the programmer changing them to shut up the compiler would break the
|
||||
program's portability.
|
||||
|
||||
Here we assume what is presently the case in all the GCC configurations
|
||||
we support: long long is always 64 bits, long is always word/address size,
|
||||
and int is always 32 bits. */
|
||||
|
||||
#define __S16_TYPE __int16_t
|
||||
#define __U16_TYPE __uint16_t
|
||||
#define __S32_TYPE __int32_t
|
||||
#define __U32_TYPE __uint32_t
|
||||
#define __SLONGWORD_TYPE long int
|
||||
#define __ULONGWORD_TYPE unsigned long int
|
||||
# define __SQUAD_TYPE __int64_t
|
||||
# define __UQUAD_TYPE __uint64_t
|
||||
# define __SWORD_TYPE long int
|
||||
# define __UWORD_TYPE unsigned long int
|
||||
# define __SLONG32_TYPE __int32_t
|
||||
# define __ULONG32_TYPE __uint32_t
|
||||
# define __S64_TYPE __int64_t
|
||||
# define __U64_TYPE __uint64_t
|
||||
# define __STD_TYPE typedef
|
||||
#include <bits/typesizes.h> /* Defines __*_T_TYPE macros. */
|
||||
#include <bits/time64.h> /* Defines __TIME*_T_TYPE macros. */
|
||||
|
||||
|
||||
__STD_TYPE __DEV_T_TYPE __dev_t; /* Type of device numbers. */
|
||||
__STD_TYPE __UID_T_TYPE __uid_t; /* Type of user identifications. */
|
||||
__STD_TYPE __GID_T_TYPE __gid_t; /* Type of group identifications. */
|
||||
__STD_TYPE __INO_T_TYPE __ino_t; /* Type of file serial numbers. */
|
||||
__STD_TYPE __INO64_T_TYPE __ino64_t; /* Type of file serial numbers (LFS).*/
|
||||
__STD_TYPE __MODE_T_TYPE __mode_t; /* Type of file attribute bitmasks. */
|
||||
__STD_TYPE __NLINK_T_TYPE __nlink_t; /* Type of file link counts. */
|
||||
__STD_TYPE __OFF_T_TYPE __off_t; /* Type of file sizes and offsets. */
|
||||
__STD_TYPE __OFF64_T_TYPE __off64_t; /* Type of file sizes and offsets (LFS). */
|
||||
__STD_TYPE __PID_T_TYPE __pid_t; /* Type of process identifications. */
|
||||
__STD_TYPE __FSID_T_TYPE __fsid_t; /* Type of file system IDs. */
|
||||
__STD_TYPE __CLOCK_T_TYPE __clock_t; /* Type of CPU usage counts. */
|
||||
__STD_TYPE __RLIM_T_TYPE __rlim_t; /* Type for resource measurement. */
|
||||
__STD_TYPE __RLIM64_T_TYPE __rlim64_t; /* Type for resource measurement (LFS). */
|
||||
__STD_TYPE __ID_T_TYPE __id_t; /* General type for IDs. */
|
||||
__STD_TYPE __TIME_T_TYPE __time_t; /* Seconds since the Epoch. */
|
||||
__STD_TYPE __USECONDS_T_TYPE __useconds_t; /* Count of microseconds. */
|
||||
__STD_TYPE __SUSECONDS_T_TYPE __suseconds_t; /* Signed count of microseconds. */
|
||||
__STD_TYPE __SUSECONDS64_T_TYPE __suseconds64_t;
|
||||
|
||||
__STD_TYPE __DADDR_T_TYPE __daddr_t; /* The type of a disk address. */
|
||||
__STD_TYPE __KEY_T_TYPE __key_t; /* Type of an IPC key. */
|
||||
|
||||
/* Clock ID used in clock and timer functions. */
|
||||
__STD_TYPE __CLOCKID_T_TYPE __clockid_t;
|
||||
|
||||
/* Timer ID returned by `timer_create'. */
|
||||
__STD_TYPE __TIMER_T_TYPE __timer_t;
|
||||
|
||||
/* Type to represent block size. */
|
||||
__STD_TYPE __BLKSIZE_T_TYPE __blksize_t;
|
||||
|
||||
/* Types from the Large File Support interface. */
|
||||
|
||||
/* Type to count number of disk blocks. */
|
||||
__STD_TYPE __BLKCNT_T_TYPE __blkcnt_t;
|
||||
__STD_TYPE __BLKCNT64_T_TYPE __blkcnt64_t;
|
||||
|
||||
/* Type to count file system blocks. */
|
||||
__STD_TYPE __FSBLKCNT_T_TYPE __fsblkcnt_t;
|
||||
__STD_TYPE __FSBLKCNT64_T_TYPE __fsblkcnt64_t;
|
||||
|
||||
/* Type to count file system nodes. */
|
||||
__STD_TYPE __FSFILCNT_T_TYPE __fsfilcnt_t;
|
||||
__STD_TYPE __FSFILCNT64_T_TYPE __fsfilcnt64_t;
|
||||
|
||||
/* Type of miscellaneous file system fields. */
|
||||
__STD_TYPE __FSWORD_T_TYPE __fsword_t;
|
||||
|
||||
__STD_TYPE __SSIZE_T_TYPE __ssize_t; /* Type of a byte count, or error. */
|
||||
|
||||
/* Signed long type used in system calls. */
|
||||
__STD_TYPE __SYSCALL_SLONG_TYPE __syscall_slong_t;
|
||||
/* Unsigned long type used in system calls. */
|
||||
__STD_TYPE __SYSCALL_ULONG_TYPE __syscall_ulong_t;
|
||||
|
||||
/* These few don't really vary by system, they always correspond
|
||||
to one of the other defined types. */
|
||||
typedef __off64_t __loff_t; /* Type of file sizes and offsets (LFS). */
|
||||
typedef char *__caddr_t;
|
||||
|
||||
/* Duplicates info from stdint.h but this is used in unistd.h. */
|
||||
__STD_TYPE __SWORD_TYPE __intptr_t;
|
||||
|
||||
/* Duplicate info from sys/socket.h. */
|
||||
__STD_TYPE __U32_TYPE __socklen_t;
|
||||
|
||||
/* C99: An integer type that can be accessed as an atomic entity,
|
||||
even in the presence of asynchronous interrupts.
|
||||
It is not currently necessary for this to be machine-specific. */
|
||||
typedef int __sig_atomic_t;
|
||||
|
||||
/* Seconds since the Epoch, visible to user code when time_t is too
|
||||
narrow only for consistency with the old way of widening too-narrow
|
||||
types. User code should never use __time64_t. */
|
||||
#if __TIMESIZE == 64 && defined __LIBC
|
||||
# define __time64_t __time_t
|
||||
#elif __TIMESIZE != 64
|
||||
__STD_TYPE __TIME64_T_TYPE __time64_t;
|
||||
#endif
|
||||
|
||||
#undef __STD_TYPE
|
||||
|
||||
#endif /* bits/types.h */
|
276
wrapperhelper/include-fixed/stdint.h
Normal file
276
wrapperhelper/include-fixed/stdint.h
Normal file
@ -0,0 +1,276 @@
|
||||
/* Copyright (C) 1997-2024 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
This file has been adapted to work with the 'wrapperhelper' project on the 09/06/2024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ISO C99: 7.18 Integer types <stdint.h>
|
||||
*/
|
||||
|
||||
#ifndef _STDINT_H
|
||||
#define _STDINT_H 1
|
||||
|
||||
#define __GLIBC_INTERNAL_STARTING_HEADER_IMPLEMENTATION
|
||||
#include <bits/libc-header-start.h>
|
||||
#include <bits/types.h>
|
||||
#include <bits/wchar.h>
|
||||
#include <bits/wordsize.h>
|
||||
|
||||
#pragma wrappers allow_ints_ext
|
||||
|
||||
/* Exact integral types. */
|
||||
|
||||
/* Signed. */
|
||||
#include <bits/stdint-intn.h>
|
||||
|
||||
/* Unsigned. */
|
||||
#include <bits/stdint-uintn.h>
|
||||
|
||||
|
||||
/* Small types. */
|
||||
#include <bits/stdint-least.h>
|
||||
|
||||
|
||||
/* Fast types. */
|
||||
|
||||
/* Signed. */
|
||||
typedef int8_t int_fast8_t;
|
||||
typedef int16_t int_fast16_t;
|
||||
typedef int32_t int_fast32_t;
|
||||
typedef int64_t int_fast64_t;
|
||||
|
||||
/* Unsigned. */
|
||||
typedef uint8_t uint_fast8_t;
|
||||
typedef uint16_t uint_fast16_t;
|
||||
typedef uint32_t uint_fast32_t;
|
||||
typedef uint64_t uint_fast64_t;
|
||||
|
||||
|
||||
/* Types for `void *' pointers. */
|
||||
# ifndef __intptr_t_defined
|
||||
typedef signed long intptr_t;
|
||||
# define __intptr_t_defined
|
||||
# endif
|
||||
typedef unsigned long uintptr_t;
|
||||
|
||||
|
||||
/* Largest integral types. */
|
||||
typedef int64_t intmax_t;
|
||||
typedef uint64_t uintmax_t;
|
||||
|
||||
|
||||
# if __WORDSIZE == 64
|
||||
# define __INT64_C(c) c ## L
|
||||
# define __UINT64_C(c) c ## UL
|
||||
# else
|
||||
# define __INT64_C(c) c ## LL
|
||||
# define __UINT64_C(c) c ## ULL
|
||||
# endif
|
||||
|
||||
/* Limits of integral types. */
|
||||
|
||||
/* Minimum of signed integral types. */
|
||||
# define INT8_MIN (-128)
|
||||
# define INT16_MIN (-32767-1)
|
||||
# define INT32_MIN (-2147483647-1)
|
||||
# define INT64_MIN (-__INT64_C(9223372036854775807)-1)
|
||||
/* Maximum of signed integral types. */
|
||||
# define INT8_MAX (127)
|
||||
# define INT16_MAX (32767)
|
||||
# define INT32_MAX (2147483647)
|
||||
# define INT64_MAX (__INT64_C(9223372036854775807))
|
||||
|
||||
/* Maximum of unsigned integral types. */
|
||||
# define UINT8_MAX (255)
|
||||
# define UINT16_MAX (65535)
|
||||
# define UINT32_MAX (4294967295U)
|
||||
# define UINT64_MAX (__UINT64_C(18446744073709551615))
|
||||
|
||||
|
||||
/* Minimum of signed integral types having a minimum size. */
|
||||
# define INT_LEAST8_MIN (-128)
|
||||
# define INT_LEAST16_MIN (-32767-1)
|
||||
# define INT_LEAST32_MIN (-2147483647-1)
|
||||
# define INT_LEAST64_MIN (-__INT64_C(9223372036854775807)-1)
|
||||
/* Maximum of signed integral types having a minimum size. */
|
||||
# define INT_LEAST8_MAX (127)
|
||||
# define INT_LEAST16_MAX (32767)
|
||||
# define INT_LEAST32_MAX (2147483647)
|
||||
# define INT_LEAST64_MAX (__INT64_C(9223372036854775807))
|
||||
|
||||
/* Maximum of unsigned integral types having a minimum size. */
|
||||
# define UINT_LEAST8_MAX (255)
|
||||
# define UINT_LEAST16_MAX (65535)
|
||||
# define UINT_LEAST32_MAX (4294967295U)
|
||||
# define UINT_LEAST64_MAX (__UINT64_C(18446744073709551615))
|
||||
|
||||
|
||||
/* Minimum of fast signed integral types having a minimum size. */
|
||||
# define INT_FAST8_MIN (-128)
|
||||
# define INT_FAST16_MIN INT16_MIN
|
||||
# define INT_FAST32_MIN INT32_MIN
|
||||
# define INT_FAST64_MIN (-__INT64_C(9223372036854775807)-1)
|
||||
/* Maximum of fast signed integral types having a minimum size. */
|
||||
# define INT_FAST8_MAX (127)
|
||||
# define INT_FAST16_MAX INT16_MAX
|
||||
# define INT_FAST32_MAX INT32_MAX
|
||||
# define INT_FAST64_MAX (__INT64_C(9223372036854775807))
|
||||
|
||||
/* Maximum of fast unsigned integral types having a minimum size. */
|
||||
# define UINT_FAST8_MAX (255)
|
||||
# define UINT_FAST16_MAX UINT16_MAX
|
||||
# define UINT_FAST32_MAX UINT32_MAX
|
||||
# define UINT_FAST64_MAX (__UINT64_C(18446744073709551615))
|
||||
|
||||
|
||||
/* Values to test for integral types holding `void *' pointer. */
|
||||
# if __WORDSIZE == 64
|
||||
# define INTPTR_MIN (-9223372036854775807L-1)
|
||||
# define INTPTR_MAX (9223372036854775807L)
|
||||
# define UINTPTR_MAX (18446744073709551615UL)
|
||||
# else
|
||||
# define INTPTR_MIN (-2147483647-1)
|
||||
# define INTPTR_MAX (2147483647)
|
||||
# define UINTPTR_MAX (4294967295U)
|
||||
# endif
|
||||
|
||||
|
||||
/* Minimum for largest signed integral type. */
|
||||
# define INTMAX_MIN (-__INT64_C(9223372036854775807)-1)
|
||||
/* Maximum for largest signed integral type. */
|
||||
# define INTMAX_MAX (__INT64_C(9223372036854775807))
|
||||
|
||||
/* Maximum for largest unsigned integral type. */
|
||||
# define UINTMAX_MAX (__UINT64_C(18446744073709551615))
|
||||
|
||||
|
||||
/* Limits of other integer types. */
|
||||
|
||||
/* Limits of `ptrdiff_t' type. */
|
||||
# if __WORDSIZE == 64
|
||||
# define PTRDIFF_MIN (-9223372036854775807L-1)
|
||||
# define PTRDIFF_MAX (9223372036854775807L)
|
||||
# else
|
||||
# if __WORDSIZE32_PTRDIFF_LONG
|
||||
# define PTRDIFF_MIN (-2147483647L-1)
|
||||
# define PTRDIFF_MAX (2147483647L)
|
||||
# else
|
||||
# define PTRDIFF_MIN (-2147483647-1)
|
||||
# define PTRDIFF_MAX (2147483647)
|
||||
# endif
|
||||
# endif
|
||||
|
||||
/* Limits of `sig_atomic_t'. */
|
||||
# define SIG_ATOMIC_MIN (-2147483647-1)
|
||||
# define SIG_ATOMIC_MAX (2147483647)
|
||||
|
||||
/* Limit of `size_t' type. */
|
||||
# if __WORDSIZE == 64
|
||||
# define SIZE_MAX (18446744073709551615UL)
|
||||
# else
|
||||
# if __WORDSIZE32_SIZE_ULONG
|
||||
# define SIZE_MAX (4294967295UL)
|
||||
# else
|
||||
# define SIZE_MAX (4294967295U)
|
||||
# endif
|
||||
# endif
|
||||
|
||||
/* Limits of `wchar_t'. */
|
||||
# ifndef WCHAR_MIN
|
||||
/* These constants might also be defined in <wchar.h>. */
|
||||
# define WCHAR_MIN __WCHAR_MIN
|
||||
# define WCHAR_MAX __WCHAR_MAX
|
||||
# endif
|
||||
|
||||
/* Limits of `wint_t'. */
|
||||
# define WINT_MIN (0u)
|
||||
# define WINT_MAX (4294967295u)
|
||||
|
||||
/* Signed. */
|
||||
# define INT8_C(c) c
|
||||
# define INT16_C(c) c
|
||||
# define INT32_C(c) c
|
||||
# if __WORDSIZE == 64
|
||||
# define INT64_C(c) c ## L
|
||||
# else
|
||||
# define INT64_C(c) c ## LL
|
||||
# endif
|
||||
|
||||
/* Unsigned. */
|
||||
# define UINT8_C(c) c
|
||||
# define UINT16_C(c) c
|
||||
# define UINT32_C(c) c ## U
|
||||
# if __WORDSIZE == 64
|
||||
# define UINT64_C(c) c ## UL
|
||||
# else
|
||||
# define UINT64_C(c) c ## ULL
|
||||
# endif
|
||||
|
||||
/* Maximal type. */
|
||||
# if __WORDSIZE == 64
|
||||
# define INTMAX_C(c) c ## L
|
||||
# define UINTMAX_C(c) c ## UL
|
||||
# else
|
||||
# define INTMAX_C(c) c ## LL
|
||||
# define UINTMAX_C(c) c ## ULL
|
||||
# endif
|
||||
|
||||
#if __GLIBC_USE (IEC_60559_BFP_EXT_C23)
|
||||
|
||||
# define INT8_WIDTH 8
|
||||
# define UINT8_WIDTH 8
|
||||
# define INT16_WIDTH 16
|
||||
# define UINT16_WIDTH 16
|
||||
# define INT32_WIDTH 32
|
||||
# define UINT32_WIDTH 32
|
||||
# define INT64_WIDTH 64
|
||||
# define UINT64_WIDTH 64
|
||||
|
||||
# define INT_LEAST8_WIDTH 8
|
||||
# define UINT_LEAST8_WIDTH 8
|
||||
# define INT_LEAST16_WIDTH 16
|
||||
# define UINT_LEAST16_WIDTH 16
|
||||
# define INT_LEAST32_WIDTH 32
|
||||
# define UINT_LEAST32_WIDTH 32
|
||||
# define INT_LEAST64_WIDTH 64
|
||||
# define UINT_LEAST64_WIDTH 64
|
||||
|
||||
# define INT_FAST8_WIDTH 8
|
||||
# define UINT_FAST8_WIDTH 8
|
||||
# define INT_FAST16_WIDTH __WORDSIZE
|
||||
# define UINT_FAST16_WIDTH __WORDSIZE
|
||||
# define INT_FAST32_WIDTH __WORDSIZE
|
||||
# define UINT_FAST32_WIDTH __WORDSIZE
|
||||
# define INT_FAST64_WIDTH 64
|
||||
# define UINT_FAST64_WIDTH 64
|
||||
|
||||
# define INTPTR_WIDTH __WORDSIZE
|
||||
# define UINTPTR_WIDTH __WORDSIZE
|
||||
|
||||
# define INTMAX_WIDTH 64
|
||||
# define UINTMAX_WIDTH 64
|
||||
|
||||
# define PTRDIFF_WIDTH __WORDSIZE
|
||||
# define SIG_ATOMIC_WIDTH 32
|
||||
# define SIZE_WIDTH __WORDSIZE
|
||||
# define WCHAR_WIDTH 32
|
||||
# define WINT_WIDTH 32
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* stdint.h */
|
@ -1,69 +0,0 @@
|
||||
#include "ast.h"
|
||||
#include "utils.h"
|
||||
|
||||
static void dump_usage() {
|
||||
std::string Usage = R"usage(
|
||||
usage: command <filename> <libname> [guest_triple] [host_triple] -- <clang_flags>
|
||||
<filename> : set the header file to be parsed
|
||||
<libname> : set libname required for wrapping func
|
||||
[guest_triple]: set guest triple: can be arm32/arm64/x86/x64, default is x64
|
||||
[host_triple] : set host triple: can be arm32/arm64/x86/x64, default is arm64
|
||||
-- : mandatory
|
||||
<clang_flags> : extra compiler flags
|
||||
)usage";
|
||||
std::cerr << Usage << std::endl;
|
||||
}
|
||||
|
||||
std::string parse_triple(const char* arg) {
|
||||
if (strcmp(arg, "x86") == 0) {
|
||||
return "i386-pc-linux-gnu";
|
||||
} else if (strcmp(arg, "x64") == 0) {
|
||||
return "x86_64-pc-linux-gnu";
|
||||
} else if (strcmp(arg, "arm32") == 0) {
|
||||
return "armv7-unknown-linux-gnueabihf";
|
||||
} else if (strcmp(arg, "arm64") == 0) {
|
||||
return "aarch64-unknown-linux-gnu";
|
||||
} else {
|
||||
std::cerr << "Invalid triple: '" << arg << "'\n";
|
||||
dump_usage();
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
if (argc < 4) {
|
||||
dump_usage();
|
||||
return 0;
|
||||
}
|
||||
std::string libname = argv[2];
|
||||
std::string guest_triple = parse_triple("x64");
|
||||
std::string host_triple = parse_triple("arm64");
|
||||
if (argc >= 5) {
|
||||
guest_triple = parse_triple(argv[3]);
|
||||
}
|
||||
if (argc >= 6) {
|
||||
host_triple = parse_triple(argv[4]);
|
||||
}
|
||||
bool has_necessary_tag = false;
|
||||
for (int i = 0; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--") == 0) {
|
||||
has_necessary_tag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!has_necessary_tag) {
|
||||
std::cerr << "Please add '--' after the triples" << std::endl;
|
||||
dump_usage();
|
||||
return 0;
|
||||
}
|
||||
std::string err;
|
||||
auto compile_db = clang::tooling::FixedCompilationDatabase::loadFromCommandLine(argc, argv, err);
|
||||
clang::tooling::ClangTool Tool(*compile_db, {argv[1]});
|
||||
Tool.appendArgumentsAdjuster([&guest_triple](const clang::tooling::CommandLineArguments &args, clang::StringRef) {
|
||||
clang::tooling::CommandLineArguments adjusted_args = args;
|
||||
adjusted_args.push_back(std::string{"-target"});
|
||||
adjusted_args.push_back(guest_triple);
|
||||
return adjusted_args;
|
||||
});
|
||||
return Tool.run(std::make_unique<MyFrontendActionFactory>(libname, host_triple, guest_triple).get());
|
||||
}
|
115
wrapperhelper/src/cstring.c
Normal file
115
wrapperhelper/src/cstring.c
Normal file
@ -0,0 +1,115 @@
|
||||
#include "cstring.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define STRING_MIN_CAP 8
|
||||
|
||||
string_t *string_new(void) {
|
||||
string_t *ret = malloc(sizeof(*ret));
|
||||
if (!ret) return NULL;
|
||||
char *buf = malloc(sizeof(char));
|
||||
if (!buf) {
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
buf[0] = '\0';
|
||||
ret->ssize = ret->scap = 0; ret->buf = buf;
|
||||
return ret;
|
||||
}
|
||||
|
||||
string_t *string_new_cap(size_t cap) {
|
||||
string_t *ret = malloc(sizeof(*ret));
|
||||
if (!ret) return NULL;
|
||||
cap = (cap < STRING_MIN_CAP) ? STRING_MIN_CAP : cap;
|
||||
ret->buf = malloc((cap + 1) * sizeof(char));
|
||||
if (!ret->buf) {
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
ret->buf[0] = '\0';
|
||||
ret->scap = cap;
|
||||
ret->ssize = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int string_reserve(string_t *s, size_t cap) {
|
||||
size_t new_cap = (cap < STRING_MIN_CAP) ? STRING_MIN_CAP : cap;
|
||||
if (new_cap <= s->scap) return 1;
|
||||
|
||||
void *new_buf = realloc(s->buf, sizeof(char) * (new_cap + 1));
|
||||
if (!new_buf) return 0;
|
||||
s->buf = new_buf;
|
||||
s->scap = new_cap;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void string_del(string_t *s) {
|
||||
if (s->buf) free(s->buf);
|
||||
free(s);
|
||||
}
|
||||
|
||||
char *string_steal(string_t *s) {
|
||||
char *ret = s->buf;
|
||||
free(s);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int string_add_char(string_t *s, char elem) {
|
||||
if (s->ssize >= s->scap) {
|
||||
size_t new_cap = (s->scap < STRING_MIN_CAP) ? STRING_MIN_CAP : s->scap * 2;
|
||||
char *new_buf = realloc(s->buf, sizeof(char) * (new_cap + 1));
|
||||
if (!new_buf) return 0;
|
||||
s->buf = new_buf;
|
||||
s->scap = new_cap;
|
||||
}
|
||||
s->buf[s->ssize++] = elem;
|
||||
s->buf[s->ssize] = '\0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
int string_add_string(string_t *s1, string_t *s2) {
|
||||
if (s1->ssize + s2->ssize > s1->scap) {
|
||||
size_t new_cap = (s1->scap < STRING_MIN_CAP) ? STRING_MIN_CAP : s1->scap * 2;
|
||||
while (s1->ssize + s2->ssize > new_cap) {
|
||||
new_cap = new_cap * 2;
|
||||
}
|
||||
char *new_buf = realloc(s1->buf, sizeof(char) * (new_cap + 1));
|
||||
if (!new_buf) return 0;
|
||||
s1->buf = new_buf;
|
||||
s1->scap = new_cap;
|
||||
}
|
||||
memcpy(s1->buf + s1->ssize, s2->buf, s2->ssize);
|
||||
s1->ssize += s2->ssize;
|
||||
s1->buf[s1->ssize] = '\0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
void string_pop(string_t *s) {
|
||||
if (!s->ssize) return;
|
||||
s->buf[--s->ssize] = '\0';
|
||||
if (s->ssize < s->scap / 4) {
|
||||
size_t new_cap = (s->scap / 2 < STRING_MIN_CAP) ? STRING_MIN_CAP : s->scap / 2;
|
||||
if (new_cap == s->scap) return;
|
||||
void *new_buf = realloc(s->buf, sizeof(char) * (new_cap + 1));
|
||||
if (!new_buf) return; // We don't really care if the realloc fails, we just need to not update anything
|
||||
s->buf = new_buf;
|
||||
s->scap = new_cap;
|
||||
}
|
||||
}
|
||||
|
||||
string_t *string_dup(string_t const *s) {
|
||||
string_t *ret = string_new_cap(s->ssize);
|
||||
if (!ret) return NULL;
|
||||
memcpy(ret->buf, s->buf, s->ssize + 1);
|
||||
ret->ssize = s->ssize;
|
||||
return ret;
|
||||
}
|
||||
|
||||
string_t *string_concat(string_t const *l, string_t const *r) {
|
||||
string_t *ret = string_new_cap(l->ssize + r->ssize);
|
||||
if (!ret) return NULL;
|
||||
memcpy(ret->buf, l->buf, l->ssize);
|
||||
memcpy(ret->buf + l->ssize, r->buf, r->ssize);
|
||||
ret->buf[ret->ssize] = '\0';
|
||||
return ret;
|
||||
}
|
78
wrapperhelper/src/cstring.h
Normal file
78
wrapperhelper/src/cstring.h
Normal file
@ -0,0 +1,78 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef STRING_H
|
||||
#define STRING_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/** Thread-unsafe string implementation, with support for raw NULL bytes
|
||||
* USAGE:
|
||||
* ======
|
||||
* string_t ------------ The string type.
|
||||
* string_new ---------- Creates a new string.
|
||||
* string_new_cap ------ Creates a new string with a given capacity. Takes the capacity.
|
||||
* string_reserve ------ Ensures a string has at least a given capacity. Takes the string and the capacity.
|
||||
* string_del ---------- Frees a string. Takes the string.
|
||||
* string_steal -------- Frees a string, keeping the content alive. Takes the string. The content (also returned) needs to be freed separately.
|
||||
* string_add_char ----- Add a character at the end. Takes the string and the new character. May increase the string capacity.
|
||||
* string_add_string --- Add a string at the end in-place. Takes both strings. May increase the string capacity.
|
||||
* string_pop ---------- Pops the last character. Takes the string. May reduce the string capacity.
|
||||
* string_dup ---------- Duplicate a string. Takes the string. Does not free the old string.
|
||||
* string_concat ------- Concatenate two strings. Takes both strings. Does not free any string.
|
||||
* string_len ---------- String length. Takes the string.
|
||||
* string_cap ---------- String capacity. Takes the string.
|
||||
* string_content ------ Pointer to the string content. Valid C string. Takes the string.
|
||||
* string_begin -------- Start of the string. Takes the string.
|
||||
* string_end ---------- End of the string. Points to unmanaged memory. Takes the string.
|
||||
* string_last --------- Last element of the string. Points to invalid memory if size is zero. Takes the string.
|
||||
* string_for ---------- Iterate over the characters of a string. This is a for loop. Takes the iterator name and the string.
|
||||
*
|
||||
* EXAMPLE:
|
||||
* ========
|
||||
* Source main.c:
|
||||
* -------------------
|
||||
// ...
|
||||
int main() {
|
||||
string_t *str = string_new_cap(2);
|
||||
if (!str) {
|
||||
printf("Error: failed to allocate new string\n");
|
||||
return 2;
|
||||
}
|
||||
string_add_char(str, 'H'); // Cannot fail
|
||||
string_add_char(str, 'i'); // Cannot fail
|
||||
if (!string_add_char(str, '!')) {
|
||||
printf("Error: failed to add char to string\n");
|
||||
return 2;
|
||||
}
|
||||
printf("String length: %zu: \"%s\"\n", string_len(str), string_content(str)); // 3, "Hi!"
|
||||
string_del(str);
|
||||
}
|
||||
*/
|
||||
|
||||
typedef struct string_s {
|
||||
size_t ssize, scap;
|
||||
char *buf;
|
||||
} string_t;
|
||||
|
||||
string_t *string_new(void);
|
||||
string_t *string_new_cap(size_t cap);
|
||||
int string_reserve(string_t *s, size_t cap);
|
||||
void string_del(string_t *s);
|
||||
char *string_steal(string_t *s);
|
||||
int string_add_char(string_t *s, char elem);
|
||||
int string_add_string(string_t *s1, string_t *s2);
|
||||
void string_pop(string_t *s);
|
||||
string_t *string_dup(string_t const *s);
|
||||
string_t *string_concat(string_t const *l, string_t const *r);
|
||||
#define string_len(s) ((s)->ssize)
|
||||
#define string_cap(s) ((s)->scap)
|
||||
#define string_content(s) ((s)->buf)
|
||||
#define string_begin(s) ((s)->buf)
|
||||
#define string_end(s) ((s)->buf + (s)->ssize)
|
||||
#define string_last(s) ((s)->buf[(s)->ssize - 1])
|
||||
#define string_for(itname, s) \
|
||||
for (char *itname = string_begin((s)); itname != string_end((s)); ++itname)
|
||||
|
||||
#endif // STRING_H
|
922
wrapperhelper/src/generator.c
Normal file
922
wrapperhelper/src/generator.c
Normal file
@ -0,0 +1,922 @@
|
||||
#include "generator.h"
|
||||
|
||||
#include "lang.h"
|
||||
#include "prepare.h"
|
||||
|
||||
static const char *rft2str[8] = {
|
||||
[RQT_FUN] = "",
|
||||
[RQT_FUN_2] = "",
|
||||
[RQT_FUN_MY] = "(my) ",
|
||||
[RQT_FUN_D] = "(D) ",
|
||||
[RQT_DATA] = "",
|
||||
[RQT_DATAV] = "(V) ",
|
||||
[RQT_DATAB] = "(B) ",
|
||||
[RQT_DATAM] = "(my) ",
|
||||
};
|
||||
#define IS_RQT_FUN2(rty) (((rty) == RQT_FUN_2) || ((rty) == RQT_FUN_D))
|
||||
#define IS_RQT_FUNCTION(rty) ((rty) < RQT_DATA)
|
||||
|
||||
void request_print(request_t *req) {
|
||||
printf("%s", string_content(req->obj_name));
|
||||
if (req->has_default && req->has_val && (IS_RQT_FUNCTION(req->def.rty) != IS_RQT_FUNCTION(req->val.rty))) {
|
||||
printf(" => conflict: was/is data, is/was function\n");
|
||||
}
|
||||
int is_fun;
|
||||
if (req->has_default) is_fun = IS_RQT_FUNCTION(req->def.rty);
|
||||
else if (req->has_val) is_fun = IS_RQT_FUNCTION(req->val.rty);
|
||||
else {
|
||||
printf(" => (no value)\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_fun) {
|
||||
printf(" => %sfunction", req->weak ? "weak " : "");
|
||||
if (req->has_default) {
|
||||
printf(" with %sdefault %s%s%s%s",
|
||||
req->default_comment ? "commented " : "",
|
||||
rft2str[req->def.rty],
|
||||
string_content(req->def.fun.typ),
|
||||
(req->def.rty == RQT_FUN_2) ? " -> " : "",
|
||||
(req->def.rty == RQT_FUN_2) ? string_content(req->def.fun.fun2) : "");
|
||||
}
|
||||
if (req->has_val) {
|
||||
printf(" with solved %s%s%s%s",
|
||||
rft2str[req->val.rty],
|
||||
string_content(req->val.fun.typ),
|
||||
(req->val.rty == RQT_FUN_2) ? " -> " : "",
|
||||
(req->val.rty == RQT_FUN_2) ? string_content(req->val.fun.fun2) : "");
|
||||
}
|
||||
} else {
|
||||
printf(" => %sdata", req->weak ? "weak " : "");
|
||||
if (req->has_default) {
|
||||
if (req->def.dat.has_size) printf(" with default %zu", req->def.dat.sz);
|
||||
else printf(" with no default");
|
||||
}
|
||||
if (req->has_val) {
|
||||
if (req->def.dat.has_size) printf(" with solved %zu", req->def.dat.sz);
|
||||
else printf(" with no solved");
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
void request_print_check(request_t *req) {
|
||||
if (req->has_default && req->has_val && (IS_RQT_FUNCTION(req->def.rty) != IS_RQT_FUNCTION(req->val.rty))) {
|
||||
printf("%s => conflict: was/is data, is/was function\n", string_content(req->obj_name));
|
||||
}
|
||||
int is_fun;
|
||||
if (req->has_default) is_fun = IS_RQT_FUNCTION(req->def.rty);
|
||||
else if (req->has_val) is_fun = IS_RQT_FUNCTION(req->val.rty);
|
||||
else {
|
||||
printf(" => (no value)\n");
|
||||
return;
|
||||
}
|
||||
if (is_fun) {
|
||||
if (req->has_val) {
|
||||
if (req->has_default) {
|
||||
int similar = 1;
|
||||
// if (req->def.rty != req->val.rty) similar = 0;
|
||||
if (similar && strcmp(string_content(req->def.fun.typ), string_content(req->val.fun.typ))) {
|
||||
// similar = 0;
|
||||
// TODO
|
||||
if (req->def.rty == RQT_FUN_MY) {
|
||||
similar =
|
||||
string_len(req->def.fun.typ) >= 3 &&
|
||||
string_content(req->def.fun.typ)[2] == 'E' &&
|
||||
!strncmp(string_content(req->def.fun.typ), string_content(req->val.fun.typ), 2) &&
|
||||
!strcmp(string_content(req->def.fun.typ) + 3, string_content(req->val.fun.typ) + 2);
|
||||
if (similar) {
|
||||
// We need to add the 'E' back here
|
||||
}
|
||||
} else {
|
||||
similar = 0;
|
||||
}
|
||||
}
|
||||
if (!similar) {
|
||||
printf("%s => %sfunction with %sdefault %s%s%s%s and different solved %s%s%s%s\n",
|
||||
string_content(req->obj_name),
|
||||
req->weak ? "weak " : "",
|
||||
req->default_comment ? "commented " : "",
|
||||
rft2str[req->def.rty],
|
||||
string_content(req->def.fun.typ),
|
||||
(req->def.rty == RQT_FUN_2) ? " -> " : "",
|
||||
(req->def.rty == RQT_FUN_2) ? string_content(req->def.fun.fun2) : "",
|
||||
rft2str[req->val.rty],
|
||||
string_content(req->val.fun.typ),
|
||||
(req->val.rty == RQT_FUN_2) ? " -> " : "",
|
||||
(req->val.rty == RQT_FUN_2) ? string_content(req->val.fun.fun2) : "");
|
||||
}
|
||||
} else {
|
||||
printf("%s => %sfunction with solved %s%s%s%s\n",
|
||||
string_content(req->obj_name),
|
||||
req->weak ? "weak " : "",
|
||||
rft2str[req->val.rty],
|
||||
string_content(req->val.fun.typ),
|
||||
(req->val.rty == RQT_FUN_2) ? " -> " : "",
|
||||
(req->val.rty == RQT_FUN_2) ? string_content(req->val.fun.fun2) : "");
|
||||
}
|
||||
} else if (req->has_default) {
|
||||
/* printf("%s => unsolved %sfunction with %sdefault %s%s%s%s\n",
|
||||
string_content(req->obj_name),
|
||||
req->weak ? "weak " : "",
|
||||
req->default_comment ? "commented " : "",
|
||||
rft2str[req->def.rty],
|
||||
string_content(req->def.fun.typ),
|
||||
(req->def.rty == RQT_FUN_2) ? " -> " : "",
|
||||
(req->def.rty == RQT_FUN_2) ? string_content(req->def.fun.fun2) : ""); */
|
||||
}
|
||||
} else {
|
||||
printf("%s => %sdata", string_content(req->obj_name), req->weak ? "weak " : "");
|
||||
if (req->has_default) {
|
||||
if (req->def.dat.has_size) printf(" with default %zu", req->def.dat.sz);
|
||||
else printf(" with no default");
|
||||
}
|
||||
if (req->has_val) {
|
||||
if (req->def.dat.has_size) printf(" with solved %zu", req->def.dat.sz);
|
||||
else printf(" with no solved");
|
||||
}
|
||||
}
|
||||
}
|
||||
void request_del(request_t *req) {
|
||||
string_del(req->obj_name);
|
||||
if (req->has_default) {
|
||||
switch (req->def.rty) {
|
||||
case RQT_FUN: string_del(req->def.fun.typ); break;
|
||||
case RQT_FUN_2: string_del(req->def.fun.typ); string_del(req->def.fun.fun2); break;
|
||||
case RQT_FUN_MY: string_del(req->def.fun.typ); break;
|
||||
case RQT_FUN_D: string_del(req->def.fun.typ); string_del(req->def.fun.fun2); break;
|
||||
case RQT_DATA: break;
|
||||
case RQT_DATAV: break;
|
||||
case RQT_DATAB: break;
|
||||
case RQT_DATAM: break;
|
||||
}
|
||||
}
|
||||
if (req->has_val) {
|
||||
switch (req->val.rty) {
|
||||
case RQT_FUN: string_del(req->val.fun.typ); break;
|
||||
case RQT_FUN_2: string_del(req->val.fun.typ); string_del(req->val.fun.fun2); break;
|
||||
case RQT_FUN_MY: string_del(req->val.fun.typ); break;
|
||||
case RQT_FUN_D: string_del(req->val.fun.typ); string_del(req->val.fun.fun2); break;
|
||||
case RQT_DATA: break;
|
||||
case RQT_DATAV: break;
|
||||
case RQT_DATAB: break;
|
||||
case RQT_DATAM: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int valid_reqtype(string_t *t) {
|
||||
const char *s = string_content(t);
|
||||
if (!((s[0] >= 'A') && (s[0] <= 'Z')) && !((s[0] >= 'a') && (s[0] <= 'z'))) return 0;
|
||||
if (s[1] != 'F') return 0;
|
||||
for (size_t i = 2; i < string_len(t); ++i) {
|
||||
if (!((s[i] >= 'A') && (s[i] <= 'Z')) && !((s[i] >= 'a') && (s[i] <= 'z'))) return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
static const char *rqt_suffix[8] = {
|
||||
[RQT_FUN] = "",
|
||||
[RQT_FUN_2] = "2",
|
||||
[RQT_FUN_MY] = "M",
|
||||
[RQT_FUN_D] = "D",
|
||||
[RQT_DATA] = "",
|
||||
[RQT_DATAV] = "V",
|
||||
[RQT_DATAB] = "B",
|
||||
[RQT_DATAM] = "M",
|
||||
};
|
||||
|
||||
static void request_output(FILE *f, request_t *req) {
|
||||
if (!req->has_val) {
|
||||
if (!req->has_default) {
|
||||
// printf("Warning: %s has no value and no default, assuming function\n", string_content(req->obj_name));
|
||||
fprintf(f, "//GO%s(%s, \n", req->weak ? "W" : "", string_content(req->obj_name));
|
||||
} else if (IS_RQT_FUNCTION(req->def.rty)) {
|
||||
fprintf(f, "%sGO%s%s(%s, %s%s%s%s%s)%s\n",
|
||||
req->default_comment ? "//" : "",
|
||||
req->weak ? "W" : "",
|
||||
rqt_suffix[req->def.rty],
|
||||
string_content(req->obj_name),
|
||||
valid_reqtype(req->def.fun.typ) ? "" : "\"",
|
||||
string_content(req->def.fun.typ),
|
||||
valid_reqtype(req->def.fun.typ) ? "" : "\"",
|
||||
IS_RQT_FUN2(req->def.rty) ? ", " : "",
|
||||
IS_RQT_FUN2(req->def.rty) ? string_content(req->def.fun.fun2) : "",
|
||||
req->default_comment ? "" : " // Warning: failed to confirm");
|
||||
} else {
|
||||
if (req->def.dat.has_size) {
|
||||
fprintf(f, "%sDATA%s%s(%s, %zu) // Warning: failed to confirm\n",
|
||||
req->default_comment ? "//" : "",
|
||||
req->weak ? "W" : "",
|
||||
rqt_suffix[req->def.rty],
|
||||
string_content(req->obj_name),
|
||||
req->def.dat.sz);
|
||||
} else {
|
||||
fprintf(f, "//DATA%s%s(%s, \n",
|
||||
req->weak ? "W" : "",
|
||||
rqt_suffix[req->def.rty],
|
||||
string_content(req->obj_name));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (IS_RQT_FUNCTION(req->val.rty)) {
|
||||
int is_comment =
|
||||
(req->has_default && !req->default_comment) ? (req->val.rty != req->def.rty) : (req->val.rty != RQT_FUN);
|
||||
fprintf(f, "%sGO%s%s(%s, %s%s%s)\n",
|
||||
is_comment ? "//" : "",
|
||||
req->weak ? "W" : "",
|
||||
rqt_suffix[req->val.rty],
|
||||
string_content(req->obj_name),
|
||||
string_content(req->val.fun.typ),
|
||||
IS_RQT_FUN2(req->val.rty) ? ", " : "",
|
||||
IS_RQT_FUN2(req->val.rty) ? req->val.fun.fun2 ? string_content(req->val.fun.fun2) : "<error: no val>" : "");
|
||||
} else {
|
||||
if (req->val.dat.has_size) {
|
||||
int is_comment = !req->has_default || req->default_comment || (req->def.rty != req->val.rty);
|
||||
fprintf(f, "%sDATA%s(%s, %zu)\n",
|
||||
is_comment ? "//" : "",
|
||||
rqt_suffix[req->val.rty],
|
||||
string_content(req->obj_name),
|
||||
req->val.dat.sz);
|
||||
} else {
|
||||
fprintf(f, "//DATA%s(%s, \n",
|
||||
rqt_suffix[req->val.rty],
|
||||
string_content(req->obj_name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void output_from_requests(FILE *f, VECTOR(requests) *reqs) {
|
||||
fprintf(f, "#if !(defined(GO) && defined(GOM) && defined(GO2) && defined(DATA))\n#error Meh...\n#endif\n\n");
|
||||
vector_for(requests, req, reqs) {
|
||||
request_output(f, req);
|
||||
}
|
||||
}
|
||||
|
||||
VECTOR_IMPL(requests, request_del)
|
||||
|
||||
VECTOR(requests) *requests_from_file(const char *filename, FILE *f) {
|
||||
prepare_t *prep = prepare_new_file(f, filename);
|
||||
if (!prep) {
|
||||
printf("Failed to create the prepare structure for the requests file\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VECTOR(requests) *ret = vector_new(requests);
|
||||
if (!ret) {
|
||||
prepare_del(prep);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int lineno = 1;
|
||||
|
||||
// Ignore the first 3 lines
|
||||
preproc_token_t tok;
|
||||
do {
|
||||
tok = pre_next_token(prep, 0);
|
||||
if (tok.tokt == PPTOK_NEWLINE) ++lineno;
|
||||
} while (!preproc_token_isend(&tok) && (lineno < 4));
|
||||
|
||||
// TODO: better conditionals handling
|
||||
// Also, for now assume we have no definition
|
||||
int if_depth = 0, entered_depth = 0;
|
||||
while (1) {
|
||||
int is_comment = 0;
|
||||
tok = pre_next_token(prep, 1);
|
||||
while (tok.tokt == PPTOK_START_LINE_COMMENT) {
|
||||
is_comment = 1;
|
||||
// Empty destructor
|
||||
tok = pre_next_token(prep, 1);
|
||||
}
|
||||
if ((tok.tokt == PPTOK_SYM) && (tok.tokv.sym == SYM_HASH)) {
|
||||
if (is_comment) {
|
||||
preproc_token_del(&tok);
|
||||
tok = pre_next_newline_token(prep); // Returns a newline
|
||||
++lineno;
|
||||
continue;
|
||||
}
|
||||
tok = pre_next_token(prep, 0);
|
||||
if (tok.tokt != PPTOK_IDENT) {
|
||||
printf("Error: invalid requests file: invalid preprocessor line\n");
|
||||
preproc_token_del(&tok);
|
||||
goto failed;
|
||||
}
|
||||
if (!strcmp(string_content(tok.tokv.str), "ifdef")) {
|
||||
string_del(tok.tokv.str);
|
||||
tok = pre_next_token(prep, 0);
|
||||
if (tok.tokt != PPTOK_IDENT) {
|
||||
printf("Error: invalid requests file: invalid '#ifdef' line\n");
|
||||
preproc_token_del(&tok);
|
||||
goto failed;
|
||||
}
|
||||
++if_depth;
|
||||
string_del(tok.tokv.str);
|
||||
tok = pre_next_token(prep, 0);
|
||||
} else if (!strcmp(string_content(tok.tokv.str), "ifndef")) {
|
||||
string_del(tok.tokv.str);
|
||||
tok = pre_next_token(prep, 0);
|
||||
if (tok.tokt != PPTOK_IDENT) {
|
||||
printf("Error: invalid requests file: invalid '#ifndef' line\n");
|
||||
preproc_token_del(&tok);
|
||||
goto failed;
|
||||
}
|
||||
if (if_depth == entered_depth) ++entered_depth;
|
||||
++if_depth;
|
||||
string_del(tok.tokv.str);
|
||||
tok = pre_next_token(prep, 0);
|
||||
} else if (!strcmp(string_content(tok.tokv.str), "else")) {
|
||||
string_del(tok.tokv.str);
|
||||
tok = pre_next_token(prep, 0);
|
||||
if (if_depth == entered_depth + 1) ++entered_depth;
|
||||
else if (if_depth == entered_depth) --entered_depth;
|
||||
} else if (!strcmp(string_content(tok.tokv.str), "endif")) {
|
||||
string_del(tok.tokv.str);
|
||||
tok = pre_next_token(prep, 0);
|
||||
if (if_depth == entered_depth) --entered_depth;
|
||||
--if_depth;
|
||||
} else {
|
||||
printf("Error: invalid requests file: invalid preprocessor command '%s'\n", string_content(tok.tokv.str));
|
||||
string_del(tok.tokv.str);
|
||||
goto failed;
|
||||
}
|
||||
while (!preproc_token_isend(&tok) && (tok.tokt != PPTOK_NEWLINE)) {
|
||||
preproc_token_del(&tok);
|
||||
tok = pre_next_token(prep, 0);
|
||||
}
|
||||
++lineno;
|
||||
if (preproc_token_isend(&tok)) {
|
||||
if (tok.tokt == PPTOK_EOF) goto success;
|
||||
else {
|
||||
preproc_token_del(&tok);
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
} else if (tok.tokt == PPTOK_NEWLINE) {
|
||||
++lineno;
|
||||
} else if (tok.tokt == PPTOK_EOF) {
|
||||
goto success;
|
||||
} else if ((tok.tokt == PPTOK_IDENT)
|
||||
&& (!strcmp(string_content(tok.tokv.str), "GO")
|
||||
|| !strcmp(string_content(tok.tokv.str), "GO2")
|
||||
|| !strcmp(string_content(tok.tokv.str), "GOD")
|
||||
|| !strcmp(string_content(tok.tokv.str), "GOM")
|
||||
|| !strcmp(string_content(tok.tokv.str), "GOW")
|
||||
|| !strcmp(string_content(tok.tokv.str), "GOW2")
|
||||
|| !strcmp(string_content(tok.tokv.str), "GOWD")
|
||||
|| !strcmp(string_content(tok.tokv.str), "GOWM"))) {
|
||||
int isweak = (string_content(tok.tokv.str)[2] == 'W');
|
||||
request_t req = {
|
||||
.has_default = 0,
|
||||
.default_comment = is_comment,
|
||||
.has_val = 0,
|
||||
.obj_name = NULL,
|
||||
.weak = isweak,
|
||||
.def = {
|
||||
.rty =
|
||||
(string_content(tok.tokv.str)[isweak ? 3 : 2] == '2') ? RQT_FUN_2 :
|
||||
(string_content(tok.tokv.str)[isweak ? 3 : 2] == 'D') ? RQT_FUN_D :
|
||||
(string_content(tok.tokv.str)[isweak ? 3 : 2] == 'M') ? RQT_FUN_MY : RQT_FUN,
|
||||
.fun.typ = NULL,
|
||||
.fun.fun2 = NULL,
|
||||
},
|
||||
};
|
||||
string_del(tok.tokv.str);
|
||||
tok = pre_next_token(prep, 0);
|
||||
if ((tok.tokt != PPTOK_SYM) || (tok.tokv.sym != SYM_LPAREN)) {
|
||||
printf("Error: invalid requests file: invalid GO line %d (lparen)\n", lineno);
|
||||
preproc_token_del(&tok);
|
||||
goto failed;
|
||||
}
|
||||
// Empty destructor
|
||||
tok = pre_next_token(prep, 0);
|
||||
if (tok.tokt != PPTOK_IDENT) {
|
||||
printf("Error: invalid requests file: invalid GO line %d (obj_name)\n", lineno);
|
||||
preproc_token_del(&tok);
|
||||
goto failed;
|
||||
}
|
||||
req.obj_name = tok.tokv.str;
|
||||
// Token moved
|
||||
tok = pre_next_token(prep, 0);
|
||||
if ((tok.tokt != PPTOK_SYM) || (tok.tokv.sym != SYM_COMMA)) {
|
||||
printf("Error: invalid requests file: invalid GO line %d (comma)\n", lineno);
|
||||
string_del(req.obj_name);
|
||||
preproc_token_del(&tok);
|
||||
goto failed;
|
||||
}
|
||||
// Empty destructor
|
||||
tok = pre_next_token(prep, 0);
|
||||
if ((tok.tokt == PPTOK_IDENT) || (tok.tokt == PPTOK_STRING)) {
|
||||
req.def.fun.typ = (tok.tokt == PPTOK_STRING) ? tok.tokv.sstr : tok.tokv.str;
|
||||
req.has_default = 1;
|
||||
// Token moved
|
||||
tok = pre_next_token(prep, 0);
|
||||
if ((req.def.rty == RQT_FUN_2) || (req.def.rty == RQT_FUN_D)) {
|
||||
if ((tok.tokt != PPTOK_SYM) || (tok.tokv.sym != SYM_COMMA)) {
|
||||
printf("Error: invalid requests file: invalid GO line %d (comma 2)\n", lineno);
|
||||
string_del(req.obj_name);
|
||||
string_del(req.def.fun.typ);
|
||||
preproc_token_del(&tok);
|
||||
goto failed;
|
||||
}
|
||||
// Empty destructor
|
||||
tok = pre_next_token(prep, 0);
|
||||
if (tok.tokt != PPTOK_IDENT) {
|
||||
printf("Error: invalid requests file: invalid GO line %d (redirect)\n", lineno);
|
||||
string_del(req.obj_name);
|
||||
string_del(req.def.fun.typ);
|
||||
preproc_token_del(&tok);
|
||||
goto failed;
|
||||
}
|
||||
req.def.fun.fun2 = tok.tokv.str;
|
||||
// Token moved
|
||||
tok = pre_next_token(prep, 0);
|
||||
}
|
||||
if ((tok.tokt != PPTOK_SYM) || (tok.tokv.sym != SYM_RPAREN)) {
|
||||
printf("Error: invalid requests file: invalid GO line %d (rparen)\n", lineno);
|
||||
string_del(req.obj_name);
|
||||
string_del(req.def.fun.typ);
|
||||
if (req.def.fun.fun2) string_del(req.def.fun.fun2);
|
||||
preproc_token_del(&tok);
|
||||
goto failed;
|
||||
}
|
||||
// Empty destructor
|
||||
tok = pre_next_token(prep, 0);
|
||||
}
|
||||
if (tok.tokt != PPTOK_NEWLINE) {
|
||||
printf("Error: invalid requests file: invalid GO line %d (newline)\n", lineno);
|
||||
string_del(req.obj_name);
|
||||
if (req.def.fun.typ) string_del(req.def.fun.typ);
|
||||
if (req.def.fun.fun2) string_del(req.def.fun.fun2);
|
||||
preproc_token_del(&tok);
|
||||
goto failed;
|
||||
}
|
||||
if (if_depth == entered_depth) {
|
||||
if (!vector_push(requests, ret, req)) {
|
||||
printf("Error: failed to add request for %s\n", string_content(req.obj_name));
|
||||
string_del(req.obj_name);
|
||||
if (req.def.fun.typ) string_del(req.def.fun.typ);
|
||||
if (req.def.fun.fun2) string_del(req.def.fun.fun2);
|
||||
// Empty destructor
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
++lineno;
|
||||
} else if ((tok.tokt == PPTOK_IDENT)
|
||||
&& (!strcmp(string_content(tok.tokv.str), "DATA")
|
||||
|| !strcmp(string_content(tok.tokv.str), "DATAV")
|
||||
|| !strcmp(string_content(tok.tokv.str), "DATAB")
|
||||
|| !strcmp(string_content(tok.tokv.str), "DATAM"))) {
|
||||
request_t req = {
|
||||
.has_default = 1,
|
||||
.default_comment = is_comment,
|
||||
.has_val = 0,
|
||||
.obj_name = NULL,
|
||||
.weak = (string_content(tok.tokv.str)[4] == 'V'),
|
||||
.def = {
|
||||
.rty =
|
||||
(string_content(tok.tokv.str)[4] == 'V') ? RQT_DATAV :
|
||||
(string_content(tok.tokv.str)[4] == 'B') ? RQT_DATAB :
|
||||
(string_content(tok.tokv.str)[4] == 'M') ? RQT_DATAM : RQT_DATA,
|
||||
.dat.has_size = 0,
|
||||
.dat.sz = 0,
|
||||
},
|
||||
};
|
||||
string_del(tok.tokv.str);
|
||||
tok = pre_next_token(prep, 0);
|
||||
if ((tok.tokt != PPTOK_SYM) || (tok.tokv.sym != SYM_LPAREN)) {
|
||||
printf("Error: invalid requests file: invalid DATA line %d (lparen)\n", lineno);
|
||||
preproc_token_del(&tok);
|
||||
goto failed;
|
||||
}
|
||||
// Empty destructor
|
||||
tok = pre_next_token(prep, 0);
|
||||
if (tok.tokt != PPTOK_IDENT) {
|
||||
printf("Error: invalid requests file: invalid DATA line %d (obj_name)\n", lineno);
|
||||
preproc_token_del(&tok);
|
||||
goto failed;
|
||||
}
|
||||
req.obj_name = tok.tokv.str;
|
||||
// Token moved
|
||||
tok = pre_next_token(prep, 0);
|
||||
if ((tok.tokt != PPTOK_SYM) || (tok.tokv.sym != SYM_COMMA)) {
|
||||
printf("Error: invalid requests file: invalid DATA line %d (comma)\n", lineno);
|
||||
string_del(req.obj_name);
|
||||
preproc_token_del(&tok);
|
||||
goto failed;
|
||||
}
|
||||
// Empty destructor
|
||||
tok = pre_next_token(prep, 0);
|
||||
if (tok.tokt == PPTOK_NUM) {
|
||||
num_constant_t cst;
|
||||
if (!num_constant_convert(tok.tokv.str, &cst)) {
|
||||
printf("Error: invalid requests file: invalid DATA line %d (num conversion)\n", lineno);
|
||||
string_del(req.obj_name);
|
||||
preproc_token_del(&tok);
|
||||
goto failed;
|
||||
}
|
||||
switch (cst.typ) {
|
||||
case NCT_FLOAT:
|
||||
case NCT_DOUBLE:
|
||||
case NCT_LDOUBLE:
|
||||
printf("Error: invalid requests file: invalid DATA line %d (num conversion)\n", lineno);
|
||||
string_del(req.obj_name);
|
||||
preproc_token_del(&tok);
|
||||
goto failed;
|
||||
case NCT_INT32: req.def.dat.sz = (size_t)cst.val.i32; break;
|
||||
case NCT_UINT32: req.def.dat.sz = (size_t)cst.val.u32; break;
|
||||
case NCT_INT64: req.def.dat.sz = (size_t)cst.val.i64; break;
|
||||
case NCT_UINT64: req.def.dat.sz = (size_t)cst.val.u64; break;
|
||||
}
|
||||
req.def.dat.has_size = 1;
|
||||
// Token moved
|
||||
tok = pre_next_token(prep, 0);
|
||||
if ((tok.tokt != PPTOK_SYM) || (tok.tokv.sym != SYM_RPAREN)) {
|
||||
printf("Error: invalid requests file: invalid DATA line %d (rparen)\n", lineno);
|
||||
string_del(req.obj_name);
|
||||
preproc_token_del(&tok);
|
||||
goto failed;
|
||||
}
|
||||
// Empty destructor
|
||||
tok = pre_next_token(prep, 0);
|
||||
}
|
||||
if (tok.tokt != PPTOK_NEWLINE) {
|
||||
printf("Error: invalid requests file: invalid DATA line %d (newline)\n", lineno);
|
||||
string_del(req.obj_name);
|
||||
preproc_token_del(&tok);
|
||||
goto failed;
|
||||
}
|
||||
if (if_depth == entered_depth) {
|
||||
if (!vector_push(requests, ret, req)) {
|
||||
printf("Error: failed to add request for %s\n", string_content(req.obj_name));
|
||||
string_del(req.obj_name);
|
||||
// Empty destructor
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
++lineno;
|
||||
} else {
|
||||
if (is_comment) {
|
||||
preproc_token_del(&tok);
|
||||
tok = pre_next_newline_token(prep); // Returns a newline
|
||||
++lineno;
|
||||
continue;
|
||||
}
|
||||
printf("Error: invalid requests file: invalid token:\n");
|
||||
preproc_token_print(&tok);
|
||||
preproc_token_del(&tok);
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
failed:
|
||||
prepare_del(prep);
|
||||
vector_del(requests, ret);
|
||||
return NULL;
|
||||
|
||||
success:
|
||||
prepare_del(prep);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int is_simple_type_ptr_to(type_t *typ, int *needs_D, int *needs_my) {
|
||||
switch (typ->typ) {
|
||||
case TYPE_BUILTIN:
|
||||
return 1; // Assume pointers to builtin are simple
|
||||
case TYPE_ARRAY:
|
||||
if (typ->val.array.array_sz == (size_t)-1) return 0; // VLA are not simple
|
||||
return is_simple_type_ptr_to(typ->val.array.typ, needs_D, needs_my);
|
||||
case TYPE_STRUCT_UNION:
|
||||
if (typ->val.st->explicit_simple) return 1;
|
||||
if (typ->_internal_use) return 1; // Recursive structures are OK as long as every other members are OK
|
||||
if (!typ->val.st->is_defined) return 1; // Undefined structures are OK since they are opaque
|
||||
typ->_internal_use = 1;
|
||||
for (size_t i = 0; i < typ->val.st->nmembers; ++i) {
|
||||
st_member_t *mem = &typ->val.st->members[i];
|
||||
if (!is_simple_type_ptr_to(mem->typ, needs_D, needs_my)) {
|
||||
typ->_internal_use = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
typ->_internal_use = 0;
|
||||
return 1;
|
||||
case TYPE_ENUM:
|
||||
return is_simple_type_ptr_to(typ->val.typ, needs_D, needs_my);
|
||||
case TYPE_PTR:
|
||||
return is_simple_type_ptr_to(typ->val.typ, needs_D, needs_my);
|
||||
case TYPE_FUNCTION:
|
||||
*needs_my = 1;
|
||||
return 1;
|
||||
default:
|
||||
printf("Error: is_simple_type_ptr_to on unknown type %u\n", typ->typ);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
static int is_simple_type(type_t *typ, int *needs_D, int *needs_my) {
|
||||
switch (typ->typ) {
|
||||
case TYPE_BUILTIN:
|
||||
return 1; // Assume pointers to builtin are simple
|
||||
case TYPE_ARRAY:
|
||||
if (typ->val.array.array_sz == (size_t)-1) return 0; // VLA are not simple
|
||||
return is_simple_type_ptr_to(typ->val.array.typ, needs_D, needs_my);
|
||||
case TYPE_STRUCT_UNION:
|
||||
if (typ->val.st->explicit_simple) return 1;
|
||||
if (typ->_internal_use) return 1; // Recursive structures are OK as long as every other members are OK
|
||||
// if (!typ->val.st->is_defined) return 1; // Undefined structures are OK since they are opaque
|
||||
// To be safe, don't allow opaque structures
|
||||
if (!typ->val.st->is_defined) return 0;
|
||||
typ->_internal_use = 1;
|
||||
for (size_t i = 0; i < typ->val.st->nmembers; ++i) {
|
||||
st_member_t *mem = &typ->val.st->members[i];
|
||||
if (!is_simple_type(mem->typ, needs_D, needs_my)) {
|
||||
typ->_internal_use = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
typ->_internal_use = 0;
|
||||
return 1;
|
||||
case TYPE_ENUM:
|
||||
return is_simple_type(typ->val.typ, needs_D, needs_my);
|
||||
case TYPE_PTR:
|
||||
return is_simple_type_ptr_to(typ->val.typ, needs_D, needs_my);
|
||||
case TYPE_FUNCTION:
|
||||
// Functions should be handled differently (GO instead of DATA)
|
||||
return 0;
|
||||
default:
|
||||
printf("Error: is_simple_type on unknown type %u\n", typ->typ);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int convert_type(string_t *dest, type_t *typ, int is_ret, int *needs_D, int *needs_my, string_t *obj_name) {
|
||||
if (typ->is_atomic) {
|
||||
printf("TODO: convert_type for atomic types\n");
|
||||
return 0;
|
||||
}
|
||||
switch (typ->typ) {
|
||||
case TYPE_BUILTIN: {
|
||||
int has_char = 0;
|
||||
char c;
|
||||
switch (typ->val.builtin) {
|
||||
case BTT_VOID: has_char = 1; c = 'v'; break;
|
||||
case BTT_BOOL: has_char = 1; c = 'i'; break;
|
||||
case BTT_CHAR: has_char = 1; c = 'c'; break;
|
||||
case BTT_SCHAR: has_char = 1; c = 'c'; break;
|
||||
case BTT_UCHAR: has_char = 1; c = 'C'; break;
|
||||
case BTT_SHORT: has_char = 1; c = 'w'; break;
|
||||
case BTT_SSHORT: has_char = 1; c = 'w'; break;
|
||||
case BTT_USHORT: has_char = 1; c = 'W'; break;
|
||||
case BTT_INT: has_char = 1; c = 'i'; break;
|
||||
case BTT_SINT: has_char = 1; c = 'i'; break;
|
||||
case BTT_UINT: has_char = 1; c = 'u'; break;
|
||||
case BTT_LONG: has_char = 1; c = 'l'; break;
|
||||
case BTT_SLONG: has_char = 1; c = 'l'; break;
|
||||
case BTT_ULONG: has_char = 1; c = 'L'; break;
|
||||
case BTT_LONGLONG: has_char = 1; c = 'I'; break;
|
||||
case BTT_SLONGLONG: has_char = 1; c = 'I'; break;
|
||||
case BTT_ULONGLONG: has_char = 1; c = 'U'; break;
|
||||
case BTT_INT128: has_char = 1; c = 'H'; break; // TODO: Is 'H' for signed and unsigned?
|
||||
case BTT_SINT128: has_char = 1; c = 'H'; break; // Is 'H' for signed and unsigned?
|
||||
case BTT_UINT128: has_char = 1; c = 'H'; break; // Is 'H' for signed and unsigned?
|
||||
case BTT_S8: has_char = 1; c = 'c'; break;
|
||||
case BTT_U8: has_char = 1; c = 'C'; break;
|
||||
case BTT_S16: has_char = 1; c = 'w'; break;
|
||||
case BTT_U16: has_char = 1; c = 'W'; break;
|
||||
case BTT_S32: has_char = 1; c = 'i'; break;
|
||||
case BTT_U32: has_char = 1; c = 'u'; break;
|
||||
case BTT_S64: has_char = 1; c = 'I'; break;
|
||||
case BTT_U64: has_char = 1; c = 'U'; break;
|
||||
case BTT_FLOAT: has_char = 1; c = 'f'; break;
|
||||
case BTT_CFLOAT: has_char = 1; c = 'x'; break;
|
||||
case BTT_IFLOAT: has_char = 1; c = 'f'; break;
|
||||
case BTT_DOUBLE: has_char = 1; c = 'd'; break;
|
||||
case BTT_CDOUBLE: has_char = 1; c = 'X'; break;
|
||||
case BTT_IDOUBLE: has_char = 1; c = 'd'; break;
|
||||
case BTT_LONGDOUBLE: *needs_D = 1; has_char = 1; c = 'D'; break;
|
||||
case BTT_CLONGDOUBLE: *needs_D = 1; has_char = 1; c = 'Y'; break;
|
||||
case BTT_ILONGDOUBLE: *needs_D = 1; has_char = 1; c = 'D'; break;
|
||||
case BTT_VA_LIST: has_char = 1; c = 'A'; break;
|
||||
default:
|
||||
printf("Error: convert_type on unknown builtin %u\n", typ->val.builtin);
|
||||
return 0;
|
||||
}
|
||||
if (has_char) {
|
||||
if (!string_add_char(dest, c)) {
|
||||
printf("Error: failed to add type char for %s\n", builtin2str[typ->val.builtin]);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
printf("Internal error: unknown state builtin=%u\n", typ->val.builtin);
|
||||
return 0;
|
||||
} }
|
||||
case TYPE_ARRAY:
|
||||
printf("Error: convert_type on raw array\n");
|
||||
return 0;
|
||||
case TYPE_STRUCT_UNION:
|
||||
if (!typ->is_validated || typ->is_incomplete) {
|
||||
printf("Error: incomplete return type for %s\n", string_content(obj_name));
|
||||
return 0;
|
||||
}
|
||||
if (is_ret) {
|
||||
if (typ->szinfo.size <= 8) {
|
||||
if (!string_add_char(dest, 'U')) {
|
||||
printf("Error: failed to add type char for structure return\n");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
} else if (typ->szinfo.size <= 16) {
|
||||
if (!string_add_char(dest, 'H')) {
|
||||
printf("Error: failed to add type char for large structure return\n");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
if (!string_add_char(dest, 'p')) {
|
||||
printf("Error: failed to add type char for very large structure return\n");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
if (typ->val.st->nmembers == 1) {
|
||||
return convert_type(dest, typ->val.st->members[0].typ, is_ret, needs_D, needs_my, obj_name);
|
||||
}
|
||||
printf("TODO: convert_type on structure as argument (%s)\n", string_content(obj_name));
|
||||
return 0;
|
||||
}
|
||||
case TYPE_ENUM:
|
||||
return convert_type(dest, typ->val.typ, is_ret, needs_D, needs_my, obj_name);
|
||||
case TYPE_PTR:
|
||||
if ((typ->val.typ->typ == TYPE_STRUCT_UNION) && typ->val.typ->val.st->tag && !strcmp(string_content(typ->val.typ->val.st->tag), "_IO_FILE")) {
|
||||
if (!string_add_char(dest, 'S')) {
|
||||
printf("Error: failed to add type char for %s\n", builtin2str[typ->val.builtin]);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (is_simple_type_ptr_to(typ->val.typ, needs_D, needs_my)) {
|
||||
if (!string_add_char(dest, 'p')) {
|
||||
printf("Error: failed to add type char for simple pointer\n");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
*needs_my = 1;
|
||||
if (!string_add_char(dest, 'p')) {
|
||||
printf("Error: failed to add type char for %s\n", builtin2str[typ->val.builtin]);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
case TYPE_FUNCTION:
|
||||
printf("Error: convert_type on raw function\n");
|
||||
return 0;
|
||||
default:
|
||||
printf("Error: convert_type on unknown type %u\n", typ->typ);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
static int convert_type_post(string_t *dest, type_t *typ, string_t *obj_name) {
|
||||
if (typ->is_atomic) {
|
||||
printf("TODO: convert_type_post for atomic types\n");
|
||||
return 0;
|
||||
}
|
||||
switch (typ->typ) {
|
||||
case TYPE_BUILTIN: return 1;
|
||||
case TYPE_ARRAY: return 1;
|
||||
case TYPE_STRUCT_UNION:
|
||||
if (!typ->is_validated || typ->is_incomplete) {
|
||||
printf("Error: incomplete return type for %s\n", string_content(obj_name));
|
||||
return 0;
|
||||
}
|
||||
if (typ->szinfo.size <= 16) {
|
||||
return 1;
|
||||
} else {
|
||||
if (!string_add_char(dest, 'p')) {
|
||||
printf("Error: failed to add type char for very large structure return as parameter\n");
|
||||
return 0;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
case TYPE_ENUM: return 1;
|
||||
case TYPE_PTR: return 1;
|
||||
case TYPE_FUNCTION: return 1;
|
||||
default:
|
||||
printf("Error: convert_type_post on unknown type %u\n", typ->typ);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int solve_request(request_t *req, type_t *typ) {
|
||||
if (typ->typ == TYPE_FUNCTION) {
|
||||
int needs_D = 0, needs_my = req->has_default && (req->def.rty == RQT_FUN_MY), needs_2 = 0;
|
||||
int convert_post;
|
||||
req->val.fun.typ = string_new();
|
||||
if (!req->val.fun.typ) {
|
||||
printf("Error: failed to create function type string\n");
|
||||
return 0;
|
||||
}
|
||||
if (!convert_type(req->val.fun.typ, typ->val.fun.ret, 1, &needs_D, &needs_my, req->obj_name)) goto fun_fail;
|
||||
if (!string_add_char(req->val.fun.typ, 'F')) {
|
||||
printf("Error: failed to add convention char\n");
|
||||
goto fun_fail;
|
||||
}
|
||||
if (req->has_default && (req->def.rty == RQT_FUN_MY) && (string_content(req->def.fun.typ)[2] == 'E')) {
|
||||
if (!string_add_char(req->val.fun.typ, 'E')) {
|
||||
printf("Error: failed to add emu char\n");
|
||||
goto fun_fail;
|
||||
}
|
||||
}
|
||||
convert_post = convert_type_post(req->val.fun.typ, typ->val.fun.ret, req->obj_name);
|
||||
if (!convert_post) goto fun_fail;
|
||||
if (typ->val.fun.nargs == (size_t)-1) {
|
||||
printf("Warning: assuming empty specification is void specification\n");
|
||||
if (convert_post == 1) {
|
||||
if (!string_add_char(req->val.fun.typ, 'v')) {
|
||||
printf("Error: failed to add void specification char\n");
|
||||
goto fun_fail;
|
||||
}
|
||||
}
|
||||
} else if (!typ->val.fun.nargs && !typ->val.fun.has_varargs) {
|
||||
if (convert_post == 1) {
|
||||
if (!string_add_char(req->val.fun.typ, 'v')) {
|
||||
printf("Error: failed to add void specification char\n");
|
||||
goto fun_fail;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < typ->val.fun.nargs; ++i) {
|
||||
if (!convert_type(req->val.fun.typ, typ->val.fun.args[i], 0, &needs_D, &needs_my, req->obj_name)) goto fun_fail;
|
||||
}
|
||||
if (typ->val.fun.has_varargs) {
|
||||
if (!string_add_char(req->val.fun.typ, 'V')) {
|
||||
printf("Error: failed to add type char for %s\n", builtin2str[typ->val.builtin]);
|
||||
goto fun_fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fun_succ:
|
||||
if (req->has_default && (req->def.rty == RQT_FUN_2) && !needs_my) {
|
||||
needs_2 = 1;
|
||||
req->val.fun.fun2 = string_dup(req->def.fun.fun2);
|
||||
if (!req->val.fun.fun2) {
|
||||
printf("Error: failed to duplicate string (request for function %s with default redirection)\n", string_content(req->obj_name));
|
||||
return 0;
|
||||
}
|
||||
} else if (req->has_default && (req->def.rty == RQT_FUN_D) && !needs_my) {
|
||||
needs_2 = 0;
|
||||
req->val.fun.fun2 = string_dup(req->def.fun.fun2);
|
||||
if (!req->val.fun.fun2) {
|
||||
printf("Error: failed to duplicate string (request for function %s with long double types)\n", string_content(req->obj_name));
|
||||
return 0;
|
||||
}
|
||||
} else if (!needs_my && needs_D) {
|
||||
req->val.fun.fun2 = string_new();
|
||||
if (!req->val.fun.fun2) {
|
||||
printf("Error: failed to create empty string (request for function %s with long double types)\n", string_content(req->obj_name));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
req->val.rty =
|
||||
needs_my ? RQT_FUN_MY :
|
||||
needs_2 ? RQT_FUN_2 :
|
||||
needs_D ? RQT_FUN_D : RQT_FUN;
|
||||
req->has_val = 1;
|
||||
return 1;
|
||||
|
||||
fun_fail:
|
||||
string_del(req->val.fun.typ);
|
||||
return 0;
|
||||
} else {
|
||||
int needs_D = 0, needs_my = req->has_default && (req->def.rty == RQT_FUN_MY);
|
||||
if (is_simple_type(typ, &needs_D, &needs_my)) {
|
||||
// TODO: Hmm...
|
||||
req->val.rty = needs_my ? RQT_DATAM : req->has_default ? req->def.rty : req->weak ? RQT_DATAV : RQT_DATA;
|
||||
req->val.dat.has_size = 1;
|
||||
req->val.dat.sz = typ->szinfo.size;
|
||||
req->has_val = 1;
|
||||
return 1;
|
||||
} else {
|
||||
printf("Error: TODO: solve_request for data %s with non-simple type ", string_content(req->obj_name));
|
||||
type_print(typ);
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
int solve_request_map(request_t *req, khash_t(type_map) *decl_map) {
|
||||
khiter_t it = kh_get(type_map, decl_map, string_content(req->obj_name));
|
||||
if (it == kh_end(decl_map)) {
|
||||
if (string_content(req->obj_name)[0] != '_') {
|
||||
printf("Error: %s was not declared\n", string_content(req->obj_name));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return solve_request(req, kh_val(decl_map, it));
|
||||
}
|
||||
int solve_requests(VECTOR(requests) *reqs, khash_t(type_map) *decl_map) {
|
||||
int ret = 1;
|
||||
vector_for(requests, req, reqs) {
|
||||
if (!solve_request_map(req, decl_map)) ret = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
50
wrapperhelper/src/generator.h
Normal file
50
wrapperhelper/src/generator.h
Normal file
@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef GENERATOR_H
|
||||
#define GENERATOR_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "cstring.h"
|
||||
#include "lang.h"
|
||||
|
||||
typedef struct request_s {
|
||||
string_t *obj_name;
|
||||
_Bool has_default, default_comment;
|
||||
_Bool has_val;
|
||||
_Bool weak;
|
||||
struct {
|
||||
enum request_type_e {
|
||||
RQT_FUN,
|
||||
RQT_FUN_2,
|
||||
RQT_FUN_MY,
|
||||
RQT_FUN_D,
|
||||
|
||||
RQT_DATA,
|
||||
RQT_DATAV,
|
||||
RQT_DATAB,
|
||||
RQT_DATAM,
|
||||
} rty;
|
||||
union {
|
||||
struct {
|
||||
string_t *typ;
|
||||
string_t *fun2;
|
||||
} fun;
|
||||
struct {
|
||||
int has_size;
|
||||
size_t sz;
|
||||
} dat;
|
||||
};
|
||||
} def, val;
|
||||
} request_t;
|
||||
VECTOR_DECLARE(requests, request_t)
|
||||
void request_print(request_t *req);
|
||||
void request_print_check(request_t *req);
|
||||
void output_from_requests(FILE *f, VECTOR(requests) *reqs);
|
||||
|
||||
VECTOR(requests) *requests_from_file(const char *filename, FILE *f); // Takes ownership of f
|
||||
int solve_request(request_t *req, type_t *typ);
|
||||
int solve_request_map(request_t *req, khash_t(type_map) *decl_map);
|
||||
int solve_requests(VECTOR(requests) *reqs, khash_t(type_map) *decl_map);
|
||||
|
||||
#endif // GENERATOR_H
|
699
wrapperhelper/src/khash.h
Normal file
699
wrapperhelper/src/khash.h
Normal file
@ -0,0 +1,699 @@
|
||||
/* The MIT License
|
||||
|
||||
Copyright (c) 2008, 2009, 2011 by Attractive Chaos <attractor@live.co.uk>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
An example:
|
||||
|
||||
#include "khash.h"
|
||||
KHASH_MAP_INIT_INT(32, char)
|
||||
int main() {
|
||||
int ret, is_missing;
|
||||
khiter_t k;
|
||||
khash_t(32) *h = kh_init(32);
|
||||
k = kh_put(32, h, 5, &ret);
|
||||
kh_value(h, k) = 10;
|
||||
k = kh_get(32, h, 10);
|
||||
is_missing = (k == kh_end(h));
|
||||
k = kh_get(32, h, 5);
|
||||
kh_del(32, h, k);
|
||||
for (k = kh_begin(h); k != kh_end(h); ++k)
|
||||
if (kh_exist(h, k)) kh_value(h, k) = 1;
|
||||
kh_destroy(32, h);
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
2013-05-02 (0.2.8):
|
||||
|
||||
* Use quadratic probing. When the capacity is power of 2, stepping function
|
||||
i*(i+1)/2 guarantees to traverse each bucket. It is better than double
|
||||
hashing on cache performance and is more robust than linear probing.
|
||||
|
||||
In theory, double hashing should be more robust than quadratic probing.
|
||||
However, my implementation is probably not for large hash tables, because
|
||||
the second hash function is closely tied to the first hash function,
|
||||
which reduce the effectiveness of double hashing.
|
||||
|
||||
Reference: http://research.cs.vt.edu/AVresearch/hashing/quadratic.php
|
||||
|
||||
2011-12-29 (0.2.7):
|
||||
|
||||
* Minor code clean up; no actual effect.
|
||||
|
||||
2011-09-16 (0.2.6):
|
||||
|
||||
* The capacity is a power of 2. This seems to dramatically improve the
|
||||
speed for simple keys. Thank Zilong Tan for the suggestion. Reference:
|
||||
|
||||
- http://code.google.com/p/ulib/
|
||||
- http://nothings.org/computer/judy/
|
||||
|
||||
* Allow to optionally use linear probing which usually has better
|
||||
performance for random input. Double hashing is still the default as it
|
||||
is more robust to certain non-random input.
|
||||
|
||||
* Added Wang's integer hash function (not used by default). This hash
|
||||
function is more robust to certain non-random input.
|
||||
|
||||
2011-02-14 (0.2.5):
|
||||
|
||||
* Allow to declare global functions.
|
||||
|
||||
2009-09-26 (0.2.4):
|
||||
|
||||
* Improve portability
|
||||
|
||||
2008-09-19 (0.2.3):
|
||||
|
||||
* Corrected the example
|
||||
* Improved interfaces
|
||||
|
||||
2008-09-11 (0.2.2):
|
||||
|
||||
* Improved speed a little in kh_put()
|
||||
|
||||
2008-09-10 (0.2.1):
|
||||
|
||||
* Added kh_clear()
|
||||
* Fixed a compiling error
|
||||
|
||||
2008-09-02 (0.2.0):
|
||||
|
||||
* Changed to token concatenation which increases flexibility.
|
||||
|
||||
2008-08-31 (0.1.2):
|
||||
|
||||
* Fixed a bug in kh_get(), which has not been tested previously.
|
||||
|
||||
2008-08-31 (0.1.1):
|
||||
|
||||
* Added destructor
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __AC_KHASH_H
|
||||
#define __AC_KHASH_H
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wsign-conversion"
|
||||
#pragma GCC diagnostic ignored "-Wconversion"
|
||||
|
||||
/*!
|
||||
@header
|
||||
|
||||
Generic hash table library.
|
||||
*/
|
||||
|
||||
#define AC_VERSION_KHASH_H "0.2.8"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
/* compiler specific configuration */
|
||||
|
||||
#if UINT_MAX == 0xffffffffu
|
||||
typedef unsigned int khint32_t;
|
||||
#elif ULONG_MAX == 0xffffffffu
|
||||
typedef unsigned long khint32_t;
|
||||
#endif
|
||||
|
||||
#if ULONG_MAX == ULLONG_MAX
|
||||
typedef unsigned long khint64_t;
|
||||
#else
|
||||
typedef unsigned long long khint64_t;
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define kh_inline __inline
|
||||
#else
|
||||
#define kh_inline inline
|
||||
#endif
|
||||
|
||||
typedef khint32_t khint_t;
|
||||
typedef khint_t khiter_t;
|
||||
|
||||
#define __ac_isempty(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&2)
|
||||
#define __ac_isdel(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&1)
|
||||
#define __ac_iseither(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&3)
|
||||
#define __ac_set_isdel_false(flag, i) (flag[i>>4]&=~(1u<<((i&0xfU)<<1)))
|
||||
#define __ac_set_isempty_false(flag, i) (flag[i>>4]&=~(2u<<((i&0xfU)<<1)))
|
||||
#define __ac_set_isboth_false(flag, i) (flag[i>>4]&=~(3u<<((i&0xfU)<<1)))
|
||||
#define __ac_set_isdel_true(flag, i) (flag[i>>4]|=1u<<((i&0xfU)<<1))
|
||||
|
||||
#define __ac_fsize(m) ((m) < 16? 1 : (m)>>4)
|
||||
|
||||
#ifndef kroundup32
|
||||
#define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))
|
||||
#endif
|
||||
|
||||
#ifndef kcalloc
|
||||
#define kcalloc(N,Z) calloc(N,Z)
|
||||
#endif
|
||||
#ifndef kmalloc
|
||||
#define kmalloc(Z) malloc(Z)
|
||||
#endif
|
||||
#ifndef krealloc
|
||||
#define krealloc(P,Z) realloc(P,Z)
|
||||
#endif
|
||||
#ifndef kfree
|
||||
#define kfree(P) free(P)
|
||||
#endif
|
||||
|
||||
static const double __ac_HASH_UPPER = 0.77;
|
||||
|
||||
#define __KHASH_TYPE(name, khkey_t, khval_t) \
|
||||
typedef struct kh_##name##_s{ \
|
||||
khint_t n_buckets, size, n_occupied, upper_bound; \
|
||||
khint32_t *flags; \
|
||||
khkey_t *keys; \
|
||||
khval_t *vals; \
|
||||
} kh_##name##_t;
|
||||
|
||||
#define __KHASH_PROTOTYPES(name, khkey_t, khval_t) \
|
||||
extern kh_##name##_t *kh_init_##name(void); \
|
||||
extern void kh_destroy_##name(kh_##name##_t *h); \
|
||||
extern void kh_clear_##name(kh_##name##_t *h); \
|
||||
extern khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key); \
|
||||
extern int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets); \
|
||||
extern khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret); \
|
||||
extern void kh_del_##name(kh_##name##_t *h, khint_t x);
|
||||
|
||||
#define __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
|
||||
SCOPE kh_##name##_t *kh_init_##name(void) { \
|
||||
return (kh_##name##_t*)kcalloc(1, sizeof(kh_##name##_t)); \
|
||||
} \
|
||||
SCOPE void kh_destroy_##name(kh_##name##_t *h) \
|
||||
{ \
|
||||
if (h) { \
|
||||
kfree((void *)h->keys); kfree(h->flags); \
|
||||
kfree((void *)h->vals); \
|
||||
kfree(h); \
|
||||
} \
|
||||
} \
|
||||
SCOPE void kh_clear_##name(kh_##name##_t *h) \
|
||||
{ \
|
||||
if (h && h->flags) { \
|
||||
memset(h->flags, 0xaa, __ac_fsize(h->n_buckets) * sizeof(khint32_t)); \
|
||||
h->size = h->n_occupied = 0; \
|
||||
} \
|
||||
} \
|
||||
__attribute__((pure)) SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) \
|
||||
{ \
|
||||
if (h->n_buckets) { \
|
||||
khint_t k, i, last, mask, step = 0; \
|
||||
mask = h->n_buckets - 1; \
|
||||
k = __hash_func(key); i = k & mask; \
|
||||
last = i; \
|
||||
while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
|
||||
i = (i + (++step)) & mask; \
|
||||
if (i == last) return h->n_buckets; \
|
||||
} \
|
||||
return __ac_iseither(h->flags, i)? h->n_buckets : i; \
|
||||
} else return 0; \
|
||||
} \
|
||||
SCOPE int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets) \
|
||||
{ /* This function uses 0.25*n_buckets bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets. */ \
|
||||
khint32_t *new_flags = 0; \
|
||||
khint_t j = 1; \
|
||||
{ \
|
||||
kroundup32(new_n_buckets); \
|
||||
if (new_n_buckets < 4) new_n_buckets = 4; \
|
||||
if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) j = 0; /* requested size is too small */ \
|
||||
else { /* hash table size to be changed (shrink or expand); rehash */ \
|
||||
new_flags = (khint32_t*)kmalloc(__ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
|
||||
if (!new_flags) return -1; \
|
||||
memset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
|
||||
if (h->n_buckets < new_n_buckets) { /* expand */ \
|
||||
khkey_t *new_keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
|
||||
if (!new_keys) { kfree(new_flags); return -1; } \
|
||||
h->keys = new_keys; \
|
||||
if (kh_is_map) { \
|
||||
khval_t *new_vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
|
||||
if (!new_vals) { kfree(new_flags); return -1; } \
|
||||
h->vals = new_vals; \
|
||||
} \
|
||||
} /* otherwise shrink */ \
|
||||
} \
|
||||
} \
|
||||
if (j) { /* rehashing is needed */ \
|
||||
for (j = 0; j != h->n_buckets; ++j) { \
|
||||
if (__ac_iseither(h->flags, j) == 0) { \
|
||||
khkey_t key = h->keys[j]; \
|
||||
khval_t val; \
|
||||
khint_t new_mask; \
|
||||
new_mask = new_n_buckets - 1; \
|
||||
if (kh_is_map) val = h->vals[j]; \
|
||||
__ac_set_isdel_true(h->flags, j); \
|
||||
while (1) { /* kick-out process; sort of like in Cuckoo hashing */ \
|
||||
khint_t k, i, step = 0; \
|
||||
k = __hash_func(key); \
|
||||
i = k & new_mask; \
|
||||
while (!__ac_isempty(new_flags, i)) i = (i + (++step)) & new_mask; \
|
||||
__ac_set_isempty_false(new_flags, i); \
|
||||
if (i < h->n_buckets && __ac_iseither(h->flags, i) == 0) { /* kick out the existing element */ \
|
||||
{ khkey_t tmp = h->keys[i]; h->keys[i] = key; key = tmp; } \
|
||||
if (kh_is_map) { khval_t tmp = h->vals[i]; h->vals[i] = val; val = tmp; } \
|
||||
__ac_set_isdel_true(h->flags, i); /* mark it as deleted in the old hash table */ \
|
||||
} else { /* write the element and jump out of the loop */ \
|
||||
h->keys[i] = key; \
|
||||
if (kh_is_map) h->vals[i] = val; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
if (h->n_buckets > new_n_buckets) { /* shrink the hash table */ \
|
||||
h->keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
|
||||
if (kh_is_map) h->vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
|
||||
} \
|
||||
kfree(h->flags); /* free the working space */ \
|
||||
h->flags = new_flags; \
|
||||
h->n_buckets = new_n_buckets; \
|
||||
h->n_occupied = h->size; \
|
||||
h->upper_bound = (khint_t)(h->n_buckets * __ac_HASH_UPPER + 0.5); \
|
||||
} \
|
||||
return 0; \
|
||||
} \
|
||||
SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) \
|
||||
{ \
|
||||
khint_t x; \
|
||||
if (h->n_occupied >= h->upper_bound) { /* update the hash table */ \
|
||||
if (h->n_buckets > (h->size<<1)) { \
|
||||
if (kh_resize_##name(h, h->n_buckets - 1) < 0) { /* clear "deleted" elements */ \
|
||||
*ret = -1; return h->n_buckets; \
|
||||
} \
|
||||
} else if (kh_resize_##name(h, h->n_buckets + 1) < 0) { /* expand the hash table */ \
|
||||
*ret = -1; return h->n_buckets; \
|
||||
} \
|
||||
} /* TODO: to implement automatically shrinking; resize() already support shrinking */ \
|
||||
{ \
|
||||
khint_t k, i, site, last, mask = h->n_buckets - 1, step = 0; \
|
||||
x = site = h->n_buckets; k = __hash_func(key); i = k & mask; \
|
||||
if (__ac_isempty(h->flags, i)) x = i; /* for speed up */ \
|
||||
else { \
|
||||
last = i; \
|
||||
while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
|
||||
if (__ac_isdel(h->flags, i)) site = i; \
|
||||
i = (i + (++step)) & mask; \
|
||||
if (i == last) { x = site; break; } \
|
||||
} \
|
||||
if (x == h->n_buckets) { \
|
||||
if (__ac_isempty(h->flags, i) && site != h->n_buckets) x = site; \
|
||||
else x = i; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
if (__ac_isempty(h->flags, x)) { /* not present at all */ \
|
||||
h->keys[x] = key; \
|
||||
__ac_set_isboth_false(h->flags, x); \
|
||||
++h->size; ++h->n_occupied; \
|
||||
*ret = 1; \
|
||||
} else if (__ac_isdel(h->flags, x)) { /* deleted */ \
|
||||
h->keys[x] = key; \
|
||||
__ac_set_isboth_false(h->flags, x); \
|
||||
++h->size; \
|
||||
*ret = 2; \
|
||||
} else *ret = 0; /* Don't touch h->keys[x] if present and not deleted */ \
|
||||
return x; \
|
||||
} \
|
||||
SCOPE void kh_del_##name(kh_##name##_t *h, khint_t x) \
|
||||
{ \
|
||||
if (x != h->n_buckets && !__ac_iseither(h->flags, x)) { \
|
||||
__ac_set_isdel_true(h->flags, x); \
|
||||
--h->size; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define KHASH_DECLARE(name, khkey_t, khval_t) \
|
||||
__KHASH_TYPE(name, khkey_t, khval_t) \
|
||||
__KHASH_PROTOTYPES(name, khkey_t, khval_t)
|
||||
|
||||
#define KHASH_INIT2(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
|
||||
__KHASH_TYPE(name, khkey_t, khval_t) \
|
||||
__KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)
|
||||
|
||||
#define KHASH_INIT(name, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
|
||||
KHASH_INIT2(name, static kh_inline, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)
|
||||
|
||||
/* --- BEGIN OF HASH FUNCTIONS --- */
|
||||
|
||||
/*! @function
|
||||
@abstract Integer hash function
|
||||
@param key The integer [khint32_t]
|
||||
@return The hash value [khint_t]
|
||||
*/
|
||||
#define kh_int_hash_func(key) (khint32_t)(key)
|
||||
/*! @function
|
||||
@abstract Integer comparison function
|
||||
*/
|
||||
#define kh_int_hash_equal(a, b) ((a) == (b))
|
||||
/*! @function
|
||||
@abstract 64-bit integer hash function
|
||||
@param key The integer [khint64_t]
|
||||
@return The hash value [khint_t]
|
||||
*/
|
||||
#define kh_int64_hash_func(key) (khint32_t)((key)>>33^(key)^(key)<<11)
|
||||
/*! @function
|
||||
@abstract 64-bit integer comparison function
|
||||
*/
|
||||
#define kh_int64_hash_equal(a, b) ((a) == (b))
|
||||
/*! @function
|
||||
@abstract const char* hash function
|
||||
@param s Pointer to a null terminated string
|
||||
@return The hash value
|
||||
*/
|
||||
__attribute__((pure)) static kh_inline khint_t __ac_X31_hash_string(const char *s)
|
||||
{
|
||||
khint_t h = (khint_t)*s;
|
||||
if (h) for (++s ; *s; ++s) h = (h << 5) - h + (khint_t)*s;
|
||||
return h;
|
||||
}
|
||||
/*! @function
|
||||
@abstract Another interface to const char* hash function
|
||||
@param key Pointer to a null terminated string [const char*]
|
||||
@return The hash value [khint_t]
|
||||
*/
|
||||
#define kh_str_hash_func(key) __ac_X31_hash_string(key)
|
||||
/*! @function
|
||||
@abstract Const char* comparison function
|
||||
*/
|
||||
#define kh_str_hash_equal(a, b) ((!a && !b) || (a && b && strcmp(a, b) == 0))
|
||||
|
||||
static kh_inline khint_t __ac_Wang_hash(khint_t key)
|
||||
{
|
||||
key += ~(key << 15);
|
||||
key ^= (key >> 10);
|
||||
key += (key << 3);
|
||||
key ^= (key >> 6);
|
||||
key += ~(key << 11);
|
||||
key ^= (key >> 16);
|
||||
return key;
|
||||
}
|
||||
#define kh_int_hash_func2(k) __ac_Wang_hash((khint_t)key)
|
||||
|
||||
/* --- END OF HASH FUNCTIONS --- */
|
||||
|
||||
/* Other convenient macros... */
|
||||
|
||||
/*!
|
||||
@abstract Type of the hash table.
|
||||
@param name Name of the hash table [symbol]
|
||||
*/
|
||||
#define khash_t(name) kh_##name##_t
|
||||
|
||||
/*! @function
|
||||
@abstract Initiate a hash table.
|
||||
@param name Name of the hash table [symbol]
|
||||
@return Pointer to the hash table [khash_t(name)*]
|
||||
*/
|
||||
#define kh_init(name) kh_init_##name()
|
||||
|
||||
/*! @function
|
||||
@abstract Destroy a hash table.
|
||||
@param name Name of the hash table [symbol]
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
*/
|
||||
#define kh_destroy(name, h) kh_destroy_##name(h)
|
||||
|
||||
/*! @function
|
||||
@abstract Reset a hash table without deallocating memory.
|
||||
@param name Name of the hash table [symbol]
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
*/
|
||||
#define kh_clear(name, h) kh_clear_##name(h)
|
||||
|
||||
/*! @function
|
||||
@abstract Resize a hash table.
|
||||
@param name Name of the hash table [symbol]
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
@param s New size [khint_t]
|
||||
*/
|
||||
#define kh_resize(name, h, s) kh_resize_##name(h, s)
|
||||
|
||||
/*! @function
|
||||
@abstract Insert a key to the hash table.
|
||||
@param name Name of the hash table [symbol]
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
@param k Key [type of keys]
|
||||
@param r Extra return code: 0 if the key is present in the hash table;
|
||||
1 if the bucket is empty (never used); 2 if the element in
|
||||
the bucket has been deleted [int*]
|
||||
@return Iterator to the inserted element [khint_t]
|
||||
*/
|
||||
#define kh_put(name, h, k, r) kh_put_##name(h, k, r)
|
||||
|
||||
/*! @function
|
||||
@abstract Retrieve a key from the hash table.
|
||||
@param name Name of the hash table [symbol]
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
@param k Key [type of keys]
|
||||
@return Iterator to the found element, or kh_end(h) if the element is absent [khint_t]
|
||||
*/
|
||||
#define kh_get(name, h, k) kh_get_##name(h, k)
|
||||
|
||||
/*! @function
|
||||
@abstract Remove a key from the hash table.
|
||||
@param name Name of the hash table [symbol]
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
@param k Iterator to the element to be deleted [khint_t]
|
||||
*/
|
||||
#define kh_del(name, h, k) kh_del_##name(h, k)
|
||||
|
||||
/*! @function
|
||||
@abstract Test whether a bucket contains data.
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
@param x Iterator to the bucket [khint_t]
|
||||
@return 1 if containing data; 0 otherwise [int]
|
||||
*/
|
||||
#define kh_exist(h, x) (!__ac_iseither((h)->flags, (x)))
|
||||
|
||||
/*! @function
|
||||
@abstract Get key given an iterator
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
@param x Iterator to the bucket [khint_t]
|
||||
@return Key [type of keys]
|
||||
*/
|
||||
#define kh_key(h, x) ((h)->keys[x])
|
||||
|
||||
/*! @function
|
||||
@abstract Get value given an iterator
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
@param x Iterator to the bucket [khint_t]
|
||||
@return Value [type of values]
|
||||
@discussion For hash sets, calling this results in segfault.
|
||||
*/
|
||||
#define kh_val(h, x) ((h)->vals[x])
|
||||
|
||||
/*! @function
|
||||
@abstract Alias of kh_val()
|
||||
*/
|
||||
#define kh_value(h, x) ((h)->vals[x])
|
||||
|
||||
/*! @function
|
||||
@abstract Get the start iterator
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
@return The start iterator [khint_t]
|
||||
*/
|
||||
#define kh_begin(h) (khint_t)(0)
|
||||
|
||||
/*! @function
|
||||
@abstract Get the end iterator
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
@return The end iterator [khint_t]
|
||||
*/
|
||||
#define kh_end(h) ((h)->n_buckets)
|
||||
|
||||
/*! @function
|
||||
@abstract Get the number of elements in the hash table
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
@return Number of elements in the hash table [khint_t]
|
||||
*/
|
||||
#define kh_size(h) ((h)->size)
|
||||
|
||||
/*! @function
|
||||
@abstract Get the number of buckets in the hash table
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
@return Number of buckets in the hash table [khint_t]
|
||||
*/
|
||||
#define kh_n_buckets(h) ((h)->n_buckets)
|
||||
|
||||
/*! @function
|
||||
@abstract Iterate over the entries in the hash table
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
@param kvar Variable to which key will be assigned
|
||||
@param vvar Variable to which value will be assigned
|
||||
@param code Block of code to execute
|
||||
*/
|
||||
#define kh_foreach(h, kvar, vvar, code) { khint_t __i; \
|
||||
for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
|
||||
if (!kh_exist(h,__i)) continue; \
|
||||
(kvar) = kh_key(h,__i); \
|
||||
(vvar) = kh_val(h,__i); \
|
||||
code; \
|
||||
} }
|
||||
|
||||
/*! @function
|
||||
@abstract Iterate over the entries in the hash table
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
@param kvar Variable to which key will be assigned
|
||||
@param code Block of code to execute
|
||||
*/
|
||||
#define kh_foreach_key(h, kvar, code) { khint_t __i; \
|
||||
for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
|
||||
if (!kh_exist(h,__i)) continue; \
|
||||
(kvar) = kh_key(h,__i); \
|
||||
code; \
|
||||
} }
|
||||
|
||||
/*! @function
|
||||
@abstract Iterate over the values in the hash table
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
@param vvar Variable to which value will be assigned
|
||||
@param code Block of code to execute
|
||||
*/
|
||||
#define kh_foreach_value(h, vvar, code) { khint_t __i; \
|
||||
for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
|
||||
if (!kh_exist(h,__i)) continue; \
|
||||
(vvar) = kh_val(h,__i); \
|
||||
code; \
|
||||
} }
|
||||
|
||||
/*! @function
|
||||
@abstract Iterate over the entries in the hash table
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
@param kvar Variable to which key will be assigned
|
||||
@param rvar Variable to which value will be assigned
|
||||
@param code Block of code to execute
|
||||
*/
|
||||
#define kh_foreach_key_value_ref(h, kvar, rvar, code) { khint_t __i; \
|
||||
for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
|
||||
if (!kh_exist(h,__i)) continue; \
|
||||
(kvar) = kh_key(h,__i); \
|
||||
(rvar) = &kh_val(h,__i); \
|
||||
code; \
|
||||
} }
|
||||
|
||||
/*! @function
|
||||
@abstract Iterate over the values in the hash table
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
@param rvar Variable to which value will be assigned
|
||||
@param code Block of code to execute
|
||||
*/
|
||||
#define kh_foreach_value_ref(h, rvar, code) { khint_t __i; \
|
||||
for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
|
||||
if (!kh_exist(h,__i)) continue; \
|
||||
(rvar) = &kh_val(h,__i); \
|
||||
code; \
|
||||
} }
|
||||
|
||||
/* More conenient interfaces */
|
||||
|
||||
/*! @function
|
||||
@abstract Instantiate a hash set containing integer keys
|
||||
@param name Name of the hash table [symbol]
|
||||
*/
|
||||
#define KHASH_SET_INIT_INT(name) \
|
||||
KHASH_INIT(name, khint32_t, char, 0, kh_int_hash_func, kh_int_hash_equal)
|
||||
|
||||
#define KHASH_SET_DECLARE_INT(name) \
|
||||
KHASH_DECLARE(name, khint32_t, char)
|
||||
|
||||
#define KHASH_SET_IMPL_INT(name) \
|
||||
__KHASH_IMPL(name, , khint32_t, char, 0, kh_int_hash_func, kh_int_hash_equal)
|
||||
|
||||
/*! @function
|
||||
@abstract Instantiate a hash map containing integer keys
|
||||
@param name Name of the hash table [symbol]
|
||||
@param khval_t Type of values [type]
|
||||
*/
|
||||
#define KHASH_MAP_INIT_INT(name, khval_t) \
|
||||
KHASH_INIT(name, khint32_t, khval_t, 1, kh_int_hash_func, kh_int_hash_equal)
|
||||
|
||||
#define KHASH_MAP_DECLARE_INT(name, khval_t) \
|
||||
KHASH_DECLARE(name, khint32_t, khval_t)
|
||||
|
||||
#define KHASH_MAP_IMPL_INT(name, khval_t) \
|
||||
__KHASH_IMPL(name, , khint32_t, khval_t, 1, kh_int_hash_func, kh_int_hash_equal)
|
||||
|
||||
/*! @function
|
||||
@abstract Instantiate a hash map containing 64-bit integer keys
|
||||
@param name Name of the hash table [symbol]
|
||||
*/
|
||||
#define KHASH_SET_INIT_INT64(name) \
|
||||
KHASH_INIT(name, khint64_t, char, 0, kh_int64_hash_func, kh_int64_hash_equal)
|
||||
|
||||
#define KHASH_SET_DECLARE_INT64(name) \
|
||||
KHASH_DECLARE(name, khint64_t, char)
|
||||
|
||||
#define KHASH_SET_IMPL_INT64(name) \
|
||||
__KHASH_IMPL(name, , khint64_t, char, 0, kh_int64_hash_func, kh_int64_hash_equal)
|
||||
|
||||
/*! @function
|
||||
@abstract Instantiate a hash map containing 64-bit integer keys
|
||||
@param name Name of the hash table [symbol]
|
||||
@param khval_t Type of values [type]
|
||||
*/
|
||||
#define KHASH_MAP_INIT_INT64(name, khval_t) \
|
||||
KHASH_INIT(name, khint64_t, khval_t, 1, kh_int64_hash_func, kh_int64_hash_equal)
|
||||
|
||||
#define KHASH_MAP_DECLARE_INT64(name, khval_t) \
|
||||
KHASH_DECLARE(name, khint64_t, khval_t)
|
||||
|
||||
#define KHASH_MAP_IMPL_INT64(name, khval_t) \
|
||||
__KHASH_IMPL(name, , khint64_t, khval_t, 1, kh_int64_hash_func, kh_int64_hash_equal)
|
||||
|
||||
typedef const char *kh_cstr_t;
|
||||
/*! @function
|
||||
@abstract Instantiate a hash map containing const char* keys
|
||||
@param name Name of the hash table [symbol]
|
||||
*/
|
||||
#define KHASH_SET_INIT_STR(name) \
|
||||
KHASH_INIT(name, kh_cstr_t, char, 0, kh_str_hash_func, kh_str_hash_equal)
|
||||
|
||||
#define KHASH_SET_DECLARE_STR(name) \
|
||||
KHASH_DECLARE(name, kh_cstr_t, char)
|
||||
|
||||
#define KHASH_SET_IMPL_STR(name) \
|
||||
__KHASH_IMPL(name, , kh_cstr_t, char, 0, kh_str_hash_func, kh_str_hash_equal)
|
||||
|
||||
/*! @function
|
||||
@abstract Instantiate a hash map containing const char* keys
|
||||
@param name Name of the hash table [symbol]
|
||||
@param khval_t Type of values [type]
|
||||
*/
|
||||
#define KHASH_MAP_INIT_STR(name, khval_t) \
|
||||
KHASH_INIT(name, kh_cstr_t, khval_t, 1, kh_str_hash_func, kh_str_hash_equal)
|
||||
|
||||
#define KHASH_MAP_DECLARE_STR(name, khval_t) \
|
||||
KHASH_DECLARE(name, kh_cstr_t, khval_t)
|
||||
|
||||
#define KHASH_MAP_IMPL_STR(name, khval_t) \
|
||||
__KHASH_IMPL(name, , kh_cstr_t, khval_t, 1, kh_str_hash_func, kh_str_hash_equal)
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
#endif /* __AC_KHASH_H */
|
1164
wrapperhelper/src/lang.c
Normal file
1164
wrapperhelper/src/lang.c
Normal file
File diff suppressed because it is too large
Load Diff
439
wrapperhelper/src/lang.h
Normal file
439
wrapperhelper/src/lang.h
Normal file
@ -0,0 +1,439 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef LANG_H
|
||||
#define LANG_H
|
||||
|
||||
#include "cstring.h"
|
||||
#include "khash.h"
|
||||
#include "vector.h"
|
||||
|
||||
#define LONG_IS_32BITS 0
|
||||
|
||||
enum token_sym_type_e {
|
||||
SYM_LBRACKET,
|
||||
SYM_RBRACKET,
|
||||
SYM_LSQBRACKET,
|
||||
SYM_RSQBRACKET,
|
||||
SYM_LPAREN,
|
||||
SYM_RPAREN,
|
||||
SYM_HASH,
|
||||
SYM_HASHHASH,
|
||||
SYM_SEMICOLON,
|
||||
SYM_COLON,
|
||||
SYM_COLONCOLON,
|
||||
SYM_VARIADIC,
|
||||
SYM_QUESTION,
|
||||
SYM_DOT,
|
||||
SYM_DASHGT,
|
||||
SYM_TILDE,
|
||||
SYM_EXCL,
|
||||
SYM_PLUS,
|
||||
SYM_DASH,
|
||||
SYM_STAR,
|
||||
SYM_SLASH,
|
||||
SYM_PERCENT,
|
||||
SYM_HAT,
|
||||
SYM_AMP,
|
||||
SYM_PIPE,
|
||||
SYM_EQ,
|
||||
SYM_PLUSEQ,
|
||||
SYM_DASHEQ,
|
||||
SYM_STAREQ,
|
||||
SYM_SLASHEQ,
|
||||
SYM_PERCENTEQ,
|
||||
SYM_HATEQ,
|
||||
SYM_AMPEQ,
|
||||
SYM_PIPEEQ,
|
||||
SYM_EQEQ,
|
||||
SYM_EXCLEQ,
|
||||
SYM_LT,
|
||||
SYM_GT,
|
||||
SYM_LTEQ,
|
||||
SYM_GTEQ,
|
||||
SYM_AMPAMP,
|
||||
SYM_PIPEPIPE,
|
||||
SYM_LTLT,
|
||||
SYM_GTGT,
|
||||
SYM_LTLTEQ,
|
||||
SYM_GTGTEQ,
|
||||
SYM_PLUSPLUS,
|
||||
SYM_DASHDASH,
|
||||
SYM_COMMA,
|
||||
};
|
||||
#define LAST_SYM SYM_COMMA
|
||||
|
||||
typedef struct preproc_token_s {
|
||||
enum preproc_token_e {
|
||||
PPTOK_INVALID = 0,
|
||||
PPTOK_IDENT, // Expandable ident
|
||||
PPTOK_IDENT_UNEXP, // Unexpandable ident
|
||||
PPTOK_NUM,
|
||||
PPTOK_STRING,
|
||||
PPTOK_INCL,
|
||||
PPTOK_SYM,
|
||||
PPTOK_NEWLINE,
|
||||
PPTOK_BLANK,
|
||||
PPTOK_START_LINE_COMMENT,
|
||||
PPTOK_EOF
|
||||
} tokt;
|
||||
union {
|
||||
string_t *str;
|
||||
struct {
|
||||
string_t *sstr; // The string literal content
|
||||
int sisstr; // 0 for '' or <>, 1 for ""
|
||||
};
|
||||
char c;
|
||||
enum token_sym_type_e sym;
|
||||
} tokv;
|
||||
} preproc_token_t;
|
||||
VECTOR_DECLARE(preproc, preproc_token_t)
|
||||
void preproc_token_del(preproc_token_t *tok);
|
||||
|
||||
enum token_keyword_type_e {
|
||||
KW_ALIGNAS = 0,
|
||||
KW_ALIGNOF,
|
||||
KW_ATOMIC,
|
||||
KW_AUTO,
|
||||
KW_BOOL,
|
||||
KW_BREAK,
|
||||
KW_CASE,
|
||||
KW_CHAR,
|
||||
KW_COMPLEX,
|
||||
KW_CONST,
|
||||
KW_CONTINUE,
|
||||
KW_DEFAULT,
|
||||
KW_DO,
|
||||
KW_DOUBLE,
|
||||
KW_ELSE,
|
||||
KW_ENUM,
|
||||
KW_EXTERN,
|
||||
KW_FLOAT,
|
||||
KW_FOR,
|
||||
KW_GENERIC,
|
||||
KW_GOTO,
|
||||
KW_IF,
|
||||
KW_IMAGINARY,
|
||||
KW_INLINE,
|
||||
KW_INT,
|
||||
KW_INT128,
|
||||
KW_LONG,
|
||||
KW_NORETURN,
|
||||
KW_REGISTER,
|
||||
KW_RESTRICT,
|
||||
KW_RETURN,
|
||||
KW_SHORT,
|
||||
KW_SIGNED,
|
||||
KW_SIZEOF,
|
||||
KW_STATIC,
|
||||
KW_STATIC_ASSERT,
|
||||
KW_STRUCT,
|
||||
KW_SWITCH,
|
||||
KW_THREAD_LOCAL,
|
||||
KW_TYPEDEF,
|
||||
KW_UNION,
|
||||
KW_UNSIGNED,
|
||||
KW_VOID,
|
||||
KW_VOLATILE,
|
||||
KW_WHILE,
|
||||
};
|
||||
#define LAST_KEYWORD KW_WHILE
|
||||
|
||||
typedef struct proc_token_s {
|
||||
enum proc_token_e {
|
||||
PTOK_INVALID = 0,
|
||||
PTOK_IDENT,
|
||||
PTOK_KEYWORD,
|
||||
PTOK_NUM,
|
||||
PTOK_STRING,
|
||||
PTOK_SYM,
|
||||
PTOK_PRAGMA,
|
||||
PTOK_EOF
|
||||
} tokt;
|
||||
union proc_token_val_u {
|
||||
string_t *str;
|
||||
struct {
|
||||
string_t *sstr; // The string literal content
|
||||
int sisstr; // 0 for '' or <>, 1 for ""
|
||||
};
|
||||
char c;
|
||||
enum token_sym_type_e sym;
|
||||
enum token_keyword_type_e kw;
|
||||
struct {
|
||||
enum proc_pragma_e {
|
||||
PRAGMA_ALLOW_INTS,
|
||||
PRAGMA_MARK_SIMPLE,
|
||||
} typ;
|
||||
string_t *val;
|
||||
} pragma;
|
||||
} tokv;
|
||||
} proc_token_t;
|
||||
VECTOR_DECLARE(proc, proc_token_t)
|
||||
void proc_token_del(proc_token_t *tok);
|
||||
|
||||
typedef struct num_constant_s {
|
||||
enum num_constant_e {
|
||||
NCT_FLOAT,
|
||||
NCT_DOUBLE,
|
||||
NCT_LDOUBLE,
|
||||
NCT_INT32,
|
||||
NCT_UINT32,
|
||||
NCT_INT64,
|
||||
NCT_UINT64,
|
||||
} typ;
|
||||
union {
|
||||
float f;
|
||||
double d;
|
||||
long double l;
|
||||
int32_t i32;
|
||||
uint32_t u32;
|
||||
int64_t i64;
|
||||
uint64_t u64;
|
||||
} val;
|
||||
} num_constant_t;
|
||||
int num_constant_convert(string_t *str, num_constant_t *cst);
|
||||
KHASH_MAP_DECLARE_STR(const_map, num_constant_t)
|
||||
|
||||
typedef struct expr_s {
|
||||
enum expr_type_e {
|
||||
ETY_VAR,
|
||||
ETY_CONST,
|
||||
// ETY_GENERIC,
|
||||
ETY_CALL,
|
||||
ETY_ACCESS,
|
||||
ETY_PTRACCESS, // Convertible to DEREF + ACCESS
|
||||
ETY_UNARY,
|
||||
ETY_BINARY,
|
||||
ETY_TERNARY,
|
||||
// ETY_INIT_LIST,
|
||||
ETY_CAST,
|
||||
} typ;
|
||||
union {
|
||||
string_t *var;
|
||||
num_constant_t cst;
|
||||
// TODO: _Generic
|
||||
struct {
|
||||
struct expr_s *fun, **args;
|
||||
size_t nargs;
|
||||
} call;
|
||||
struct {
|
||||
struct expr_s *val;
|
||||
string_t *member;
|
||||
} access;
|
||||
struct {
|
||||
enum unary_op_e {
|
||||
UOT_POSTINCR,
|
||||
UOT_POSTDECR,
|
||||
UOT_PREINCR,
|
||||
UOT_PREDECR,
|
||||
UOT_REF,
|
||||
UOT_POS,
|
||||
UOT_NEG,
|
||||
UOT_DEREF,
|
||||
UOT_ANOT, // Arithmetic not, ie '~'
|
||||
UOT_BNOT, // Boolean not, ie '!'
|
||||
} typ;
|
||||
struct expr_s *e;
|
||||
} unary;
|
||||
struct {
|
||||
enum binary_op_e {
|
||||
BOT_ADD,
|
||||
BOT_SUB,
|
||||
BOT_MUL,
|
||||
BOT_DIV,
|
||||
BOT_MOD,
|
||||
BOT_LSH,
|
||||
BOT_RSH,
|
||||
BOT_LT,
|
||||
BOT_GT,
|
||||
BOT_LE,
|
||||
BOT_GE,
|
||||
BOT_EQ,
|
||||
BOT_NE,
|
||||
BOT_AAND,
|
||||
BOT_AXOR,
|
||||
BOT_AOR,
|
||||
BOT_BAND,
|
||||
BOT_BOR,
|
||||
BOT_ASSGN_EQ,
|
||||
BOT_ASSGN_ADD,
|
||||
BOT_ASSGN_SUB,
|
||||
BOT_ASSGN_MUL,
|
||||
BOT_ASSGN_DIV,
|
||||
BOT_ASSGN_MOD,
|
||||
BOT_ASSGN_LSH,
|
||||
BOT_ASSGN_RSH,
|
||||
BOT_ASSGN_AAND,
|
||||
BOT_ASSGN_AXOR,
|
||||
BOT_ASSGN_AOR,
|
||||
BOT_COMMA,
|
||||
|
||||
BOT_ARRAY, // Convertible to DEREF + ADD
|
||||
} typ;
|
||||
struct expr_s *e1, *e2;
|
||||
} binary;
|
||||
struct {
|
||||
enum ternary_op_e {
|
||||
TOT_COND,
|
||||
} typ;
|
||||
struct expr_s *e1, *e2, *e3;
|
||||
} ternary;
|
||||
// TODO: (type){init}
|
||||
struct {
|
||||
struct type_s *typ;
|
||||
struct expr_s *e;
|
||||
} cast;
|
||||
} val;
|
||||
} expr_t;
|
||||
void expr_del(expr_t *e);
|
||||
|
||||
typedef struct size_info_s {
|
||||
size_t size, align;
|
||||
} size_info_t;
|
||||
|
||||
typedef struct type_s {
|
||||
struct {
|
||||
unsigned is_atomic : 1;
|
||||
unsigned is_const : 1;
|
||||
unsigned is_restrict : 1;
|
||||
unsigned is_volatile : 1;
|
||||
unsigned is_incomplete : 1; // \ The type needs to be complete and
|
||||
unsigned is_validated : 1; // / validated for the size_info to be populated
|
||||
unsigned _internal_use : 1;
|
||||
};
|
||||
size_t nrefs;
|
||||
enum type_type_e {
|
||||
TYPE_BUILTIN, // builtin
|
||||
TYPE_ARRAY, // array
|
||||
TYPE_STRUCT_UNION, // st
|
||||
TYPE_ENUM, // typ which points to TYPE_BUILTIN
|
||||
TYPE_PTR, // typ
|
||||
TYPE_FUNCTION, // fun
|
||||
} typ;
|
||||
union {
|
||||
enum type_builtin_e {
|
||||
BTT_VOID,
|
||||
BTT_BOOL,
|
||||
BTT_CHAR,
|
||||
BTT_SCHAR,
|
||||
BTT_UCHAR,
|
||||
BTT_SHORT,
|
||||
BTT_SSHORT,
|
||||
BTT_USHORT,
|
||||
BTT_INT,
|
||||
BTT_SINT,
|
||||
BTT_UINT,
|
||||
BTT_LONG,
|
||||
BTT_SLONG,
|
||||
BTT_ULONG,
|
||||
BTT_LONGLONG,
|
||||
BTT_SLONGLONG,
|
||||
BTT_ULONGLONG,
|
||||
BTT_INT128,
|
||||
BTT_SINT128,
|
||||
BTT_UINT128,
|
||||
BTT_S8,
|
||||
BTT_U8,
|
||||
BTT_S16,
|
||||
BTT_U16,
|
||||
BTT_S32,
|
||||
BTT_U32,
|
||||
BTT_S64,
|
||||
BTT_U64,
|
||||
#define BTT_START_INT_EXT BTT_S8
|
||||
#define BTT_INT_EXTS "__int8_t", "__uint8_t", "__int16_t", "__uint16_t", "__int32_t", "__uint32_t", "__int64_t", "__uint64_t"
|
||||
BTT_FLOAT,
|
||||
BTT_CFLOAT,
|
||||
BTT_IFLOAT,
|
||||
BTT_DOUBLE,
|
||||
BTT_CDOUBLE,
|
||||
BTT_IDOUBLE,
|
||||
BTT_LONGDOUBLE,
|
||||
BTT_CLONGDOUBLE,
|
||||
BTT_ILONGDOUBLE,
|
||||
BTT_VA_LIST,
|
||||
} builtin;
|
||||
#define LAST_BUILTIN BTT_VA_LIST
|
||||
struct type_s *typ;
|
||||
struct {
|
||||
struct type_s *typ;
|
||||
size_t array_sz; // -1 for VLA
|
||||
} array;
|
||||
struct struct_s *st;
|
||||
struct {
|
||||
struct type_s *ret;
|
||||
size_t nargs; // -1 for no specification
|
||||
struct type_s **args;
|
||||
int has_varargs;
|
||||
} fun;
|
||||
} val;
|
||||
size_info_t szinfo;
|
||||
} type_t;
|
||||
void type_del(type_t *typ);
|
||||
KHASH_MAP_DECLARE_STR(type_map, type_t*)
|
||||
void type_map_del(khash_t(type_map) *map);
|
||||
|
||||
int type_t_equal(type_t*, type_t*);
|
||||
|
||||
typedef struct st_member_s {
|
||||
string_t *name; // May be NULL
|
||||
type_t *typ;
|
||||
_Bool is_bitfield;
|
||||
size_t bitfield_width;
|
||||
} st_member_t;
|
||||
typedef struct struct_s {
|
||||
string_t *tag;
|
||||
int is_defined;
|
||||
size_t nrefs;
|
||||
int is_struct; // 0 = union, 1 = struct
|
||||
int has_incomplete; // 1 if the last element of the structure is a VLA or if an element of the union recursively contains a VLA
|
||||
int explicit_simple;
|
||||
size_t nmembers;
|
||||
st_member_t *members;
|
||||
} struct_t;
|
||||
void st_member_del(st_member_t *member);
|
||||
void struct_del(struct_t *st);
|
||||
KHASH_MAP_DECLARE_STR(struct_map, struct_t*)
|
||||
|
||||
type_t *type_new(void); // Create a new (complete) builtin type
|
||||
type_t *type_new_ptr(type_t *target); // Create a new pointer type; doesn't increment the use counter of the target
|
||||
// type_t *type_do_copy(type_t *ref); // Always duplicate ref; decrements the use counter
|
||||
// type_t *type_do_copy_nodec(const type_t *ref); // Always duplicate ref; doesn't decrements the use counter
|
||||
// type_t *type_maybe_copy(type_t *ref); // Only duplicate ref if it is used elsewhere; in that case, decrements the use counter
|
||||
int type_copy_into(type_t *dest, const type_t *ref); // Copy ref into dest, keeping additional qualifiers and without changing any use counter
|
||||
|
||||
struct_t *struct_new(int is_struct, string_t *tag); // Create a new struct
|
||||
|
||||
// Try to merge some types with other types; this may delete ptr and increase a use counter in a type referenced by the table
|
||||
KHASH_DECLARE(type_set, type_t*, char)
|
||||
type_t *type_try_merge(type_t *ptr, khash_t(type_set) *set);
|
||||
|
||||
extern const char *builtin2str[LAST_BUILTIN + 1];
|
||||
void type_print(type_t *typ);
|
||||
void struct_print(const struct_t *st);
|
||||
|
||||
typedef struct file_s {
|
||||
khash_t(struct_map) *struct_map;
|
||||
khash_t(type_map) *type_map;
|
||||
khash_t(type_map) *enum_map;
|
||||
khash_t(type_map) *decl_map;
|
||||
type_t *builtins[LAST_BUILTIN + 1];
|
||||
khash_t(const_map) *const_map;
|
||||
khash_t(type_set) *type_set;
|
||||
} file_t;
|
||||
file_t *file_new(void);
|
||||
void file_del(file_t *f);
|
||||
|
||||
extern const char *sym2str[LAST_SYM + 1];
|
||||
extern const char *kw2str[LAST_KEYWORD + 1];
|
||||
void preproc_token_print(const preproc_token_t *tok);
|
||||
int preproc_token_isend(const preproc_token_t *tok);
|
||||
void proc_token_print(const proc_token_t *tok);
|
||||
int proc_token_iserror(const proc_token_t *tok);
|
||||
int proc_token_isend(const proc_token_t *tok);
|
||||
|
||||
KHASH_MAP_DECLARE_STR(str2kw, enum token_keyword_type_e)
|
||||
extern khash_t(str2kw) *str2kw;
|
||||
int init_str2kw(void);
|
||||
void del_str2kw(void);
|
||||
|
||||
#endif // LANG_H
|
184
wrapperhelper/src/main.c
Normal file
184
wrapperhelper/src/main.c
Normal file
@ -0,0 +1,184 @@
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "generator.h"
|
||||
#include "lang.h"
|
||||
#include "parse.h"
|
||||
#include "khash.h"
|
||||
|
||||
static void help(char *arg0) {
|
||||
printf("Usage: %s --help\n"
|
||||
" %s [--prepare|--preproc|--proc] <filename_in>\n"
|
||||
" %s <filename_in> <filename_reqs> <filename_out>\n"
|
||||
"\n"
|
||||
" --prepare Dump all preprocessor tokens (prepare phase)\n"
|
||||
" --preproc Dump all processor tokens (preprocessor phase)\n"
|
||||
" --proc Dump all typedefs, declarations and constants (processor phase)\n"
|
||||
"\n"
|
||||
" <filename_in> Parsing file\n"
|
||||
" <filename_reqs> Reference file (example: wrappedlibc_private.h)\n"
|
||||
" <filename_out> Output file\n",
|
||||
arg0, arg0, arg0);
|
||||
}
|
||||
|
||||
enum main_state {
|
||||
MAIN_RUN,
|
||||
MAIN_PREPARE,
|
||||
MAIN_PREPROC,
|
||||
MAIN_PROC,
|
||||
};
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
setbuf(stdout, NULL);
|
||||
if (!setlocale(LC_NUMERIC, "C")) {
|
||||
printf("Error: failed to set LC_NUMERIC to C\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
enum main_state ms;
|
||||
int off;
|
||||
|
||||
if ((argc == 2) && !strcmp(argv[1], "--help")) {
|
||||
help(argv[0]);
|
||||
return 0;
|
||||
} else if (argc == 2) {
|
||||
ms = MAIN_PROC;
|
||||
off = 1;
|
||||
} else if ((argc == 3) && !strcmp(argv[1], "--prepare")) {
|
||||
ms = MAIN_PREPARE;
|
||||
off = 2;
|
||||
} else if ((argc == 3) && !strcmp(argv[1], "--preproc")) {
|
||||
ms = MAIN_PREPROC;
|
||||
off = 2;
|
||||
} else if ((argc == 3) && !strcmp(argv[1], "--proc")) {
|
||||
ms = MAIN_PROC;
|
||||
off = 2;
|
||||
} else if (argc == 4) {
|
||||
ms = MAIN_RUN;
|
||||
off = 1;
|
||||
} else {
|
||||
help(argv[0]);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (!init_str2kw()) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
FILE *f = fopen(argv[off], "r");
|
||||
if (!f) {
|
||||
err(2, "Error: failed to open %s", argv[off]);
|
||||
return 2;
|
||||
}
|
||||
switch (ms) {
|
||||
case MAIN_RUN: {
|
||||
file_t *content = parse_file(argv[off], f); // Takes ownership of f
|
||||
if (!content) {
|
||||
printf("Error: failed to parse the file\n");
|
||||
del_str2kw();
|
||||
return 0;
|
||||
}
|
||||
|
||||
FILE *ref = fopen(argv[off + 1], "r");
|
||||
if (!ref) {
|
||||
err(2, "Error: failed to open %s", argv[off + 1]);
|
||||
del_str2kw();
|
||||
return 2;
|
||||
}
|
||||
VECTOR(requests) *reqs = requests_from_file(argv[off + 1], ref);
|
||||
if (!reqs) {
|
||||
file_del(content);
|
||||
del_str2kw();
|
||||
return 2;
|
||||
}
|
||||
// vector_for(requests, req, reqs) request_print(req);
|
||||
if (!solve_requests(reqs, content->decl_map)) {
|
||||
printf("Warning: failed to solve all default requests\n");
|
||||
}
|
||||
// vector_for(requests, req, reqs) request_print(req);
|
||||
//vector_for(requests, req, reqs) request_print_check(req);
|
||||
FILE *out = fopen(argv[off + 2], "w");
|
||||
if (!out) {
|
||||
err(2, "Error: failed to open %s", argv[off + 1]);
|
||||
file_del(content);
|
||||
vector_del(requests, reqs);
|
||||
del_str2kw();
|
||||
return 2;
|
||||
}
|
||||
output_from_requests(out, reqs);
|
||||
fclose(out);
|
||||
vector_del(requests, reqs);
|
||||
file_del(content);
|
||||
del_str2kw();
|
||||
return 0; }
|
||||
case MAIN_PROC: {
|
||||
file_t *content = parse_file(argv[off], f); // Takes ownership of f
|
||||
if (!content) {
|
||||
printf("Error: failed to parse the file\n");
|
||||
del_str2kw();
|
||||
return 0;
|
||||
}
|
||||
// print content
|
||||
const char *name;
|
||||
struct_t *st;
|
||||
type_t *typ;
|
||||
num_constant_t cst;
|
||||
/* for (enum type_builtin_e i = 0; i < LAST_BUILTIN; ++i) {
|
||||
printf("Builtin %u: %p, ", i, content->builtins[i]);
|
||||
type_print(content->builtins[i]);
|
||||
printf("\n");
|
||||
} */
|
||||
kh_foreach(content->struct_map, name, st,
|
||||
printf("Struct: %s -> %p = ", name, st);
|
||||
struct_print(st);
|
||||
printf("\n")
|
||||
)
|
||||
kh_foreach(content->type_map, name, typ,
|
||||
printf("Typedef: %s -> %p = ", name, typ);
|
||||
type_print(typ);
|
||||
printf("\n")
|
||||
)
|
||||
kh_foreach(content->enum_map, name, typ,
|
||||
printf("Enum: %s -> %p = ", name, typ);
|
||||
type_print(typ);
|
||||
printf("\n")
|
||||
)
|
||||
kh_foreach(content->const_map, name, cst,
|
||||
printf("Constant: %s -> ", name);
|
||||
switch (cst.typ) {
|
||||
case NCT_FLOAT: printf("%ff", cst.val.f); break;
|
||||
case NCT_DOUBLE: printf("%f", cst.val.d); break;
|
||||
case NCT_LDOUBLE: printf("%Lfl", cst.val.l); break;
|
||||
case NCT_INT32: printf("%d", cst.val.i32); break;
|
||||
case NCT_UINT32: printf("%uu", cst.val.u32); break;
|
||||
case NCT_INT64: printf("%ldll", cst.val.i64); break;
|
||||
case NCT_UINT64: printf("%lullu", cst.val.u64); break;
|
||||
}
|
||||
printf("\n")
|
||||
)
|
||||
kh_foreach(content->decl_map, name, typ,
|
||||
printf("Declaration: %s -> %p = ", name, typ);
|
||||
type_print(typ);
|
||||
printf("\n")
|
||||
)
|
||||
file_del(content);
|
||||
del_str2kw();
|
||||
return 0; }
|
||||
|
||||
case MAIN_PREPARE:
|
||||
dump_prepare(argv[off], f); // Takes ownership of f
|
||||
del_str2kw();
|
||||
return 0;
|
||||
|
||||
case MAIN_PREPROC:
|
||||
dump_preproc(argv[off], f); // Takes ownership of f
|
||||
del_str2kw();
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("<internal error> Failed to run mode %u\n", ms);
|
||||
return 2;
|
||||
}
|
3164
wrapperhelper/src/parse.c
Normal file
3164
wrapperhelper/src/parse.c
Normal file
File diff suppressed because it is too large
Load Diff
14
wrapperhelper/src/parse.h
Normal file
14
wrapperhelper/src/parse.h
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef PARSE_H
|
||||
#define PARSE_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "lang.h"
|
||||
|
||||
void dump_prepare(const char *filename, FILE *file);
|
||||
void dump_preproc(const char *filename, FILE *file);
|
||||
file_t *parse_file(const char *filename, FILE *file);
|
||||
|
||||
#endif // PARSE_H
|
372
wrapperhelper/src/prepare.c
Normal file
372
wrapperhelper/src/prepare.c
Normal file
@ -0,0 +1,372 @@
|
||||
#include "prepare.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
struct prepare_s {
|
||||
FILE *f;
|
||||
int buf[4];
|
||||
int buf_len; // <= 4 (though 3 *should* be enough)
|
||||
char *srcn;
|
||||
enum prepare_state {
|
||||
PREPST_NONE = 0,
|
||||
PREPST_NL,
|
||||
PREPST_HASH,
|
||||
PREPST_INCL,
|
||||
PREPST_DEF,
|
||||
PREPST_DEFID,
|
||||
} st;
|
||||
};
|
||||
|
||||
prepare_t *prepare_new_file(FILE *f, const char *filename) {
|
||||
prepare_t *ret = malloc(sizeof *ret);
|
||||
if (!ret) {
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
*ret = (prepare_t){
|
||||
.f = f,
|
||||
.buf = {0, 0, 0},
|
||||
.buf_len = 0,
|
||||
.srcn = strdup(filename),
|
||||
.st = PREPST_NL,
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
void prepare_del(prepare_t *prep) {
|
||||
if (prep->f) fclose(prep->f);
|
||||
if (prep->srcn) free(prep->srcn);
|
||||
free(prep);
|
||||
}
|
||||
|
||||
static int get_char(prepare_t *src) {
|
||||
start_get_char:
|
||||
int c = src->buf_len ? src->buf[--src->buf_len] : getc(src->f);
|
||||
src->buf_len = 0;
|
||||
if (c == '\\') {
|
||||
c = src->buf_len ? src->buf[--src->buf_len] : getc(src->f);
|
||||
if (c == '\n') goto start_get_char;
|
||||
src->buf[src->buf_len++] = c;
|
||||
return '\\';
|
||||
}
|
||||
return c;
|
||||
}
|
||||
// Do not call this more than twice in a row if the last character retrieved is '\\'
|
||||
static void unget_char(prepare_t *src, int c) {
|
||||
src->buf[src->buf_len++] = c;
|
||||
}
|
||||
|
||||
static void fill_ident(prepare_t *src, string_t *buf) {
|
||||
while (1) {
|
||||
int c = get_char(src);
|
||||
if ((c == '_') || ((c >= '0') && (c <= '9')) || ((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z'))) {
|
||||
string_add_char(buf, (char)c);
|
||||
} else {
|
||||
unget_char(src, c);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fill_num(prepare_t *src, string_t *buf) {
|
||||
int started_exp = 0;
|
||||
while (1) {
|
||||
int c = get_char(src);
|
||||
if ((c == '_') || (c == '.') || ((c >= '0') && (c <= '9')) || ((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z'))
|
||||
|| (started_exp && ((c == '+') || (c == '-')))) {
|
||||
started_exp = (c == 'e') || (c == 'E') || (c == 'p') || (c == 'P');
|
||||
string_add_char(buf, (char)c);
|
||||
} else {
|
||||
unget_char(src, c);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fill_str(prepare_t *src, string_t *buf, char end_c, int can_esc) {
|
||||
int has_esc = 0;
|
||||
while (1) {
|
||||
int c = get_char(src);
|
||||
if (has_esc && (c >= 0) && (c <= 0x7F) && (c != '\n')) {
|
||||
// Not technically standard compliant (should support \ooo, \x..., \u..., \U...)
|
||||
// Since we don't really care about parsing the content, only the delimiters, this is good enough
|
||||
string_add_char(buf, '\\');
|
||||
string_add_char(buf, (char)c);
|
||||
has_esc = 0;
|
||||
} else if (c == '\\') {
|
||||
if (can_esc) {
|
||||
has_esc = 1;
|
||||
} else {
|
||||
string_add_char(buf, '\\');
|
||||
}
|
||||
} else if ((c >= 0) && (c <= 0x7F) && (c != end_c)) {
|
||||
has_esc = 0;
|
||||
string_add_char(buf, (char)c);
|
||||
} else {
|
||||
if (has_esc) {
|
||||
// c is invalid or a '\n', or can_esc = 0 and c = end_c
|
||||
string_add_char(buf, '\\');
|
||||
}
|
||||
if (c != end_c)
|
||||
unget_char(src, c);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define BASE_NSYMS 25
|
||||
static const struct symbs_s {
|
||||
char c;
|
||||
enum token_sym_type_e sym;
|
||||
int nnext;
|
||||
const struct symbs_s *next;
|
||||
} *symbs = (struct symbs_s[BASE_NSYMS]){
|
||||
#define TERM(ch, t) { .c = ch, .sym = t, .nnext = 0, .next = NULL }
|
||||
#define NONTERM(ch, t, n, ...) { .c = ch, .sym = t, .nnext = n, .next = (struct symbs_s[n]){__VA_ARGS__} }
|
||||
// Only '..' must have a sym > LAST_SYM; change next_token if this is not the case
|
||||
NONTERM('.', SYM_DOT, 1, NONTERM('.', LAST_SYM + 1, 1, TERM('.', SYM_VARIADIC))),
|
||||
TERM('{', SYM_LBRACKET),
|
||||
TERM('}', SYM_RBRACKET),
|
||||
TERM('[', SYM_LSQBRACKET),
|
||||
TERM(']', SYM_RSQBRACKET),
|
||||
TERM('(', SYM_LPAREN),
|
||||
TERM(')', SYM_RPAREN),
|
||||
NONTERM('#', SYM_HASH, 1, TERM('#', SYM_HASHHASH)),
|
||||
TERM(';', SYM_SEMICOLON),
|
||||
NONTERM(':', SYM_COLON, 1, TERM(':', SYM_COLONCOLON)),
|
||||
TERM('?', SYM_QUESTION),
|
||||
TERM('~', SYM_TILDE),
|
||||
NONTERM('!', SYM_EXCL, 1, TERM('=', SYM_EXCLEQ)),
|
||||
NONTERM('+', SYM_PLUS, 2, TERM('=', SYM_PLUSEQ), TERM('+', SYM_PLUSPLUS)),
|
||||
NONTERM('-', SYM_DASH, 3, TERM('=', SYM_DASHEQ), TERM('-', SYM_DASHDASH), TERM('>', SYM_DASHGT)),
|
||||
NONTERM('*', SYM_STAR, 1, TERM('=', SYM_STAREQ)),
|
||||
NONTERM('/', SYM_SLASH, 1, TERM('=', SYM_SLASHEQ)),
|
||||
NONTERM('%', SYM_PERCENT, 1, TERM('=', SYM_PERCENTEQ)),
|
||||
NONTERM('^', SYM_HAT, 1, TERM('=', SYM_HATEQ)),
|
||||
NONTERM('&', SYM_AMP, 2, TERM('=', SYM_AMPEQ), TERM('&', SYM_AMPAMP)),
|
||||
NONTERM('|', SYM_PIPE, 2, TERM('=', SYM_PIPEEQ), TERM('|', SYM_PIPEPIPE)),
|
||||
NONTERM('=', SYM_EQ, 1, TERM('=', SYM_EQEQ)),
|
||||
NONTERM('<', SYM_LT, 2, TERM('=', SYM_LTEQ), NONTERM('<', SYM_LTLT, 1, TERM('=', SYM_LTLTEQ))),
|
||||
NONTERM('>', SYM_GT, 2, TERM('=', SYM_GTEQ), NONTERM('>', SYM_GTGT, 1, TERM('=', SYM_GTGTEQ))),
|
||||
TERM(',', SYM_COMMA),
|
||||
#undef NONTERM
|
||||
#undef TERM
|
||||
};
|
||||
|
||||
preproc_token_t pre_next_token(prepare_t *src, int allow_comments) {
|
||||
start_next_token:
|
||||
int c = get_char(src);
|
||||
if (c == EOF) {
|
||||
if (src->st == PREPST_NL) {
|
||||
return (preproc_token_t){
|
||||
.tokt = PPTOK_EOF,
|
||||
.tokv.c = (char)c
|
||||
};
|
||||
} else {
|
||||
// Force newline at EOF
|
||||
unget_char(src, c);
|
||||
src->st = PREPST_NL;
|
||||
return (preproc_token_t){
|
||||
.tokt = PPTOK_NEWLINE,
|
||||
.tokv.c = (char)c
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (src->st == PREPST_INCL && (c == '<')) {
|
||||
src->st = PREPST_NONE;
|
||||
preproc_token_t ret;
|
||||
ret.tokt = PPTOK_INCL;
|
||||
ret.tokv.sisstr = 0;
|
||||
ret.tokv.sstr = string_new();
|
||||
fill_str(src, ret.tokv.sstr, '>', 0);
|
||||
return ret;
|
||||
}
|
||||
if (c == '\'') {
|
||||
src->st = PREPST_NONE;
|
||||
preproc_token_t ret;
|
||||
ret.tokt = PPTOK_STRING;
|
||||
ret.tokv.sisstr = 0;
|
||||
ret.tokv.sstr = string_new_cap(1); // Usually only one character is inside a char literal
|
||||
fill_str(src, ret.tokv.sstr, '\'', 1);
|
||||
return ret;
|
||||
}
|
||||
if (c == '"') {
|
||||
preproc_token_t ret;
|
||||
ret.tokt = (src->st == PREPST_INCL) ? PPTOK_INCL : PPTOK_STRING;
|
||||
src->st = PREPST_NONE;
|
||||
ret.tokv.sisstr = 1;
|
||||
ret.tokv.sstr = string_new();
|
||||
fill_str(src, ret.tokv.sstr, '"', ret.tokt == PPTOK_STRING);
|
||||
return ret;
|
||||
}
|
||||
if ((c == ' ') || (c == '\f') || (c == '\t') || (c == '\v')) {
|
||||
if (src->st == PREPST_DEFID) {
|
||||
src->st = PREPST_NONE;
|
||||
return (preproc_token_t){
|
||||
.tokt = PPTOK_BLANK,
|
||||
.tokv.c = (char)c
|
||||
};
|
||||
} else goto start_next_token;
|
||||
}
|
||||
if (c == '\n') {
|
||||
src->st = PREPST_NL;
|
||||
return (preproc_token_t){
|
||||
.tokt = PPTOK_NEWLINE,
|
||||
.tokv.c = (char)c
|
||||
};
|
||||
}
|
||||
if ((c == '_') || ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))) {
|
||||
preproc_token_t ret;
|
||||
ret.tokt = PPTOK_IDENT;
|
||||
ret.tokv.str = string_new_cap(1);
|
||||
string_add_char(ret.tokv.str, (char)c);
|
||||
fill_ident(src, ret.tokv.str);
|
||||
src->st =
|
||||
((src->st == PREPST_HASH) && (!strcmp(string_content(ret.tokv.str), "include"))) ? PREPST_INCL :
|
||||
((src->st == PREPST_HASH) && (!strcmp(string_content(ret.tokv.str), "include_next"))) ? PREPST_INCL :
|
||||
((src->st == PREPST_HASH) && (!strcmp(string_content(ret.tokv.str), "define"))) ? PREPST_DEF :
|
||||
(src->st == PREPST_DEF) ? PREPST_DEFID :
|
||||
PREPST_NONE;
|
||||
return ret;
|
||||
}
|
||||
if ((c >= '0') && (c <= '9')) {
|
||||
src->st = PREPST_NONE;
|
||||
preproc_token_t ret;
|
||||
ret.tokt = PPTOK_NUM;
|
||||
ret.tokv.str = string_new_cap(1);
|
||||
string_add_char(ret.tokv.str, (char)c);
|
||||
fill_num(src, ret.tokv.str);
|
||||
return ret;
|
||||
}
|
||||
if (c == '.') {
|
||||
c = get_char(src);
|
||||
if ((c >= '0') && (c <= '9')) {
|
||||
src->st = PREPST_NONE;
|
||||
preproc_token_t ret;
|
||||
ret.tokt = PPTOK_NUM;
|
||||
ret.tokv.str = string_new_cap(2);
|
||||
string_add_char(ret.tokv.str, '.');
|
||||
string_add_char(ret.tokv.str, (char)c);
|
||||
fill_num(src, ret.tokv.str);
|
||||
return ret;
|
||||
} else {
|
||||
unget_char(src, c);
|
||||
c = '.';
|
||||
}
|
||||
}
|
||||
if (c == '/') {
|
||||
c = get_char(src);
|
||||
if (c == '/') {
|
||||
if (allow_comments) {
|
||||
src->st = PREPST_NONE;
|
||||
return (preproc_token_t){
|
||||
.tokt = PPTOK_START_LINE_COMMENT,
|
||||
.tokv.c = '/'
|
||||
};
|
||||
}
|
||||
|
||||
do {
|
||||
c = get_char(src);
|
||||
} while ((c != EOF) && (c != '\n'));
|
||||
if (c != EOF) {
|
||||
if (src->st == PREPST_NL)
|
||||
goto start_next_token;
|
||||
else {
|
||||
src->st = PREPST_NL;
|
||||
return (preproc_token_t){
|
||||
.tokt = PPTOK_NEWLINE,
|
||||
.tokv.c = (char)c
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
src->st = PREPST_NONE;
|
||||
printf("Unfinished comment while preparing %s\n", src->srcn);
|
||||
return (preproc_token_t){
|
||||
.tokt = PPTOK_INVALID,
|
||||
.tokv.c = (char)c
|
||||
};
|
||||
} else if (c == '*') {
|
||||
c = get_char(src);
|
||||
int last_star = 0;
|
||||
while ((c != EOF) && (!last_star || (c != '/'))) {
|
||||
last_star = c == '*';
|
||||
c = get_char(src);
|
||||
}
|
||||
if (c != EOF) goto start_next_token;
|
||||
|
||||
src->st = PREPST_NONE;
|
||||
printf("Unfinished comment while preparing %s\n", src->srcn);
|
||||
return (preproc_token_t){
|
||||
.tokt = PPTOK_INVALID,
|
||||
.tokv.c = (char)c
|
||||
};
|
||||
} else {
|
||||
unget_char(src, c);
|
||||
c = '/';
|
||||
}
|
||||
}
|
||||
|
||||
struct symbs_s const *sym = NULL;
|
||||
for (int i = 0; i < BASE_NSYMS; ++i) {
|
||||
if (c == symbs[i].c) {
|
||||
sym = &symbs[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sym) {
|
||||
while (sym->nnext) {
|
||||
c = get_char(src);
|
||||
int found = 0;
|
||||
for (int i = 0; i < sym->nnext; ++i) {
|
||||
if (c == sym->next[i].c) {
|
||||
found = 1;
|
||||
sym = &sym->next[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
unget_char(src, c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sym->sym == LAST_SYM + 1) {
|
||||
unget_char(src, sym->c);
|
||||
sym = &symbs[0]; // This is where no check is made (see comment in the definition of symbs)
|
||||
}
|
||||
src->st = ((src->st == PREPST_NL) && (sym->sym == SYM_HASH)) ? PREPST_HASH : PREPST_NONE;
|
||||
return (preproc_token_t){
|
||||
.tokt = PPTOK_SYM,
|
||||
.tokv.sym = sym->sym
|
||||
};
|
||||
}
|
||||
|
||||
src->st = PREPST_NONE;
|
||||
printf("Invalid character 0x%X (%c) while preparing %s\n", (unsigned)c, (c >= 0x20) && (c < 127) ? c : '?', src->srcn);
|
||||
return (preproc_token_t){
|
||||
.tokt = PPTOK_INVALID,
|
||||
.tokv.c = (char)c
|
||||
};
|
||||
}
|
||||
preproc_token_t pre_next_newline_token(prepare_t *src) {
|
||||
start_next_token:
|
||||
int c = get_char(src);
|
||||
if (c == EOF) {
|
||||
// Force newline at EOF
|
||||
unget_char(src, c);
|
||||
src->st = PREPST_NL;
|
||||
return (preproc_token_t){
|
||||
.tokt = PPTOK_NEWLINE,
|
||||
.tokv.c = (char)c
|
||||
};
|
||||
}
|
||||
if (c == '\n') {
|
||||
src->st = PREPST_NL;
|
||||
return (preproc_token_t){
|
||||
.tokt = PPTOK_NEWLINE,
|
||||
.tokv.c = (char)c
|
||||
};
|
||||
}
|
||||
goto start_next_token;
|
||||
}
|
18
wrapperhelper/src/prepare.h
Normal file
18
wrapperhelper/src/prepare.h
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef PREPARE_H
|
||||
#define PREPARE_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "cstring.h"
|
||||
#include "lang.h"
|
||||
|
||||
typedef struct prepare_s prepare_t;
|
||||
|
||||
prepare_t *prepare_new_file(FILE *f, const char *filename); // Takes ownership of f
|
||||
void prepare_del(prepare_t *src);
|
||||
preproc_token_t pre_next_token(prepare_t *src, int allow_comments);
|
||||
preproc_token_t pre_next_newline_token(prepare_t *src); // In a comment ignore everything until the EOL or EOF
|
||||
|
||||
#endif // PREPARE_H
|
2901
wrapperhelper/src/preproc.c
Normal file
2901
wrapperhelper/src/preproc.c
Normal file
File diff suppressed because it is too large
Load Diff
17
wrapperhelper/src/preproc.h
Normal file
17
wrapperhelper/src/preproc.h
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef PREPROC_H
|
||||
#define PREPROC_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "lang.h"
|
||||
|
||||
typedef struct preproc_s preproc_t;
|
||||
|
||||
preproc_t *preproc_new_file(FILE *f, char *dirname, const char *filename); // Takes ownership of f and dirname
|
||||
proc_token_t proc_next_token(preproc_t *src);
|
||||
int proc_unget_token(preproc_t *src, proc_token_t *tok);
|
||||
void preproc_del(preproc_t *src);
|
||||
|
||||
#endif // PREPROC_H
|
105
wrapperhelper/src/vector.c
Normal file
105
wrapperhelper/src/vector.c
Normal file
@ -0,0 +1,105 @@
|
||||
#include "vector.h"
|
||||
|
||||
VECTOR_IMPL(voidp, (void))
|
||||
VECTOR_IMPL(char, (void))
|
||||
VECTOR_IMPL(charp, (void))
|
||||
static void stringp_del(string_t **s) { return string_del(*s); }
|
||||
VECTOR_IMPL(string, stringp_del)
|
||||
|
||||
VECTOR(voidp) *vector_new_impl(void) {
|
||||
VECTOR(voidp) *ret = malloc(sizeof(*ret));
|
||||
if (!ret) return NULL;
|
||||
ret->vsize = ret->vcap = 0; ret->content_v = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
VECTOR(voidp) *vector_new_cap_impl(size_t elem_size, size_t cap) {
|
||||
VECTOR(voidp) *ret = malloc(sizeof(*ret));
|
||||
if (!ret) return NULL;
|
||||
cap = (cap < VECTOR_MIN_CAP) ? VECTOR_MIN_CAP : cap * 2;
|
||||
ret->content_v = malloc(cap * elem_size);
|
||||
if (!ret->content_v) {
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
ret->vcap = cap;
|
||||
ret->vsize = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int vector_reserve_impl(VECTOR(voidp) *v, size_t elem_size, size_t cap) {
|
||||
size_t new_cap = (cap < VECTOR_MIN_CAP) ? VECTOR_MIN_CAP : cap;
|
||||
if (new_cap <= v->vcap) return 1;
|
||||
|
||||
void *new_content_v = realloc(v->content_v, elem_size * new_cap);
|
||||
if (!new_content_v) return 0;
|
||||
v->content_v = new_content_v;
|
||||
v->vcap = new_cap;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vector_trim_impl(VECTOR(voidp) *v, size_t elem_size) {
|
||||
if (v->vsize) {
|
||||
void *new_content_v = realloc(v->content_v, elem_size * v->vsize);
|
||||
if (!new_content_v) return 0;
|
||||
v->content_v = new_content_v;
|
||||
v->vcap = v->vsize;
|
||||
return 1;
|
||||
} else {
|
||||
free(v->content_v);
|
||||
v->content_v = NULL;
|
||||
v->vcap = 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void vector_common_pop_impl(VECTOR(voidp) *v, size_t elem_size) {
|
||||
if (--v->vsize < v->vcap / 4) {
|
||||
size_t new_cap = (v->vcap / 2 < VECTOR_MIN_CAP) ? VECTOR_MIN_CAP : v->vcap / 2;
|
||||
if (new_cap == v->vcap) return;
|
||||
void *new_content_v = realloc(v->content_v, elem_size * new_cap);
|
||||
if (!new_content_v) return; // We don't really care if the realloc fails, we just need to not update anything
|
||||
v->content_v = new_content_v;
|
||||
v->vcap = new_cap;
|
||||
}
|
||||
}
|
||||
|
||||
void vector_common_popn_impl(VECTOR(voidp) *v, size_t n, size_t elem_size) {
|
||||
if (n > v->vsize) n = v->vsize;
|
||||
v->vsize -= n;
|
||||
if (v->vsize < v->vcap / 4) {
|
||||
size_t new_cap = v->vcap / 2;
|
||||
while (v->vsize < new_cap / 4) new_cap /= 2;
|
||||
new_cap = (new_cap < VECTOR_MIN_CAP) ? VECTOR_MIN_CAP : new_cap;
|
||||
if (new_cap == v->vcap) return;
|
||||
void *new_content_v = realloc(v->content_v, elem_size * new_cap);
|
||||
if (!new_content_v) return; // We don't really care if the realloc fails, we just need to not update anything
|
||||
v->content_v = new_content_v;
|
||||
v->vcap = new_cap;
|
||||
}
|
||||
}
|
||||
|
||||
void vector_common_clear_impl(VECTOR(voidp) *v) {
|
||||
if (!v->content_v) return;
|
||||
free(v->content_v);
|
||||
v->vsize = v->vcap = 0; v->content_v = NULL;
|
||||
}
|
||||
|
||||
int vector_push_vec_impl(VECTOR(voidp) *v1, VECTOR(voidp) *v2, size_t start, size_t len, size_t elem_size) {
|
||||
if (start >= v2->vsize) return 1;
|
||||
if (start + len > v2->vsize) len = v2->vsize - start;
|
||||
if (!len) return 1;
|
||||
if (v1->vsize + len > v1->vcap) {
|
||||
size_t new_cap = (v1->vcap < VECTOR_MIN_CAP) ? VECTOR_MIN_CAP : v1->vcap * 2;
|
||||
while (v1->vsize + len > new_cap) {
|
||||
new_cap = new_cap * 2;
|
||||
}
|
||||
void *new_content_v = realloc(v1->content_v, elem_size * new_cap);
|
||||
if (!new_content_v) return 0;
|
||||
v1->content_v = new_content_v;
|
||||
v1->vcap = new_cap;
|
||||
}
|
||||
memcpy((char*)v1->content_v + elem_size * v1->vsize, (char*)v2->content_v + elem_size * start, elem_size * len);
|
||||
v1->vsize += len;
|
||||
return 1;
|
||||
}
|
213
wrapperhelper/src/vector.h
Normal file
213
wrapperhelper/src/vector.h
Normal file
@ -0,0 +1,213 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef VECTOR_H
|
||||
#define VECTOR_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cstring.h"
|
||||
|
||||
// Note: do not use with empty types; simply use ints in this case.
|
||||
|
||||
/** Thread-unsafe vector implementation
|
||||
* USAGE:
|
||||
* ======
|
||||
* VECTOR_DECLARE ----------- Declare a new vector type. Takes the name and the element type.
|
||||
* VECTOR_IMPL -------------- Implements required functions for a vector type. Takes the name and the destructor of a pointer to the element.
|
||||
* VECTOR_DECLARE_STATIC ---- Declare a new vector type with static implementation. Takes the name and the element type.
|
||||
* VECTOR_IMPL_STATIC ------- Implements required functions for a vector type. Takes the name and the destructor of a pointer to the element.
|
||||
* Functions are declared static.
|
||||
* VECTOR_DEL --------------- Macro that takes the vector name and gives a function taking a vector and deletes it.
|
||||
* VECTOR ------------------- The vector type. Takes the name.
|
||||
* VECTOR_ELEM -------------- The element type. Takes the name.
|
||||
* vector_new --------------- Creates a new vector. Takes the name.
|
||||
* vector_new_cap ----------- Creates a new vector with a given capacity. Takes the name and the capacity.
|
||||
* vector_reserve ----------- Ensures a vector has at least a given capacity. Takes the name, the vector and the capacity. May not reduce the vector capacity.
|
||||
* vector_trim -------------- Ensures a vector has a capacity equal to its size. Takes the name, the vector. May reduce the vector capacity.
|
||||
* vector_del --------------- Frees a vector. Takes the name and the vector. Destructs the content of the vector.
|
||||
* vector_steal ------------- Frees a vector and returns the content. Takes the name and the vector. May reduce the vector capacity.
|
||||
* vector_del_freed --------- Frees a vector without freeing the content. Takes the name and the vector. Does not interact with the content of the vector.
|
||||
* vector_del_free_from ----- Frees a vector without freeing all of the content. Takes the name, the vector and the first element to free.
|
||||
* Destroys part of the content of the vector.
|
||||
* vector_push -------------- Push a new element. Takes the name, the vector and the new element. Does not fail if enough capacity remains.
|
||||
* vector_push_vec ---------- Push a vector of new elements. Takes the name, the vector and the new element vector. Does not fail if enough capacity remains.
|
||||
* vector_push_vec_slice ---- Push a slice of a vector of elements. Takes the name, the vector the new element vector, start and size.
|
||||
* Does not fail if enough capacity remains.
|
||||
* vector_pop --------------- Pops the last element. Takes the name and the vector. May reduce the vector capacity.
|
||||
* vector_pop_nodel --------- Pops the last element without freeing it. Takes the name and the vector. May reduce the vector capacity.
|
||||
* vector_pop_slice --------- Pops the last N element. Takes the name, the vector and the number of elements to remove.
|
||||
* vector_pop_nodel_slice --- Pops the last N element without freeing them. Takes the name, the vector and the number of elements to remove.
|
||||
* May reduce the vector capacity.
|
||||
* vector_clear ------------- Remove every element. Takes the name and the vector.
|
||||
* vector_clear_nodel ------- Remove every element without freeing them. Takes the name and the vector.
|
||||
* vector_remove ------------ Removes an element. Takes the name, the vector and the element number. May reduce the vector capacity.
|
||||
* vector_size -------------- Vector size (number of elements). Takes the name and the vector.
|
||||
* vector_cap --------------- Vector capacity (number of elements). Takes the name and the vector.
|
||||
* vector_content ----------- Pointer to the vector content. Takes the name and the vector.
|
||||
* vector_begin ------------- Start of the vector content. Takes the name and the vector.
|
||||
* vector_end --------------- End of the vector content. Points to unmanaged memory. Takes the name and the vector.
|
||||
* vector_last -------------- Last element of the vector. Points to invalid memory if size is zero. Takes the name and the vector.
|
||||
* vector_for --------------- Iterate over the elements of a vector. This is a for loop. Takes the name, the iterator name and the vector.
|
||||
*
|
||||
* VECTOR_DEL(name)(v) is equivalent to vector_del(name, v).
|
||||
* Predefined vectors: string (string_t*), char (char), charp (char*), voidp (void*)
|
||||
*
|
||||
* EXAMPLE:
|
||||
* ========
|
||||
* Header myvec.h:
|
||||
* ---------------
|
||||
// ...
|
||||
VECTOR_DECLARE(myvec, my_elem_t*)
|
||||
// ...
|
||||
|
||||
* Source myvec.c:
|
||||
* ---------------
|
||||
// ...
|
||||
VECTOR_IMPL(myvec)
|
||||
// ...
|
||||
|
||||
* Source main.c:
|
||||
* -------------------
|
||||
// ...
|
||||
extern my_elem_t elems[2];
|
||||
int main() {
|
||||
VECTOR(myvec) *vec = vector_new_cap(myvec, 2);
|
||||
vector_push(myvec, vec, &elems[0]);
|
||||
vector_push(myvec, vec, &elems[1]);
|
||||
vector_for (myvec, it, vec) {
|
||||
printf("We have an element: %s\n", it->elem_name);
|
||||
}
|
||||
vector_del(myvec, vec);
|
||||
}
|
||||
*/
|
||||
|
||||
#define VECTOR(name) vector_##name##_t
|
||||
#define VECTOR_ELEM(name) vector_##name##_elem
|
||||
|
||||
#define VECTOR_MIN_CAP 8
|
||||
|
||||
#define VECTOR_DECLARE_(name, t, pre) \
|
||||
typedef struct vector_##name##_s { \
|
||||
size_t vsize; \
|
||||
size_t vcap; \
|
||||
union { \
|
||||
t *content; \
|
||||
void *content_v; \
|
||||
}; \
|
||||
} VECTOR(name); \
|
||||
typedef t VECTOR_ELEM(name); \
|
||||
pre VECTOR_ELEM(name) *vector_steal_##name(VECTOR(name) *v); \
|
||||
pre void vector_pop_del_##name(VECTOR(name) *v); \
|
||||
pre void vector_popn_del_##name(VECTOR(name) *v, size_t idx); \
|
||||
pre void vector_clear_del_##name(VECTOR(name) *v); \
|
||||
pre void vector_del_from_##name(VECTOR(name) *v, size_t idx); \
|
||||
pre int vector_push_elem_##name(VECTOR(name) *v, VECTOR_ELEM(name) elem);
|
||||
#define VECTOR_DECLARE(name, t) VECTOR_DECLARE_(name, t,)
|
||||
#define VECTOR_DECLARE_STATIC(name, t) VECTOR_DECLARE_(name, t, static)
|
||||
|
||||
VECTOR_DECLARE(voidp, void*)
|
||||
|
||||
VECTOR(voidp) *vector_new_impl(void);
|
||||
VECTOR(voidp) *vector_new_cap_impl(size_t elem_size, size_t cap);
|
||||
int vector_reserve_impl(VECTOR(voidp) *v, size_t elem_size, size_t cap);
|
||||
int vector_trim_impl(VECTOR(voidp) *v, size_t elem_size);
|
||||
void vector_common_pop_impl(VECTOR(voidp) *v, size_t elem_size);
|
||||
void vector_common_popn_impl(VECTOR(voidp) *v, size_t n, size_t elem_size);
|
||||
void vector_common_clear_impl(VECTOR(voidp) *v);
|
||||
int vector_push_vec_impl(VECTOR(voidp) *v1, VECTOR(voidp) *v2, size_t start, size_t len, size_t elem_size);
|
||||
|
||||
#define vector_new(name) (VECTOR(name)*)vector_new_impl()
|
||||
#define vector_new_cap(name, cap) (VECTOR(name)*)vector_new_cap_impl(sizeof(VECTOR_ELEM(name)), (cap))
|
||||
#define vector_del(name, v) vector_del_from_##name((v), 0)
|
||||
#define vector_del_freed(name, v) vector_del_from_##name((v), vector_size(name, (v)))
|
||||
#define vector_del_free_from(name, v, i) vector_del_from_##name((v), (i))
|
||||
#define VECTOR_DEL(name) vector_del_##name
|
||||
#define vector_steal(name, v) vector_steal_##name((v))
|
||||
#define vector_reserve(name, v, cap) vector_reserve_impl((VECTOR(voidp)*)(v), sizeof(VECTOR_ELEM(name)), (cap))
|
||||
#define vector_trim(name, v) vector_trim_impl((VECTOR(voidp)*)(v), sizeof(VECTOR_ELEM(name)))
|
||||
#define vector_push(name, v, e) vector_push_elem_##name((v), (e))
|
||||
#define vector_push_vec(name, v1, v2) vector_push_vec_impl((VECTOR(voidp)*)(v1), (VECTOR(voidp)*)(v2), 0, vector_size(name, (v2)), sizeof(VECTOR_ELEM(name)))
|
||||
#define vector_push_vec_slice(name, v1, v2, s, l) vector_push_vec_impl((VECTOR(voidp)*)(v1), (VECTOR(voidp)*)(v2), (s), (l), sizeof(VECTOR_ELEM(name)))
|
||||
#define vector_pop(name, v) vector_pop_del_##name((v))
|
||||
#define vector_pop_slice(name, v, n) vector_popn_del_##name((VECTOR(voidp)*)(v), (n))
|
||||
#define vector_pop_nodel(name, v) vector_common_pop_impl((VECTOR(voidp)*)(v), sizeof(VECTOR_ELEM(name)))
|
||||
#define vector_pop_nodel_slice(name, v, n) vector_common_popn_impl((VECTOR(voidp)*)(v), (n), sizeof(VECTOR_ELEM(name)))
|
||||
#define vector_clear(name, v) vector_clear_del_##name((v))
|
||||
#define vector_clear_nodel(name, v) vector_common_clear_impl((VECTOR(voidp)*)(v))
|
||||
#define vector_remove(name, v, i) vector_remove_##name((v), (i))
|
||||
|
||||
#define vector_size(name, v) ((v)->vsize)
|
||||
#define vector_cap(name, v) ((v)->vcap)
|
||||
#define vector_content(name, v) ((v)->content)
|
||||
#define vector_begin(name, v) ((v)->content)
|
||||
#define vector_end(name, v) ((v)->content + (v)->vsize)
|
||||
#define vector_last(name, v) ((v)->content[(v)->vsize - 1])
|
||||
#define vector_for(name, itname, v) \
|
||||
for (VECTOR_ELEM(name) *itname = vector_begin(name, (v)); itname < vector_end(name, (v)); ++itname)
|
||||
#define vector_for_from(name, itname, v, i) \
|
||||
for (VECTOR_ELEM(name) *itname = vector_begin(name, (v)) + (i); itname < vector_end(name, (v)); ++itname)
|
||||
#define vector_for_rev(name, itname, v) \
|
||||
for (VECTOR_ELEM(name) *itname = (v)->content ? vector_end(name, (v)) - 1 : NULL; (v)->content && (itname >= vector_begin(name, (v))); --itname)
|
||||
|
||||
#define VECTOR_IMPL_(name, dtor, pre) \
|
||||
pre VECTOR_ELEM(name) *vector_steal_##name(VECTOR(name) *v) { \
|
||||
vector_trim(name, v); \
|
||||
VECTOR_ELEM(name) *ret = v->content; \
|
||||
free(v); \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
pre void vector_pop_del_##name(VECTOR(name) *v) { \
|
||||
if (v->vsize) { \
|
||||
dtor(&vector_last(name, v)); \
|
||||
vector_common_pop_impl((VECTOR(voidp)*)v, sizeof(VECTOR_ELEM(name))); \
|
||||
} \
|
||||
} \
|
||||
pre void vector_popn_del_##name(VECTOR(name) *v, size_t n) { \
|
||||
if (v->vsize > n) n = v->vsize; \
|
||||
vector_for_from(name, it, v, v->vsize - n) { dtor(it); } \
|
||||
vector_common_popn_impl((VECTOR(voidp)*)v, n, sizeof(VECTOR_ELEM(name))); \
|
||||
} \
|
||||
\
|
||||
pre void vector_remove_##name(VECTOR(name) *v, size_t i) { \
|
||||
dtor(v->content + i); \
|
||||
memmove(v->content + i, v->content + i + 1, (v->vsize - i - 1) * sizeof(VECTOR_ELEM(name))); \
|
||||
vector_common_pop_impl((VECTOR(voidp)*)v, sizeof(VECTOR_ELEM(name))); \
|
||||
} \
|
||||
\
|
||||
pre void vector_clear_del_##name(VECTOR(name) *v) { \
|
||||
if (!v->content) return; \
|
||||
vector_for(name, it, v) { dtor(it); } \
|
||||
free(v->content); \
|
||||
v->content = NULL; \
|
||||
v->vcap = v->vsize = 0; \
|
||||
} \
|
||||
\
|
||||
pre void vector_del_from_##name(VECTOR(name) *v, size_t idx) { \
|
||||
vector_for_from(name, it, v, idx) { dtor(it); } \
|
||||
if (v->content) free(v->content); \
|
||||
free(v); \
|
||||
} \
|
||||
\
|
||||
pre int vector_push_elem_##name(VECTOR(name) *v, VECTOR_ELEM(name) elem) { \
|
||||
if (v->vsize >= v->vcap) { \
|
||||
size_t new_cap = (v->vcap < VECTOR_MIN_CAP) ? VECTOR_MIN_CAP : v->vcap * 2; \
|
||||
VECTOR_ELEM(name) *new_content = realloc(v->content, sizeof(VECTOR_ELEM(name)) * new_cap); \
|
||||
if (!new_content) return 0; \
|
||||
v->content = new_content; \
|
||||
v->vcap = new_cap; \
|
||||
} \
|
||||
v->content[v->vsize++] = elem; \
|
||||
return 1; \
|
||||
}
|
||||
#define VECTOR_IMPL(name, dtor) VECTOR_IMPL_(name, dtor,)
|
||||
#define VECTOR_IMPL_STATIC(name, dtor) VECTOR_IMPL_(name, dtor, static inline)
|
||||
|
||||
VECTOR_DECLARE(char, char)
|
||||
VECTOR_DECLARE(charp, char*)
|
||||
VECTOR_DECLARE(string, string_t*)
|
||||
|
||||
#endif // VECTOR_H
|
@ -1,33 +0,0 @@
|
||||
#pragma once
|
||||
#include <clang/AST/ASTContext.h>
|
||||
#include <clang/AST/Decl.h>
|
||||
#include <clang/AST/Type.h>
|
||||
#include <clang/Tooling/Tooling.h>
|
||||
#include <clang/AST/RecordLayout.h>
|
||||
#include <clang/AST/Decl.h>
|
||||
|
||||
#include <llvm/ADT/Triple.h>
|
||||
#include <llvm/Support/Casting.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
static const clang::Type* StripTypedef(clang::QualType type) {
|
||||
if (type->isTypedefNameType()) {
|
||||
return StripTypedef(type->getAs<clang::TypedefType>()->getDecl()->getUnderlyingType());
|
||||
} else {
|
||||
return type.getTypePtr();
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Need to support other triple except default target triple
|
||||
static std::string GetDeclHeaderFile(clang::ASTContext& Ctx, clang::Decl* Decl) {
|
||||
const auto& SourceManager = Ctx.getSourceManager();
|
||||
const clang::FileID FileID = SourceManager.getFileID(Decl->getBeginLoc());
|
||||
const clang::FileEntry *FileEntry = SourceManager.getFileEntryForID(FileID);
|
||||
if (FileEntry) {
|
||||
return FileEntry->getName().str();
|
||||
}
|
||||
return "";
|
||||
}
|
Loading…
Reference in New Issue
Block a user