template lecture and parser code

This commit is contained in:
Kelvin Sherlock 2014-12-29 00:12:47 -05:00
parent a111120033
commit 7691267dea
4 changed files with 477 additions and 7 deletions

View File

@ -31,6 +31,20 @@ add_custom_command(
DEPENDS debugger.h
)
add_custom_command(
OUTPUT template_parser.cpp template_parser.h
COMMAND cp -f "${CMAKE_CURRENT_SOURCE_DIR}/template_parser.lemon" "template_parser.lemon"
COMMAND lemon template_parser.lemon
COMMAND cp -f template_parser.h "${CMAKE_CURRENT_SOURCE_DIR}/"
COMMAND cp -f template_parser.out "${CMAKE_CURRENT_SOURCE_DIR}/"
COMMAND mv -f template_parser.c template_parser.cpp
MAIN_DEPENDENCY template_parser.lemon
DEPENDS debugger.h
)
add_custom_command(
OUTPUT loadtrap.cpp
COMMAND ragel -p -G2 -o loadtrap.cpp "${CMAKE_CURRENT_SOURCE_DIR}/loadtrap.rl"
@ -39,16 +53,25 @@ add_custom_command(
)
add_custom_command(
OUTPUT template_loader.cpp
COMMAND ragel -p -G2 -o template_loader.cpp "${CMAKE_CURRENT_SOURCE_DIR}/template_loader.rl"
MAIN_DEPENDENCY template_loader.rl
DEPENDS debugger.h template_parser.h
)
set_source_files_properties(
loadtrap.cpp lexer.cpp
loadtrap.cpp lexer.cpp template_loader.cpp
PROPERTIES
COMPILE_FLAGS
"${CMAKE_CXX_FLAGS} -Wno-unused-variable"
)
add_executable(mpw loader.cpp debugger.cpp debugger_internal.cpp
address_map.cpp lexer.cpp parser.cpp loadtrap.cpp commands.cpp)
address_map.cpp lexer.cpp parser.cpp loadtrap.cpp
commands.cpp
template_loader.cpp template_parser.cpp)
target_link_libraries(mpw CPU_LIB)
target_link_libraries(mpw TOOLBOX_LIB)

45
bin/template.h Normal file
View File

@ -0,0 +1,45 @@
#ifndef __debug_template_h__
#define __debug_template_h__
#include <unordered_map>
namespace Debug {
enum {
kUnknown = 0,
kStringPtr, // p-string
kCStringPtr, // c-string
kPtr,
kOSType, // four-cc
kBoolean, // unsigned char, display true/false
};
struct Template;
struct FieldEntry;
struct FieldEntry {
std::string *name;
unsigned type;
unsigned count;
Template *tmpl;
FieldEntry *next;
};
struct Template {
unsigned type; // 0 for structs, < 256 for types.
FieldEntry *firstField;
unsigned size;
};
void CreateTypedef(const std::string *name, int type);
void CreateTemplate(const std::string *name, FieldEntry *firstField);
extern std::unordered_map<std::string, Template *> Templates;
extern int TemplateLine;
}
#endif

288
bin/template_loader.rl Normal file
View File

