From 1cd59d36f38146a594cb09d0f46c8e355f082380 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Mon, 29 Dec 2014 15:15:34 -0500 Subject: [PATCH] more template code --- bin/debugger.cpp | 8 +- bin/intern.cpp | 101 +++++++++++++++++ bin/intern.h | 14 +++ bin/template.h | 122 +++++++++++++++++--- bin/template_loader.rl | 229 +++++++++++++++++++++++++------------- bin/template_parser.lemon | 63 ++++++----- 6 files changed, 416 insertions(+), 121 deletions(-) create mode 100644 bin/intern.cpp create mode 100644 bin/intern.h diff --git a/bin/debugger.cpp b/bin/debugger.cpp index 9f1891d..6ff3cb6 100644 --- a/bin/debugger.cpp +++ b/bin/debugger.cpp @@ -49,6 +49,7 @@ #include "debugger.h" #include "debugger_internal.h" +#include "template.h" #include #include @@ -62,8 +63,6 @@ #include #include - - namespace { using namespace Debug::Internal; @@ -84,6 +83,8 @@ namespace { ToolMap tbrkMap; // tool breaks. + std::unordered_map TemplateTable; + struct BackTraceInfo { uint32_t a[8]; uint32_t d[8]; @@ -1255,6 +1256,9 @@ void Shell() LoadTrapFile(MPW::RootDirPathForFile("Globals.text"), GlobalTable); LoadTrapFile(MPW::RootDirPathForFile("Traps.text"), TrapTable); + LoadTemplateFile(MPW::RootDirPathForFile("Templates.text"), TemplateTable); + + // load the error code to error mnemonic ErrorTableInvert.reserve(ErrorTable.size()); diff --git a/bin/intern.cpp b/bin/intern.cpp new file mode 100644 index 0000000..2a65947 --- /dev/null +++ b/bin/intern.cpp @@ -0,0 +1,101 @@ +#include "intern.h" +#include + +namespace { + + std::unordered_multimap InternTable; + + std::string EmptyString; + + unsigned int DJBHash(const char* begin, size_t length) + { + unsigned int hash = 5381; + + for(size_t i = 0; i < length; ++i) + { + hash = ((hash << 5) + hash) + (begin[i]); + } + + return hash; + } +} + +namespace Intern { + + const std::string *String(std::string &&str) + { + size_t size = str.size(); + if (!size) return &EmptyString; + + unsigned hash = DJBHash(str.data(), size); + + auto range = InternTable.equal_range(hash); + auto iter = range.first; + auto endit = range.second; + + for( ; iter != endit; ++iter) + { + // hash matches, make sure the string does. + const std::string *s = iter->second; + + if (s->size() == size && std::memcmp(s->data(), str.data(), size) == 0) + return s; + } + + // insert it. I suppose this could throw, in which case a string would leak. + std::string *s = new std::string(std::move(str)); + InternTable.emplace(std::make_pair(hash, s)); + return s; + } + + const std::string *String(const char *begin, size_t size) + { + if (!size) return &EmptyString; + + unsigned hash = DJBHash(begin, size); + + auto range = InternTable.equal_range(hash); + auto iter = range.first; + auto endit = range.second; + + for( ; iter != endit; ++iter) + { + // hash matches, make sure the string does. + const std::string *s = iter->second; + + if (s->size() == size && std::memcmp(s->data(), begin, size) == 0) + return s; + } + + // insert it. I suppose this could throw, in which case a string would leak. + std::string *s = new std::string(begin, size); + InternTable.emplace(std::make_pair(hash, s)); + return s; + } + + const std::string *String(const char *begin, const char *end) + { + return String(begin, end - begin); + } + + + const std::string *String(const char *cp) + { + if (!cp || !*cp) return &EmptyString; + + return String(cp, strlen(cp)); + } + + const std::string *String(const std::string &s) + { + return String(s.data(), s.size()); + } + + + + +} + + + + diff --git a/bin/intern.h b/bin/intern.h new file mode 100644 index 0000000..8d319cd --- /dev/null +++ b/bin/intern.h @@ -0,0 +1,14 @@ +#ifndef __intern_h__ +#define __intern_h__ + +#include + +namespace Intern { + const std::string *String(const std::string &s); + const std::string *String(std::string &&s); + const std::string *String(const char *); + const std::string *String(const char *, size_t size); + const std::string *String(const char *, const char *); +}; + +#endif \ No newline at end of file diff --git a/bin/template.h b/bin/template.h index 68c1c93..aae9f80 100644 --- a/bin/template.h +++ b/bin/template.h @@ -6,40 +6,128 @@ namespace Debug { + enum { + + // 0x8000 = pointer + // 0x1000 = unsigned + // 0x0f00 = size + // 0-255 - type + + kSInt64 = 0x0800, + kUInt64 = 0x1800, + + kSInt32 = 0x0400, + kUInt32 = 0x1400, + + kSInt16 = 0x0200, + kUInt16 = 0x1200, + + kSInt8 = 0x0100, + kUInt8 = 0x1100, + + kStruct = 0x0000, + kStructPtr = 0x8000, + + // ptrs are a special case where size = 0 + //kVoid = 0x0001, + kVoidPtr = 0x8001, + + // these exist for display purposes. + kCStringPtr = 0x8002, + kPStringPtr = 0x8003, + + kOSType = 0x00404, + kBoolean = 0x0105, + kOSErr = 0x0206, + kHandle = 0x04007, + + }; + + inline unsigned MakePtr(unsigned type) { return type | 0x8000; } + inline unsigned MakeType(unsigned size, bool sign, bool ptr) { + unsigned rv = size << 8; + if (!sign) rv |= 0x0100; + if (ptr) rv |= 0x8000; + return rv; + } enum { - kUnknown = 0, - kStringPtr, // p-string - kCStringPtr, // c-string - kPtr, - kOSType, // four-cc - kBoolean, // unsigned char, display true/false + kDisplayNative = 0, + kDisplayStringPtr, // p-string + kDisplayCStringPtr, // c-string + kDisplayOSType, // four-cc + kDisplayBoolean, // unsigned char, display true/false + kDisplayOSErr, }; - struct Template; +#if 0 + + struct Type { + enum { + kSimpleType, + kStructType, + kPointerType, + }; + uint16_t tag; + uint16_t size; + }; + + // handles [signed/unsigned] type, type[], *type, and *type[] + struct SimpleType : public Type { + unsigned rank:16; // int == int[1] + unsigned display:14; // + + unsigned sign:1; + unsigned pointer:1; + + SimpleType() { + tag = kSimpleType; + size = 0; + rank = 0; + display = 0; + sign = 0; + pointer = 0; + } + }; + + struct PointerType: public Type { + Type *type; + }; + + struct StructType : public Type { + unsigned total_size; + FieldEntry *firstField; + }; + +#endif + struct FieldEntry; + typedef FieldEntry *Template; struct FieldEntry { std::string *name; unsigned type; unsigned count; - Template *tmpl; + Template tmpl; FieldEntry *next; + unsigned struct_size; // only populated for head entry. }; - struct Template { - unsigned type; // 0 for structs, < 256 for types. - - FieldEntry *firstField; - unsigned size; + struct TemplateParseInfo { + std::unordered_map *templates; + std::unordered_map *types; + int LineNumber; }; - void CreateTypedef(const std::string *name, int type); - void CreateTemplate(const std::string *name, FieldEntry *firstField); + + void CreateTypedef(const std::string *name, int type, TemplateParseInfo *); + void CreateTemplate(const std::string *name, FieldEntry *firstField, TemplateParseInfo *); + + + bool LoadTemplateFile(const std::string &filename, std::unordered_map &); + - extern std::unordered_map Templates; - extern int TemplateLine; } #endif diff --git a/bin/template_loader.rl b/bin/template_loader.rl index 97b24ab..56bd46e 100644 --- a/bin/template_loader.rl +++ b/bin/template_loader.rl @@ -12,6 +12,7 @@ #include "template_parser.h" #include "template.h" +#include "intern.h" namespace { @@ -39,63 +40,26 @@ namespace { } - - unsigned int DJBHash(const char* begin, const char *end) - { - unsigned int hash = 5381; - unsigned int i = 0; - - for(const char *iter = begin; iter != end; ++iter) - { - hash = ((hash << 5) + hash) + (*iter); - } - - return hash; - } - - std::unordered_multimap InternTable; - - const std::string *InternString(const char *begin, const char *end) - { - bool found = false; - unsigned hash = DJBHash(begin, end); - size_t length = end - begin; - - auto range = InternTable.equal_range(hash); - auto iter = range.first; - auto endit = range.second; - - for( ; iter != endit; ++iter) - { - // hash matches, make sure the string does. - const std::string *s = iter->second; - - if (s->length() == length && std::memcmp(s->data(), begin, length) == 0) - return s; - } - - // insert it. - std::string *s = new std::string(begin, end); - InternTable.emplace(std::make_pair(hash, s)); - return s; - } - } -void TemplateParse(void *yyp, int yymajor, void *yyminor); void *TemplateParseAlloc(void *(*mallocProc)(size_t)); void TemplateParseFree(void *p, void (*freeProc)(void*)); -void TemplateParse(void *yyp, int yymajor, int yyminor) +void TemplateParse(void *yyp, int yymajor, void *yyminor, Debug::TemplateParseInfo *); + + +void TemplateParse(void *yyp, int yymajor, int yyminor, Debug::TemplateParseInfo *info) { - TemplateParse(yyp, yymajor, &yyminor); + TemplateParse(yyp, yymajor, &yyminor, info); } -void TemplateParse(void *yyp, int yymajor, const std::string *yyminor) +void TemplateParse(void *yyp, int yymajor, const std::string *yyminor, Debug::TemplateParseInfo *info) { - TemplateParse(yyp, yymajor, (void *)yyminor); + TemplateParse(yyp, yymajor, (void *)yyminor, info); } +#define TemplateParse(a,b,c) TemplateParse(a,b,c, &info) + %%{ machine lexer; @@ -103,14 +67,14 @@ void TemplateParse(void *yyp, int yymajor, const std::string *yyminor) error := any* ${ fbreak; }; block_comment := |* - [\n\r] { TemplateLine++; }; + [\n\r] { info.LineNumber++; }; '*/' { fgoto main; }; any ; *|; main := |* - [\n\r] { TemplateLine++; }; + [\n\r] { info.LineNumber++; }; [ \t]+; '//' [^\r\n]* ; @@ -139,24 +103,26 @@ void TemplateParse(void *yyp, int yymajor, const std::string *yyminor) 'signed' { TemplateParse(parser, tkSIGNED, 0); }; 'unsigned' { TemplateParse(parser, tkUNSIGNED, 0); }; - 'int64_t' { TemplateParse(parser, tkTYPECODE, 'q'); }; - 'uint64_t' { TemplateParse(parser, tkTYPECODE, 'Q'); }; + 'int64_t' { TemplateParse(parser, tkTYPECODE, kSInt64); }; + 'uint64_t' { TemplateParse(parser, tkTYPECODE, kUInt64); }; - 'int32_t' { TemplateParse(parser, tkTYPECODE, 'l'); }; - 'uint32_t' { TemplateParse(parser, tkTYPECODE, 'L'); }; + 'int32_t' { TemplateParse(parser, tkTYPECODE, kSInt32); }; + 'uint32_t' { TemplateParse(parser, tkTYPECODE, kUInt32); }; - 'int16_t' { TemplateParse(parser, tkTYPECODE, 's'); }; - 'uint16_t' { TemplateParse(parser, tkTYPECODE, 'S'); }; + 'int16_t' { TemplateParse(parser, tkTYPECODE, kSInt16); }; + 'uint16_t' { TemplateParse(parser, tkTYPECODE, kUInt16); }; - 'int8_t' { TemplateParse(parser, tkTYPECODE, 'c'); }; - 'uint8_t' { TemplateParse(parser, tkTYPECODE, 'C'); }; + 'int8_t' { TemplateParse(parser, tkTYPECODE, kSInt8); }; + 'uint8_t' { TemplateParse(parser, tkTYPECODE, kUInt8); }; - 'StringPtr' { TemplateParse(parser, tkTYPECODE, kStringPtr); }; + 'StringPtr' { TemplateParse(parser, tkTYPECODE, kPStringPtr); }; 'CStringPtr' { TemplateParse(parser, tkTYPECODE, kCStringPtr); }; - 'Ptr' { TemplateParse(parser, tkTYPECODE, kPtr); }; + 'Ptr' { TemplateParse(parser, tkTYPECODE, kVoidPtr); }; 'OSType' { TemplateParse(parser, tkTYPECODE, kOSType); }; + 'OSErr' { TemplateParse(parser, tkTYPECODE, kOSErr); }; 'Boolean' { TemplateParse(parser, tkTYPECODE, kBoolean); }; + 'Handle' { TemplateParse(parser, tkTYPECODE, kHandle); }; # numbers. negative numbers are not allowed. @@ -177,16 +143,26 @@ void TemplateParse(void *yyp, int yymajor, const std::string *yyminor) // intern the string. - const std::string *name = InternString(ts, te); + const std::string *name = Intern::String(ts, te); + bool ok = false; - auto iter = Templates.find(*name); - if (iter != Templates.end()) - { - unsigned type = iter->second->type; - if (type) TemplateParse(parser, tkTYPECODE, type); - else TemplateParse(parser, tkTEMPLATE, iter->second); + if (!ok) { + auto iter = Types.find(*name); + if (iter != Types.end()) + { + TemplateParse(parser, tkTYPECODE, iter->second); + ok = true; + } } - else + if (!ok) { + auto iter = Templates.find(*name); + if (iter != Templates.end()) + { + TemplateParse(parser, tkTEMPLATE, iter->second); + ok = true; + } + } + if (!ok) { TemplateParse(parser, tkIDENTIFIER, name); } @@ -198,18 +174,108 @@ void TemplateParse(void *yyp, int yymajor, const std::string *yyminor) namespace Debug { -std::unordered_map Templates; -void CreateTypedef(const std::string *name, int type) -{ -} -void CreateTemplate(const std::string *name, FieldEntry *firstField) +void CreateTypedef(const std::string *name, int type, TemplateParseInfo *info) { + // check if it's an existing typedef... + + auto &Templates = *info->templates; + auto &Types = *info->types; + + + auto iter = Types.find(*name); + if (iter != Types.end()) + { + if (iter->second == type) return; // ok, just a duplicate. + fprintf(stderr, "Template Error: line %d - redefining %s\n", + info->LineNumber, name->c_str()); + + return; + } + + if (Templates.find(*name) != Templates.end()) + { + fprintf(stderr, "Template Error: line %d - redefining %s\n", + info->LineNumber, name->c_str()); + + return; + } + + Types.emplace(std::make_pair(*name, type)); } -int TemplateLine; +unsigned CalcSize(FieldEntry *e) +{ + unsigned size = 0; -bool ParseTemplates(const std::string &filename) + while (e) + { + unsigned s = (e->type & 0x0f00) >> 8; + + if (!s) { + // struct or pointer... + if (e->type & 0x8000) s = 4; + else if (e->tmpl) s = e->tmpl->struct_size; + } + + if (e->count != 0) s *= e->count; + + size += s; + e = e->next; + } + return size; +} + +FieldEntry *Reverse(FieldEntry *e) +{ + if (!e) return e; + + // reverse the order... + FieldEntry *prev; + FieldEntry *next; + + prev = nullptr; + for(;;) + { + next = e->next; + e->next = prev; + + prev = e; + e = next; + if (!e) return prev; + } +} + + +void CreateTemplate(const std::string *name, FieldEntry *firstField, TemplateParseInfo *info) +{ + auto &Templates = *info->templates; + auto &Types = *info->types; + + // check if it exists... + + if (Templates.find(*name) != Templates.end()) + { + fprintf(stderr, "Template Error: line %d - redefining %s\n", + info->LineNumber, name->c_str()); + return; + } + + if (Types.find(*name) != Types.end()) + { + fprintf(stderr, "Template Error: line %d - redefining %s\n", + info->LineNumber, name->c_str()); + return; + } + + firstField = Reverse(firstField); + firstField->struct_size = CalcSize(firstField); + + Templates.emplace(std::make_pair(*name, firstField)); +} + + +bool LoadTemplateFile(const std::string &filename, std::unordered_map &Templates) { %% write data; @@ -219,6 +285,17 @@ bool ParseTemplates(const std::string &filename) struct stat st; char *buffer; + std::unordered_map Types; + TemplateParseInfo info; + + info.LineNumber = 1; + info.templates = &Templates; + info.types = &Types; + + // simple types are handled via the lexer so no need to populate them here. + + + if (stat(filename.c_str(), &st) < 0) return false; if (st.st_size == 0) return false; @@ -241,9 +318,6 @@ bool ParseTemplates(const std::string &filename) parser = TemplateParseAlloc(malloc); - - TemplateLine = 1; - const char *p = buffer; const char *pe = buffer + st.st_size; const char *eof = pe; @@ -272,7 +346,8 @@ bool ParseTemplates(const std::string &filename) } if (p == pe) { - TemplateParse(parser, tkEOF, 0); + // ? + //TemplateParse(parser, tkEOF, 0); break; } } diff --git a/bin/template_parser.lemon b/bin/template_parser.lemon index 9cb1e20..88f7632 100644 --- a/bin/template_parser.lemon +++ b/bin/template_parser.lemon @@ -1,5 +1,7 @@ %token_prefix tk %name TemplateParse +%extra_argument { Debug::TemplateParseInfo *info } + %include { @@ -13,24 +15,22 @@ %type struct_fields { FieldEntry * } %type struct_field { FieldEntry * } -%type array_count { int } -%type opt_star { int } -%type typecode { int } -%type type { int } -start ::= templates EOF. +start ::= templates. templates ::= templates struct. templates ::= templates typedef. templates ::= . +// typedeffing arrays or pointers is not allowed. + typedef ::= TYPEDEF type(a) IDENTIFIER(b). { - CreateTypedef((std::string *)b, a); + CreateTypedef((std::string *)b, a, info); } struct ::= STRUCT IDENTIFIER(a) LBRACE struct_fields(b) RBRACE SEMI. { - CreateTemplate((std::string *)a, b); + CreateTemplate((std::string *)a, b, info); } struct_fields(rhs) ::= struct_fields(a) struct_field(b). { @@ -57,50 +57,63 @@ struct_field(rhs) ::= opt_volatile TEMPLATE(a) opt_star(star) IDENTIFIER(b) arra FieldEntry *e = (FieldEntry *)calloc(sizeof(FieldEntry), 1); e->name = (std::string *)b; - e->type = star ? kPtr : 0; - e->tmpl = (Template *)a; + e->type = star ? kStruct : kStructPtr; + e->tmpl = (Template)a; e->count = c; rhs = e; } -array_count(rhs) ::= . { rhs = -1; } -array_count(rhs) ::= LBRACKET INTEGER(a) RBRACKET. { rhs = *(int *)a; } +%type array_count { int } +array_count(rhs) ::= . { rhs = 0; } +array_count(rhs) ::= LBRACKET INTEGER(a) RBRACKET. { + int i = *(int *)a; + if (i == 0) { + fprintf(stderr, "Template error: line %u: 0-sized arrays are not allowed.\n", + info->LineNumber); + i = 1; + } + rhs = i; +} + +%type type { int } +type(rhs) ::= opt_volatile typecode(a). { rhs = a; } // this is an expected error... type(rhs) ::= opt_volatile IDENTIFIER(xxx). { // ugh, Lemon will blindly replace text within a string. fprintf(stderr, "Template error: line %u: %s is not a known type.\n", - TemplateLine, ((std::string *)xxx)->c_str()); + info->LineNumber, ((std::string *)xxx)->c_str()); rhs = 'i'; } -type(rhs) ::= opt_volatile typecode(a). { rhs = a; } opt_volatile ::= . opt_volatile ::= VOLATILE. -typecode(rhs) ::= SIGNED. { rhs = 'i'; } -typecode(rhs) ::= UNSIGNED. {rhs = 'I'; } -typecode(rhs) ::= opt_signed CHAR. { rhs = 'c'; } -typecode(rhs) ::= UNSIGNED CHAR. { rhs = 'C'; } +%type typecode { int } +typecode(rhs) ::= SIGNED. { rhs = kSInt32; } +typecode(rhs) ::= UNSIGNED. {rhs = kUInt32; } -typecode(rhs) ::= opt_signed SHORT. { rhs = 's'; } -typecode(rhs) ::= UNSIGNED SHORT. { rhs = 'S'; } +typecode(rhs) ::= opt_signed CHAR. { rhs = kSInt8; } +typecode(rhs) ::= UNSIGNED CHAR. { rhs = kUInt8; } -typecode(rhs) ::= opt_signed LONG opt_int. { rhs = 'l'; } -typecode(rhs) ::= UNSIGNED LONG opt_int. { rhs = 'L'; } +typecode(rhs) ::= opt_signed SHORT. { rhs = kSInt16; } +typecode(rhs) ::= UNSIGNED SHORT. { rhs = kUInt16; } -typecode(rhs) ::= opt_signed LONG LONG. { rhs = 'q'; } -typecode(rhs) ::= UNSIGNED LONG LONG. { rhs = 'Q'; } +typecode(rhs) ::= opt_signed LONG opt_int. { rhs = kSInt32; } +typecode(rhs) ::= UNSIGNED LONG opt_int. { rhs = kUInt32; } + +typecode(rhs) ::= opt_signed LONG LONG. { rhs = kSInt64; } +typecode(rhs) ::= UNSIGNED LONG LONG. { rhs = kUInt64; } typecode(rhs) ::= TYPECODE(a). { rhs = *(int *)a; } /* pointers are not fully supported yet */ -typecode(rhs) ::= VOID STAR. { rhs = kPtr; } +typecode(rhs) ::= VOID STAR. { rhs = kVoidPtr; } opt_signed ::= . opt_signed ::= SIGNED. @@ -108,7 +121,7 @@ opt_signed ::= SIGNED. opt_int ::= . opt_int ::= INT. - +%type opt_star { int } opt_star(rhs) ::= . { rhs = 0; } opt_star(rhs) ::= STAR. { rhs = 1; }