diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-14 03:29:04 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-14 03:29:04 +0000 |
| commit | 699e18b65b07af73ccd14b28f83572b1843c7d37 (patch) | |
| tree | 98b98269e02eb9052b2af698383a858d63b120a7 | |
| parent | 3ef7f8b778dce23af25965b379126b9dd95d1c27 (diff) | |
feat(types): add native C scalar types and imported aliases
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
| -rw-r--r-- | include/cps/Lexer.h | 5 | ||||
| -rw-r--r-- | include/cps/TypeAST.h | 11 | ||||
| -rw-r--r-- | include/cps/TypeSystem.h | 18 | ||||
| -rw-r--r-- | lib/CodeGen/ArrayHandler.cc | 2 | ||||
| -rw-r--r-- | lib/CodeGen/CodeGen.cc | 24 | ||||
| -rw-r--r-- | lib/CodeGen/Designator.cc | 27 | ||||
| -rw-r--r-- | lib/CodeGen/FunctionGen.cc | 6 | ||||
| -rw-r--r-- | lib/CodeGen/TypeSystem.cc | 210 | ||||
| -rw-r--r-- | lib/Lexer/Lexer.cc | 5 | ||||
| -rw-r--r-- | lib/Parser/Parser.cc | 7 | ||||
| -rw-r--r-- | lib/Parser/ParserType.cc | 23 |
11 files changed, 323 insertions, 15 deletions
diff --git a/include/cps/Lexer.h b/include/cps/Lexer.h index 2876a58..2f6f231 100644 --- a/include/cps/Lexer.h +++ b/include/cps/Lexer.h @@ -89,6 +89,11 @@ enum Token { tok_endclass = -605, tok_public = -606, tok_private = -607, + tok_c_type = -608, + tok_c_int = -609, + tok_c_char = -610, + tok_c_string = -611, + tok_c_double = -612, tok_try = -700, tok_catch = -701, diff --git a/include/cps/TypeAST.h b/include/cps/TypeAST.h index a23f836..95c1d6d 100644 --- a/include/cps/TypeAST.h +++ b/include/cps/TypeAST.h @@ -8,6 +8,17 @@ namespace cps { +// TYPE <name> = C_TYPE("<C type expression>") +class CTypeDeclAST : public StmtAST { + std::string Name; + std::string Expression; +public: + CTypeDeclAST(std::string Name, std::string Expression) + : Name(std::move(Name)), Expression(std::move(Expression)) {} + const std::string &getName() const { return Name; } + const std::string &getExpression() const { return Expression; } +}; + // ---- User-defined type declarations (CIE 9618 §4.1) ---- // One field of a record TYPE body. Plain data, not a statement node, so the diff --git a/include/cps/TypeSystem.h b/include/cps/TypeSystem.h index 2ef1cd6..20c485f 100644 --- a/include/cps/TypeSystem.h +++ b/include/cps/TypeSystem.h @@ -29,7 +29,9 @@ enum class TypeKind { Void, Enum, Record, - Pointer + Pointer, + CScalar, + CPointer }; // ---- Per-kind payloads (filled only for the matching TypeKind) ---- @@ -68,6 +70,16 @@ struct TypeInfo { EnumPayload Enum; // Kind == Enum only PointerPayload Pointer; // Kind == Pointer only + // C aliases share an identity even when their pseudocode names differ. + std::string CIdentity; + unsigned CRank = 0; + bool CSigned = false; + std::string CInputFormat; + std::string COutputFormat; + + bool isC() const; + bool sameType(const TypeInfo *Other) const; + bool isNumeric() const; bool isIntegral() const; bool isReal() const; @@ -125,6 +137,10 @@ public: bool definePointer(const std::string &Name, const std::string &PointeeName, std::string &Err); + bool defineCAlias(const std::string &Name, const std::string &Expression, + std::string &Err); + const TypeInfo *importCType(const std::string &Expression, std::string &Err); + bool sameType(const std::string &Left, const std::string &Right) const; const EnumConstant *lookupEnumConstant(const std::string &Name) const; diff --git a/lib/CodeGen/ArrayHandler.cc b/lib/CodeGen/ArrayHandler.cc index 8b37b8f..bd68473 100644 --- a/lib/CodeGen/ArrayHandler.cc +++ b/lib/CodeGen/ArrayHandler.cc @@ -321,7 +321,7 @@ bool ArrayHandler::emitArrayArgument(ExprAST *ArgExpr, Callee.c_str(), ElemTypeName.c_str()); return false; } - if (Meta->ElementTypeName != ElemTypeName) { + if (!CG.resolveType(Meta->ElementTypeName)->sameType(CG.resolveType(ElemTypeName))) { CG.reportError("Array argument %s to %s must have element type %s (got %s)", Var->getName().c_str(), Callee.c_str(), ElemTypeName.c_str(), Meta->ElementTypeName.c_str()); diff --git a/lib/CodeGen/CodeGen.cc b/lib/CodeGen/CodeGen.cc index f69fc03..8c01972 100644 --- a/lib/CodeGen/CodeGen.cc +++ b/lib/CodeGen/CodeGen.cc @@ -262,6 +262,7 @@ const TypeInfo *CodeGen::getExprTypeInfo(ExprAST *Expr) const { const TypeInfo *L = getExprTypeInfo(Bin->getLHS()); const TypeInfo *R = getExprTypeInfo(Bin->getRHS()); + if ((L && L->isC()) || (R && R->isC())) return nullptr; // Enum arithmetic: E +/- INTEGER (enum on the left) yields the enum; // every other user-kind combination has no type (emission rejects it). if ((L && L->isUserKind()) || (R && R->isUserKind())) { @@ -387,6 +388,8 @@ Value *CodeGen::coerceValueToType(Value *Val, const TypeInfo *TargetInfo) { case TypeKind::Enum: case TypeKind::Record: case TypeKind::Pointer: + case TypeKind::CScalar: + case TypeKind::CPointer: reportError("Internal: a %s value reached representation coercion without a name-level check", TargetInfo->Name.c_str()); return nullptr; @@ -507,6 +510,11 @@ void CodeGen::emitOutputValue(Value *Val, const TypeInfo *Info, bool AppendNewli reportError("Cannot OUTPUT a value of pointer type %s", Info->Name.c_str()); return; + case TypeKind::CScalar: + case TypeKind::CPointer: + reportError("OUTPUT is not supported for type %s", Info->Name.c_str()); + return; + case TypeKind::Void: reportError("Cannot OUTPUT a VOID value"); return; @@ -644,6 +652,10 @@ Value *CodeGen::emitExpr(ExprAST *Expr) { // '&' path: their admissible operations are decided by name here. const TypeInfo *LT = getExprTypeInfo(Bin->getLHS()); const TypeInfo *RT = getExprTypeInfo(Bin->getRHS()); + if ((LT && LT->isC()) || (RT && RT->isC())) { + reportError("C operators require explicit support for their operand types"); + return nullptr; + } if ((LT && LT->isUserKind()) || (RT && RT->isUserKind())) { return emitUserKindBinaryOp(Bin, LT, RT); } @@ -719,7 +731,7 @@ Value *CodeGen::emitExpr(ExprAST *Expr) { } if (Name == "ASC") { const TypeInfo *ArgType = getExprTypeInfo(Call->getArgs()[0].get()); - if (ArgType && ArgType->isUserKind()) { + if (ArgType && (ArgType->isUserKind() || ArgType->isC())) { reportError("ASC expects a CHAR or STRING (got %s)", ArgType->Name.c_str()); return nullptr; } @@ -747,7 +759,7 @@ Value *CodeGen::emitExpr(ExprAST *Expr) { } if (Name == "NUM_TO_STR") { const TypeInfo *ArgType = getExprTypeInfo(Call->getArgs()[0].get()); - if (ArgType && ArgType->isUserKind()) { + if (ArgType && (ArgType->isUserKind() || ArgType->isC())) { reportError("NUM_TO_STR expects a number (got %s)", ArgType->Name.c_str()); return nullptr; } @@ -850,7 +862,7 @@ bool CodeGen::marshalCallArgs(const std::string &Callee, return false; } // BYREF aliases the storage, so the types must match exactly. - if (Info->TypeName != TypeName) { + if (!Types->sameType(Info->TypeName, TypeName)) { reportError("BYREF argument %s to %s must be of type %s (got %s)", Var->getName().c_str(), Callee.c_str(), TypeName.c_str(), Info->TypeName.c_str()); @@ -1093,11 +1105,11 @@ void CodeGen::emitStmt(StmtAST *Stmt) { reportError("RETURN is only allowed inside a FUNCTION or PROCEDURE"); return; } - if (Sig->ReturnTypeName == "VOID" && Ret->getRetVal()) { + if (F->getReturnType()->isVoidTy() && Ret->getRetVal()) { reportError("RETURN with a value is only allowed in a FUNCTION"); return; } - if (Sig->ReturnTypeName != "VOID" && !Ret->getRetVal()) { + if (!F->getReturnType()->isVoidTy() && !Ret->getRetVal()) { reportError("RETURN in a FUNCTION requires a value"); return; } @@ -1293,7 +1305,7 @@ void CodeGen::emitStmt(StmtAST *Stmt) { // TYPE declarations are registered by compile()'s pre-pass (the parser // guarantees they are top-level); nothing is emitted here. if (dynamic_cast<EnumTypeDeclAST*>(Stmt) || dynamic_cast<PointerTypeDeclAST*>(Stmt) || - dynamic_cast<RecordTypeDeclAST*>(Stmt)) { + dynamic_cast<RecordTypeDeclAST*>(Stmt) || dynamic_cast<CTypeDeclAST*>(Stmt)) { return; } if (auto *DA = dynamic_cast<DesignatorAssignStmtAST*>(Stmt)) { diff --git a/lib/CodeGen/Designator.cc b/lib/CodeGen/Designator.cc index 9d14d23..c7d0796 100644 --- a/lib/CodeGen/Designator.cc +++ b/lib/CodeGen/Designator.cc @@ -42,7 +42,9 @@ void CodeGen::runTypePrePass(const std::vector<std::unique_ptr<StmtAST>> &Statem for (const auto &S : Statements) { bool Ok = true; - if (auto *E = dynamic_cast<EnumTypeDeclAST*>(S.get())) + if (auto *C = dynamic_cast<CTypeDeclAST*>(S.get())) + Ok = Types->defineCAlias(C->getName(), C->getExpression(), Err); + else if (auto *E = dynamic_cast<EnumTypeDeclAST*>(S.get())) Ok = Types->declareUserType(E->getName(), TypeKind::Enum, Err); else if (auto *P = dynamic_cast<PointerTypeDeclAST*>(S.get())) Ok = Types->declareUserType(P->getName(), TypeKind::Pointer, Err); @@ -163,6 +165,11 @@ bool CodeGen::emitLValue(ExprAST *E, LValueInfo &Out) { TypeName.c_str()); return false; } + const TypeInfo *Pointee = resolveType(PP->PointeeTypeName); + if (!Pointee || Pointee->isVoid()) { + reportError("Cannot dereference a void pointer"); + return false; + } Value *P = Builder->CreateLoad(PointerType::getUnqual(*TheContext), Addr, "deref_ptr"); RuntimeChecker->emitNullDerefCheck(P, D->getLine()); Addr = P; @@ -213,6 +220,22 @@ Value *CodeGen::emitCoercedExpr(ExprAST *E, const TypeInfo *Target) { const TypeInfo *Src = getExprTypeInfo(E); + if (Target->isC() || (Src && Src->isC())) { + if (auto *Addr = dynamic_cast<AddrOfExprAST*>(E)) { + const PointerPayload *PP = Target->asPointer(); + LValueInfo LV; + if (PP && emitLValue(Addr->getTarget(), LV)) { + if (Types->sameType(LV.TypeName, PP->PointeeTypeName)) return LV.Addr; + } + reportError("Address does not match C pointer type %s", Target->Name.c_str()); + return nullptr; + } + if (Src && Src->sameType(Target) && !Target->isVoid()) return emitExpr(E); + reportError("Cannot implicitly convert %s to %s; use an explicit cast", + Src ? Src->Name.c_str() : "expression", Target->Name.c_str()); + return nullptr; + } + if (Target->isUserKind()) { // ^x into a pointer target is structural: the pointee type name must // match the pointer type's declared pointee exactly (strict — the @@ -226,7 +249,7 @@ Value *CodeGen::emitCoercedExpr(ExprAST *E, const TypeInfo *Target) { } LValueInfo LV; if (!emitLValue(Addr->getTarget(), LV)) return nullptr; - if (LV.TypeName != PP->PointeeTypeName) { + if (!Types->sameType(LV.TypeName, PP->PointeeTypeName)) { reportError("%s is a pointer to %s and cannot point at a value of type %s", Target->Name.c_str(), PP->PointeeTypeName.c_str(), LV.TypeName.c_str()); return nullptr; diff --git a/lib/CodeGen/FunctionGen.cc b/lib/CodeGen/FunctionGen.cc index afa6074..480d9ba 100644 --- a/lib/CodeGen/FunctionGen.cc +++ b/lib/CodeGen/FunctionGen.cc @@ -117,6 +117,12 @@ Function *FunctionGen::emitPrototype(PrototypeAST *Proto) { std::vector<Type*> ArgTypes; for (const ParamDecl &P : Proto->getParams()) { + const TypeInfo *Info = Types.resolve(P.TypeName); + if (Info && Info->isVoid()) { + fprintf(stderr, "error: parameter %s cannot have void type\n", P.Name.c_str()); + HadError = true; + return nullptr; + } ParamSig PS; PS.TypeName = P.TypeName; PS.IsByRef = P.Mode == PassMode::ByRef; diff --git a/lib/CodeGen/TypeSystem.cc b/lib/CodeGen/TypeSystem.cc index f693ba1..73d4136 100644 --- a/lib/CodeGen/TypeSystem.cc +++ b/lib/CodeGen/TypeSystem.cc @@ -2,10 +2,49 @@ #include "cps/TypeAST.h" #include "llvm/IR/Constants.h" #include <utility> +#include <climits> +#include <limits> +#include <type_traits> +#include <sstream> +#include <cctype> using namespace llvm; using namespace cps; +namespace { + +std::string cTypeName(const std::string &Identity) { + return "C_TYPE(\"" + Identity + "\")"; +} + +// sizeof alone cannot distinguish padded x87 from IEEE quad or double-double. +template<typename T> Type *nativeFloatType(LLVMContext &C) { + constexpr int Digits = std::numeric_limits<T>::digits; + constexpr int Exponent = std::numeric_limits<T>::max_exponent; + static_assert(std::numeric_limits<T>::radix == 2, "Unsupported native C floating-point radix"); + static_assert((Digits == 24 && Exponent == 128) || + (Digits == 53 && Exponent == 1024) || + (Digits == 64 && Exponent == 16384) || + (Digits == 113 && Exponent == 16384) || + (Digits == 106 && Exponent == 1024), "Unsupported native C floating-point format"); + if constexpr (Digits == 24) return Type::getFloatTy(C); + if constexpr (Digits == 53) return Type::getDoubleTy(C); + if constexpr (Digits == 64) return Type::getX86_FP80Ty(C); + if constexpr (Digits == 113) return Type::getFP128Ty(C); + return Type::getPPC_FP128Ty(C); +} + +} // namespace + +bool TypeInfo::isC() const { return !CIdentity.empty(); } + +bool TypeInfo::sameType(const TypeInfo *Other) const { + if (!Other) return false; + if (isC() || Other->isC()) + return isC() && Other->isC() && CIdentity == Other->CIdentity; + return Name == Other->Name; +} + const RecordFieldInfo *RecordPayload::findField(const std::string &Name) const { for (const auto &F : Fields) { if (F.first == Name) return &F.second; @@ -38,7 +77,7 @@ bool TypeInfo::isChar() const { } bool TypeInfo::isVoid() const { - return Kind == TypeKind::Void; + return Kind == TypeKind::Void || (isC() && CIdentity == "void"); } bool TypeInfo::isEnum() const { @@ -50,7 +89,7 @@ bool TypeInfo::isRecord() const { } bool TypeInfo::isPointer() const { - return Kind == TypeKind::Pointer; + return Kind == TypeKind::Pointer || Kind == TypeKind::CPointer; } bool TypeInfo::isUserKind() const { @@ -69,6 +108,8 @@ bool TypeInfo::isOutputtable() const { case TypeKind::Void: case TypeKind::Record: case TypeKind::Pointer: + case TypeKind::CScalar: + case TypeKind::CPointer: return false; } return false; @@ -83,7 +124,7 @@ const EnumPayload *TypeInfo::asEnum() const { } const PointerPayload *TypeInfo::asPointer() const { - return Kind == TypeKind::Pointer ? &Pointer : nullptr; + return isPointer() ? &Pointer : nullptr; } TypeSystem::TypeSystem(LLVMContext &Ctx) : Context(Ctx) { @@ -97,6 +138,166 @@ void TypeSystem::registerBuiltins() { registerType("STRING", PointerType::getUnqual(Context), TypeKind::String); registerType("CHAR", Type::getInt8Ty(Context), TypeKind::Char); registerType("VOID", Type::getVoidTy(Context), TypeKind::Void); + + // The compiler's native C/C++ ABI determines representation, not a table + // of assumed LP64/LLP64 widths. LLVM's addressable bytes are eight bits. + static_assert(CHAR_BIT == 8, "LLVM requires eight-bit addressable bytes"); + auto Integral = [&](auto Sample, const char *Name, unsigned Rank, + const char *InputFormat, const char *OutputFormat) { + using T = decltype(Sample); + TypeInfo Info; + Info.Name = cTypeName(Name); + Info.CIdentity = Name; + Info.Kind = TypeKind::CScalar; + Info.LLVMType = Type::getIntNTy(Context, sizeof(T) * CHAR_BIT); + Info.CRank = Rank; + Info.CSigned = std::is_signed<T>::value; + Info.CInputFormat = InputFormat; + Info.COutputFormat = OutputFormat; + Types.emplace(Info.Name, std::move(Info)); + }; + Integral(char{}, "char", 2, " %c", "%c"); + Integral(static_cast<signed char>(0), "signed char", 2, "%hhd", "%hhd"); + Integral(static_cast<unsigned char>(0), "unsigned char", 2, "%hhu", "%hhu"); + Integral(short{}, "short", 3, "%hd", "%hd"); + Integral(static_cast<unsigned short>(0), "unsigned short", 3, "%hu", "%hu"); + Integral(int{}, "int", 4, "%d", "%d"); + Integral(static_cast<unsigned int>(0), "unsigned int", 4, "%u", "%u"); + Integral(long{}, "long", 5, "%ld", "%ld"); + Integral(static_cast<unsigned long>(0), "unsigned long", 5, "%lu", "%lu"); + Integral(static_cast<long long>(0), "long long", 6, "%lld", "%lld"); + Integral(static_cast<unsigned long long>(0), "unsigned long long", 6, "%llu", "%llu"); + + auto Floating = [&](auto Sample, const char *Name, unsigned Rank, const char *Format) { + TypeInfo Info; + Info.Name = cTypeName(Name); + Info.CIdentity = Name; + Info.Kind = TypeKind::CScalar; + Info.LLVMType = nativeFloatType<decltype(Sample)>(Context); + Info.CRank = Rank; + Info.CInputFormat = Format; + Info.COutputFormat = Rank == 9 ? "%Lf" : "%f"; + Types.emplace(Info.Name, std::move(Info)); + }; + Floating(float{}, "float", 7, "%f"); + Floating(double{}, "double", 8, "%lf"); + Floating(static_cast<long double>(0), "long double", 9, "%Lf"); + + TypeInfo Bool; + Bool.Name = cTypeName("_Bool"); + Bool.CIdentity = "_Bool"; + Bool.Kind = TypeKind::CScalar; + Bool.LLVMType = Type::getInt1Ty(Context); + Bool.CRank = 1; + Types.emplace(Bool.Name, std::move(Bool)); + TypeInfo Void; + Void.Name = cTypeName("void"); + Void.CIdentity = "void"; + Void.Kind = TypeKind::CScalar; + Void.LLVMType = Type::getVoidTy(Context); + Types.emplace(Void.Name, std::move(Void)); + + std::string Err; + defineCAlias("C_INT", "int", Err); + defineCAlias("C_CHAR", "char", Err); + defineCAlias("C_STRING", "char*", Err); + defineCAlias("C_DOUBLE", "double", Err); +} + +bool TypeSystem::sameType(const std::string &Left, const std::string &Right) const { + const TypeInfo *L = resolve(Left); + return L && L->sameType(resolve(Right)); +} + +const TypeInfo *TypeSystem::importCType(const std::string &Expression, std::string &Err) { + // Whitespace is immaterial around stars; C's multiword base type is + // validated separately. Stars must all precede or all follow the base. + std::istringstream Input(Expression); + std::string Word, Text; + while (Input >> Word) { + if (!Text.empty()) Text += ' '; + Text += Word; + } + unsigned Depth = 0; + bool Prefix = !Text.empty() && Text.front() == '*'; + if (Prefix) { + while (!Text.empty() && (Text.front() == '*' || Text.front() == ' ')) { + if (Text.front() == '*') ++Depth; + Text.erase(Text.begin()); + } + } else { + while (!Text.empty() && (Text.back() == '*' || Text.back() == ' ')) { + if (Text.back() == '*') ++Depth; + Text.pop_back(); + } + } + std::istringstream BaseWords(Text); + std::map<std::string, unsigned> Counts; + bool Valid = !Text.empty(); + while (BaseWords >> Word) { + if (Word != "signed" && Word != "unsigned" && Word != "short" && + Word != "long" && Word != "int" && Word != "char" && + Word != "float" && Word != "double" && Word != "_Bool" && Word != "void") + Valid = false; + ++Counts[Word]; + } + for (const auto &Entry : Counts) + if (Entry.second > (Entry.first == "long" ? 2u : 1u)) Valid = false; + auto Has = [&](const char *Name) { return Counts.count(Name) != 0; }; + if (Has("signed") && Has("unsigned")) Valid = false; + std::string Base; + if (Has("void") || Has("_Bool") || Has("float")) { + if (Counts.size() != 1) Valid = false; + Base = Has("void") ? "void" : Has("_Bool") ? "_Bool" : "float"; + } else if (Has("double")) { + if (Counts.size() != (Has("long") ? 2u : 1u) || (Has("long") && Counts["long"] > 1)) + Valid = false; + Base = Has("long") ? "long double" : "double"; + } else if (Has("char")) { + if (Has("int") || Has("short") || Has("long")) Valid = false; + Base = Has("unsigned") ? "unsigned char" : Has("signed") ? "signed char" : "char"; + } else { + if (Has("short") && Has("long")) Valid = false; + Base = Has("short") ? "short" : Has("long") ? + (Counts["long"] == 2 ? "long long" : "long") : "int"; + if (Has("unsigned")) Base = "unsigned " + Base; + } + if (!Valid) { + Err = "Invalid or unsupported C type expression '" + Expression + "'"; + return nullptr; + } + const TypeInfo *Info = resolve(cTypeName(Base)); + for (unsigned I = 0; I < Depth; ++I) { + std::string Identity = Info->CIdentity + '*'; + const TypeInfo *Existing = resolve(cTypeName(Identity)); + if (Existing) { + Info = Existing; + continue; + } + TypeInfo Pointer; + Pointer.Name = cTypeName(Identity); + Pointer.CIdentity = Identity; + Pointer.Kind = TypeKind::CPointer; + Pointer.LLVMType = PointerType::getUnqual(Context); + Pointer.Pointer.PointeeTypeName = Info->Name; + auto Result = Types.emplace(Pointer.Name, std::move(Pointer)); + Info = &Result.first->second; + } + return Info; +} + +bool TypeSystem::defineCAlias(const std::string &Name, const std::string &Expression, + std::string &Err) { + if (Types.count(Name) || EnumConstants.count(Name)) { + Err = "Type name '" + Name + "' is already defined or reserved"; + return false; + } + const TypeInfo *C = importCType(Expression, Err); + if (!C) return false; + TypeInfo Alias = *C; + Alias.Name = Name; + Types.emplace(Name, std::move(Alias)); + return true; } const TypeInfo *TypeSystem::resolve(const std::string &TypeName) const { @@ -297,6 +498,9 @@ Constant *TypeSystem::getZeroValue(const std::string &TypeName) const { return Constant::getNullValue(Info->LLVMType); // zeroinitializer case TypeKind::Pointer: return ConstantPointerNull::get(cast<PointerType>(Info->LLVMType)); + case TypeKind::CScalar: + case TypeKind::CPointer: + return Constant::getNullValue(Info->LLVMType); } return Constant::getNullValue(Info->LLVMType); diff --git a/lib/Lexer/Lexer.cc b/lib/Lexer/Lexer.cc index d366afc..31bafe1 100644 --- a/lib/Lexer/Lexer.cc +++ b/lib/Lexer/Lexer.cc @@ -74,6 +74,11 @@ int Lexer::gettok() { if (IdentifierStr == "REAL") return tok_real_kw; if (IdentifierStr == "STRING") return tok_string_kw; if (IdentifierStr == "CHAR") return tok_char_kw; + if (IdentifierStr == "C_TYPE") return tok_c_type; + if (IdentifierStr == "C_INT") return tok_c_int; + if (IdentifierStr == "C_CHAR") return tok_c_char; + if (IdentifierStr == "C_STRING") return tok_c_string; + if (IdentifierStr == "C_DOUBLE") return tok_c_double; if (IdentifierStr == "TRUE") return tok_true; if (IdentifierStr == "FALSE") return tok_false; diff --git a/lib/Parser/Parser.cc b/lib/Parser/Parser.cc index aeb81fe..3bc095e 100644 --- a/lib/Parser/Parser.cc +++ b/lib/Parser/Parser.cc @@ -112,6 +112,13 @@ bool Parser::ParseDesignatorSuffix(std::vector<DesignatorAccess> &Out) { } std::string Parser::ParseTypeName(bool AllowVoid) { + switch (CurTok) { + case tok_c_int: getNextToken(); return "C_INT"; + case tok_c_char: getNextToken(); return "C_CHAR"; + case tok_c_string: getNextToken(); return "C_STRING"; + case tok_c_double: getNextToken(); return "C_DOUBLE"; + default: break; + } if (CurTok == tok_integer_kw) { getNextToken(); return "INTEGER"; diff --git a/lib/Parser/ParserType.cc b/lib/Parser/ParserType.cc index 358e3e2..e249c4c 100644 --- a/lib/Parser/ParserType.cc +++ b/lib/Parser/ParserType.cc @@ -34,7 +34,26 @@ std::unique_ptr<StmtAST> Parser::ParseTypeDecl() { if (!IsClass && CurTok == tok_eq) { getNextToken(); - if (CurTok == '(') { + if (CurTok == tok_c_type) { + getNextToken(); + if (CurTok != '(') { + fprintf(stderr, "error: Expected '(' after C_TYPE at line %d\n", Lex.getLine()); + return nullptr; + } + getNextToken(); + if (CurTok != tok_string_literal) { + fprintf(stderr, "error: C_TYPE requires a string literal at line %d\n", Lex.getLine()); + return nullptr; + } + std::string Expression = Lex.StringVal; + getNextToken(); + if (CurTok != ')') { + fprintf(stderr, "error: Expected ')' after C_TYPE string at line %d\n", Lex.getLine()); + return nullptr; + } + getNextToken(); + Decl = std::make_unique<CTypeDeclAST>(Name, Expression); + } else if (CurTok == '(') { getNextToken(); std::vector<std::string> Values; while (true) { @@ -65,7 +84,7 @@ std::unique_ptr<StmtAST> Parser::ParseTypeDecl() { getNextToken(); return nullptr; } else { - fprintf(stderr, "error: Expected '(' or '^' after '=' in TYPE %s at line %d\n", + fprintf(stderr, "error: Expected '(', '^' or C_TYPE after '=' in TYPE %s at line %d\n", Name.c_str(), Lex.getLine()); return nullptr; } |