@ -0,0 +1,288 @@
#include <string>
#include <unordered_map>
#include <algorithm>
#include <numeric>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include "template_parser.h"
#include "template.h"
namespace {
int tox(char c)
{
c |= 0x20; // lowercase it.
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
return 0;
}
uint32_t scan10(const char *begin, const char *end)
{
return std::accumulate(begin, end, 0,
[](uint32_t value, char c){
return value * 10 + c - '0';
});
}
uint32_t scan16(const char *begin, const char *end)
{
return std::accumulate(begin, end, 0,
[](uint32_t value, char c){
return (value << 4) + tox(c);
});
}
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<unsigned, std::string *> 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)
{
TemplateParse(yyp, yymajor, &yyminor);
}
void TemplateParse(void *yyp, int yymajor, const std::string *yyminor)
{
TemplateParse(yyp, yymajor, (void *)yyminor);
}
%%{
machine lexer;
# this exits with cs == lexer_en_error.
error := any* ${ fbreak; };
block_comment := |*
[\n\r] { TemplateLine++; };
'*/' { fgoto main; };
any ;
*|;
main := |*
[\n\r] { TemplateLine++; };
[ \t]+;
'//' [^\r\n]* ;
'/*' { fgoto block_comment; };
';' { TemplateParse(parser, tkSEMI, 0); };
'{' { TemplateParse(parser, tkLBRACE, 0); };
'}' { TemplateParse(parser, tkRBRACE, 0); };
'[' { TemplateParse(parser, tkLBRACKET, 0); };
']' { TemplateParse(parser, tkRBRACKET, 0); };
'*' { TemplateParse(parser, tkSTAR, 0); };
'struct' { TemplateParse(parser, tkSTRUCT, 0); };
'typedef' { TemplateParse(parser, tkTYPEDEF, 0); };
'int' { TemplateParse(parser, tkINT, 0); };
'long' { TemplateParse(parser, tkLONG, 0); };
'short' { TemplateParse(parser, tkSHORT, 0); };
'volatile' { TemplateParse(parser, tkVOLATILE, 0); };
#'const' { TemplateParse(parser, tkCONST, 0); };
'char' { TemplateParse(parser, tkCHAR, 0); };
#'bool' { TemplateParse(parser, tkBOOL, 0); };
'void' { TemplateParse(parser, tkVOID, 0); };
'signed' { TemplateParse(parser, tkSIGNED, 0); };
'unsigned' { TemplateParse(parser, tkUNSIGNED, 0); };
'int64_t' { TemplateParse(parser, tkTYPECODE, 'q'); };
'uint64_t' { TemplateParse(parser, tkTYPECODE, 'Q'); };
'int32_t' { TemplateParse(parser, tkTYPECODE, 'l'); };
'uint32_t' { TemplateParse(parser, tkTYPECODE, 'L'); };
'int16_t' { TemplateParse(parser, tkTYPECODE, 's'); };
'uint16_t' { TemplateParse(parser, tkTYPECODE, 'S'); };
'int8_t' { TemplateParse(parser, tkTYPECODE, 'c'); };
'uint8_t' { TemplateParse(parser, tkTYPECODE, 'C'); };
'StringPtr' { TemplateParse(parser, tkTYPECODE, kStringPtr); };
'CStringPtr' { TemplateParse(parser, tkTYPECODE, kCStringPtr); };
'Ptr' { TemplateParse(parser, tkTYPECODE, kPtr); };
'OSType' { TemplateParse(parser, tkTYPECODE, kOSType); };
'Boolean' { TemplateParse(parser, tkTYPECODE, kBoolean); };
# numbers. negative numbers are not allowed.
'0x'i xdigit+ {
// hexadecimal
uint32_t value = scan16(ts + 2, te);
TemplateParse(parser, tkINTEGER, value);
};
digit+ {
uint32_t value = scan10(ts, te);
TemplateParse(parser, tkINTEGER, value);
};
# identifier ... but also need to check if it's a type.
[A-Za-z_][A-Za-z0-9_]+ {
// intern the string.
const std::string *name = InternString(ts, te);
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);
}
else
{
TemplateParse(parser, tkIDENTIFIER, name);
}
};
*|;
}%%
namespace Debug {
std::unordered_map<std::string, Template *> Templates;
void CreateTypedef(const std::string *name, int type)
{
}
void CreateTemplate(const std::string *name, FieldEntry *firstField)
{
}
int TemplateLine;
bool ParseTemplates(const std::string &filename)
{
%% write data;
void *parser;
int fd;
struct stat st;
char *buffer;
if (stat(filename.c_str(), &st) < 0) return false;
if (st.st_size == 0) return false;
fd = open(filename.c_str(), O_RDONLY);
if (fd < 0) {
perror("Error opening template file: ");
return false;
}
buffer = (char *)mmap(nullptr, st.st_size, PROT_READ, MAP_FILE | MAP_SHARED, fd, 0);
if (buffer == MAP_FAILED) {
perror("Error mapping template file: ");
close(fd);
return false;
}
close(fd);
parser = TemplateParseAlloc(malloc);
TemplateLine = 1;
const char *p = buffer;
const char *pe = buffer + st.st_size;
const char *eof = pe;
const char *ts;
const char *te;
int cs, act;
for(;;)
{
%% write init;
%% write exec;
if (cs == lexer_error)
{
fprintf(stderr, "illegal character: `%c'\n", *p);
TemplateParseFree(parser, free);
munmap(buffer, st.st_size);
return false;
}
if (cs == lexer_en_error)
{
TemplateParseFree(parser, free);
munmap(buffer, st.st_size);
return false;
}
if (p == pe)
{
TemplateParse(parser, tkEOF, 0);
break;
}
}
TemplateParse(parser, 0, 0);
TemplateParseFree(parser, free);
munmap(buffer, st.st_size);
return true;
}
}

