mirror of
https://github.com/ksherlock/mpw.git
synced 2024-11-28 08:49:20 +00:00
template lecture and parser code
This commit is contained in:
parent
a111120033
commit
7691267dea
@ -31,6 +31,20 @@ add_custom_command(
|
|||||||
DEPENDS debugger.h
|
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(
|
add_custom_command(
|
||||||
OUTPUT loadtrap.cpp
|
OUTPUT loadtrap.cpp
|
||||||
COMMAND ragel -p -G2 -o loadtrap.cpp "${CMAKE_CURRENT_SOURCE_DIR}/loadtrap.rl"
|
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(
|
set_source_files_properties(
|
||||||
loadtrap.cpp lexer.cpp
|
loadtrap.cpp lexer.cpp template_loader.cpp
|
||||||
PROPERTIES
|
PROPERTIES
|
||||||
COMPILE_FLAGS
|
COMPILE_FLAGS
|
||||||
"${CMAKE_CXX_FLAGS} -Wno-unused-variable"
|
"${CMAKE_CXX_FLAGS} -Wno-unused-variable"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
add_executable(mpw loader.cpp debugger.cpp debugger_internal.cpp
|
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 CPU_LIB)
|
||||||
target_link_libraries(mpw TOOLBOX_LIB)
|
target_link_libraries(mpw TOOLBOX_LIB)
|
||||||
|
45
bin/template.h
Normal file
45
bin/template.h
Normal 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
288
bin/template_loader.rl
Normal 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
114
bin/template_parser.lemon
Normal 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; }
|
||||||
|
|
Loading…
Reference in New Issue
Block a user