114
bin/template_parser.lemon Normal file
View File

@ -0,0 +1,114 @@
%token_prefix tk
%name TemplateParse
%include {
#include <string>
#include <stdlib.h>
#include "template.h"
using namespace Debug;
}
%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.
templates ::= templates struct.
templates ::= templates typedef.
templates ::= .
typedef ::= TYPEDEF type(a) IDENTIFIER(b). {
CreateTypedef((std::string *)b, a);
}
struct ::= STRUCT IDENTIFIER(a) LBRACE struct_fields(b) RBRACE SEMI.
{
CreateTemplate((std::string *)a, b);
}
struct_fields(rhs) ::= struct_fields(a) struct_field(b). {
// reverse order?
b->next = a;
rhs = b;
}
struct_fields(rhs) ::= struct_field(a). {
rhs = a;
}
struct_field(rhs) ::= type(a) IDENTIFIER(b) array_count(c) SEMI.
{
FieldEntry *e = (FieldEntry *)calloc(sizeof(FieldEntry), 1);
e->name = (std::string *)b;
e->type = a;
e->count = c;
rhs = e;
}
struct_field(rhs) ::= opt_volatile TEMPLATE(a) opt_star(star) IDENTIFIER(b) array_count(c) SEMI. {
FieldEntry *e = (FieldEntry *)calloc(sizeof(FieldEntry), 1);
e->name = (std::string *)b;
e->type = star ? kPtr : 0;
e->tmpl = (Template *)a;
e->count = c;
rhs = e;
}
array_count(rhs) ::= . { rhs = -1; }
array_count(rhs) ::= LBRACKET INTEGER(a) RBRACKET. { rhs = *(int *)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());
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'; }
typecode(rhs) ::= opt_signed SHORT. { rhs = 's'; }
typecode(rhs) ::= UNSIGNED SHORT. { rhs = 'S'; }
typecode(rhs) ::= opt_signed LONG opt_int. { rhs = 'l'; }
typecode(rhs) ::= UNSIGNED LONG opt_int. { rhs = 'L'; }
typecode(rhs) ::= opt_signed LONG LONG. { rhs = 'q'; }
typecode(rhs) ::= UNSIGNED LONG LONG. { rhs = 'Q'; }
typecode(rhs) ::= TYPECODE(a). { rhs = *(int *)a; }
/* pointers are not fully supported yet */
typecode(rhs) ::= VOID STAR. { rhs = kPtr; }
opt_signed ::= .
opt_signed ::= SIGNED.
opt_int ::= .
opt_int ::= INT.
opt_star(rhs) ::= . { rhs = 0; }
opt_star(rhs) ::= STAR. { rhs = 1; }