Debugger Shell

This commit is contained in:
Kelvin Sherlock 2013-07-03 17:05:00 -04:00
parent a436e91373
commit dccdd7cb26
5 changed files with 536 additions and 0 deletions

View File

@ -12,3 +12,4 @@ add_subdirectory(toolbox)
add_subdirectory(mplite)
add_subdirectory(mpw)
add_subdirectory(macos)
add_subdirectory(debugger)

23
debugger/CMakeLists.txt Normal file
View File

@ -0,0 +1,23 @@
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(DEBUGGER_SRC lexer.cpp parser.c)
add_custom_command(
OUTPUT lexer.cpp
COMMAND re2c -b -i -o lexer.cpp "${CMAKE_CURRENT_SOURCE_DIR}/lexer.re.cpp"
MAIN_DEPENDENCY lexer.re.cpp
DEPENDS commands.h parser.h
)
add_custom_command(
OUTPUT parser.cpp parser.h
COMMAND cp "${CMAKE_CURRENT_SOURCE_DIR}/parser.lemon" "parser.lemon"
COMMAND lemon parser.lemon
COMMAND cp parser.h "${CMAKE_CURRENT_SOURCE_DIR}/"
COMMAND cp parser.out "${CMAKE_CURRENT_SOURCE_DIR}/"
MAIN_DEPENDENCY parser.lemon
DEPENDS commands.h
)
add_library(DEBUGGER_LIB ${DEBUGGER_SRC})

25
debugger/commands.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef __debugger_commands__
#define __debugger_commands__
enum {
Print,
Dump,
List,
Break,
TBreak,
Continue,
Step,
SetARegister,
SetDRegister,
SetXRegister,
};
struct Command {
bool valid;
int action;
uint32_t argc;
uint32_t argv[10];
};
#endif

324
debugger/lexer.re.cpp Normal file
View File

@ -0,0 +1,324 @@
#include <string>
#include <algorithm>
#include <numeric>
#include <cstdint>
#include <stdlib.h>
#include "commands.h"
#include "parser.h"
// re2c -b -i
extern "C" {
void *ParseAlloc(void *(*mallocProc)(size_t));
void ParseFree(void *p, void (*freeProc)(void*));
void Parse(void *yyp, int yymajor, uint32_t yyminor, Command *command);
}
// p / print expression
// hd / hexdump expression [:expression]
// stack ?
// brk expression
// tbrk expression
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,
[](char c, uint32_t value){
return value * 10 + c - '0';
});
}
uint32_t scan16(const char *begin, const char *end)
{
return std::accumulate(begin, end, 0,
[](char c, uint32_t value){
return (value << 4) + tox(c);
});
}
}
#if 0
/*
* unordered_set of breakpoints?
* bloom filter via std::bitset<16 * 1024> ?
*/
class AddressFilter {
std::bitset<4096> pageSet;
std::unordered_set<uint32_t> addSet;
bool test(uint32_t address) const
{
if (address > 0xffffff) return false;
if (!pageSet[address >> 12]) return false;
return addSet.find(address) != addSet.end();
}
void add(uint32_t address)
{
if (address > 0xffffff) return;
pageSet[address >> 12] = true;
addSet.insert(address);
}
void remove(uint32_t address)
{
if (address > 0xffffff) return;
auto iter = addSet.find(address);
if (iter != addSet.end())
{
addSet.remove();
// need to re-scan all addresses to update the pageSet...
uint32_t page = address >> 12;
pageSet[page] = false;
for (auto x : addSet)
{
if ((x >> 12) == page)
{
addSet[page] = true;
break;
}
}
}
}
};
#endif
bool ParseLine(const char *iter, Command *command)
{
void *parser;
parser = ParseAlloc(malloc);
for (;;)
{
const char *begin = iter;
const char *marker;
/*!re2c
re2c:define:YYCURSOR = iter;
re2c:define:YYMARKER = marker;
re2c:define:YYCTYPE = char;
re2c:yyfill:enable = 0;
[ \t\f\r\n]+ {
// white space
continue;
}
'>=' { Parse(&parser, tkGTEQ, 0, command); continue; }
'>>' { Parse(&parser, tkGTGT, 0, command); continue; }
'<=' { Parse(&parser, tkLTEQ, 0, command); continue; }
'<<' { Parse(&parser, tkLTLT, 0, command); continue; }
'!=' { Parse(&parser, tkBANGEQ, 0, command); continue; }
'==' { Parse(&parser, tkEQEQ, 0, command); continue; }
'||' { Parse(&parser, tkPIPEPIPE, 0, command); continue; }
'&&' { Parse(&parser, tkAMPAMP, 0, command); continue; }
'(' { Parse(&parser, tkLPAREN, 0, command); continue; }
')' { Parse(&parser, tkRPAREN, 0, command); continue; }
'=' { Parse(&parser, tkEQ, 0, command); continue; }
'+' { Parse(&parser, tkPLUS, 0, command); continue; }
'-' { Parse(&parser, tkMINUS, 0, command); continue; }
'*' { Parse(&parser, tkSTAR, 0, command); continue; }
'/' { Parse(&parser, tkSLASH, 0, command); continue; }
'%' { Parse(&parser, tkPERCENT, 0, command); continue; }
'~' { Parse(&parser, tkTILDE, 0, command); continue; }
'!' { Parse(&parser, tkBANG, 0, command); continue; }
'^' { Parse(&parser, tkCARET, 0, command); continue; }
'&' { Parse(&parser, tkAMP, 0, command); continue; }
'|' { Parse(&parser, tkPIPE, 0, command); continue; }
'<' { Parse(&parser, tkLT, 0, command); continue; }
'>' { Parse(&parser, tkGT, 0, command); continue; }
[0-9]+ {
// integer
uint32_t data;
data = std::accumulate(begin, iter, 0,
[](char c, uint32_t value){
return value * 10 + c - '0';
});
Parse(&parser, tkINTEGER, data, command);
continue;
}
'$' [0-9A-Fa-f]+ {
// hex number
uint32_t data;
data = std::accumulate(begin + 1, iter, 0,
[](char c, uint32_t value){
return (value << 4) + tox(c);
}
);
Parse(&parser, tkINTEGER, data, command);
continue;
}
'0x' [0-9A-Fa-f]+ {
// hex number
uint32_t data;
data = std::accumulate(begin + 2, iter, 0,
[](char c, uint32_t value){
return (value << 4) + tox(c);
}
);
Parse(&parser, tkINTEGER, data, command);
continue;
}
['] [^']{1,4} ['] {
// 4 cc code
uint32_t data;
data = std::accumulate(begin + 1, iter - 1, 0,
[](char c, uint32_t value)
{
return (value << 8) + (unsigned)c;
}
);
Parse(&parser, tkINTEGER, data, command);
continue;
}
'd' [0-7] {
// data register
uint32_t data = begin[1] - '0';
Parse(&parser, tkDREGISTER, data, command);
continue;
}
'a' [0-7] {
// address register
uint32_t data = begin[1] - '0';
Parse(&parser, tkAREGISTER, data, command);
continue;
}
'pc' {
// program counter...
Parse(&parser, tkXREGISTER, 0, command);
continue;
}
'csr' {
// condition status register.
Parse(&parser, tkXREGISTER, 1, command);
continue;
}
'sp' {
// stack pointer aka a7
Parse(&parser, tkAREGISTER, 7, command);
continue;
}
'fp' {
// frame pointer aka a6
Parse(&parser, tkAREGISTER, 6, command);
continue;
}
'c' | 'continue' {
Parse(&parser, tkCONTINUE, 0, command);
continue;
}
'hd' | 'dump' {
Parse(&parser, tkDUMP, 0, command);
continue;
}
'h' | 'help' {
Parse(&parser, tkHELP, 0, command);
continue;
}
'n' | 'next' {
Parse(&parser, tkSTEP, 0, command);
continue;
}
's' | 'step' {
Parse(&parser, tkSTEP, 0, command);
continue;
}
'b' | 'brk' | 'break' {
Parse(&parser, tkBREAK, 0, command);
continue;
}
'g' | 'go' {
Parse(&parser, tkGO, 0, command);
continue;
}
'r' | 'run' {
Parse(&parser, tkRUN, 0, command);
continue;
}
';l' | ';list' {
Parse(&parser, tkSEMIL, 0, command);
continue;
}
';h' | ';hd' | ';hexdump' {
Parse(&parser, tkSEMIH, 0, command);
continue;
}
[_A-Za-z][_A-Za-z0-9] + {
// identifier. lookup global address, tool number, etc.
fprintf(stderr, "illegal identifier: %*.s\n", (int)(iter - begin), begin);
return false;
}
[\x00] {
// eol.
Parse(&parser, tkEOL, 0, command);
break;
}
[^] {
fprintf(stderr, "illegal character: `%c`\n", *begin);
return false;
}
*/
}
Parse(&parser, 0, 0, command);
ParseFree(&parser, free);
return command->valid;
}

163
debugger/parser.lemon Normal file
View File

@ -0,0 +1,163 @@
%extra_argument { struct Command *command }
%token_prefix tk
%token_type {uint32_t}
%parse_failure {
fprintf(stderr,"I don't understand.\n");
command->valid = false;
}
%parse_accept {
command->valid = true;
}
%left PIPEPIPE.
%left AMPAMP.
%left PIPE.
%left CARET.
%left AMP.
%left EQEQ BANGEQ.
%left LT LTEQ GT GTEQ.
%left LTLT GTGT.
%left PLUS MINUS.
%left STAR SLASH PERCENT.
%right BANG TILDE.
stmt ::= assignment EOL.
stmt ::= expr(a) EOL.
{
// print the value.
// hex, base 10, signed 16-bit (if appropriate)
printf("$%08x - %u", a, a);
if (a & 0x80000000)
printf(" %d", (int32_t)a);
if ((a & 0xffff8000) == 0x8000)
printf(" %h", (int16_t)a);
printf("\n");
command->action = PRINT;
command->arg = a;
}
stmt ::= BREAK expr(a) EOL.
{
command->action = tkBREAK;
command->arg = a;
}
stmt ::= NEXT EOL.
{
command->action = tkNEXT;
command->arg = 1;
}
stmt ::= NEXT expr(a) EOL.
{
command->action = tkNEXT;
command->arg = a;
}
stmt ::= PRINT expr(a) EOL.
{
command->action = tkPRINT;
command->arg = a;
}
stmt ::= DUMP expr(a) EOL .
{
command->action = tkDUMP;
command->arg = a;
}
stmt ::= LIST expr(a) EOL .
{
command->action = tkLIST;
command->arg = a;
}
stmt ::= expr(a) SEMIL EOL.
{
command->action = tkLIST;
command->arg = a;
}
stmt ::= expr(a) SEMIH EOL.
{
command->action = tkDUMP;
command->arg = a;
}
assignment ::= DREGISTER(a) EQ expr(b). { cpuSetDReg(a, b); }
assignment ::= AREGISTER(a) EQ expr(b). { cpuSetAReg(a, b); }
assignment ::= XREGISTER(a) EQ expr(b).
{
switch(a)
{
case 0:
cpuSetPC(b);
break;
case 1:
cpuSetSR(b);
break;
}
}
expr(rhs) ::= unary(a). { rhs = a; }
expr(rhs) ::= term(a) PLUS term(b). { rhs = a + b; }
expr(rhs) ::= term(a) MINUS term(b). { rhs = a + b; }
expr(rhs) ::= term(a) STAR term(b). { rhs = a * b; }
expr(rhs) ::= term(a) SLASH term(b). { rhs = a / b; }
expr(rhs) ::= term(a) PERCENT term(b). { rhs = a % b; }
expr(rhs) ::= term(a) LTLT term(b). { rhs = a << b; }
expr(rhs) ::= term(a) GTGT term(b). { rhs = a >> b; }
expr(rhs) ::= term(a) LT term(b). { rhs = a < b; }
expr(rhs) ::= term(a) LTEQ term(b). { rhs = a <= b; }
expr(rhs) ::= term(a) GT term(b). { rhs = a > b; }
expr(rhs) ::= term(a) GTEQ term(b). { rhs = a >= b; }
expr(rhs) ::= term(a) EQEQ term(b). { rhs = a == b; }
expr(rhs) ::= term(a) BANGEQ term(b). { rhs = a != b; }
expr(rhs) ::= term(a) AMP term(b). { rhs = a & b; }
expr(rhs) ::= term(a) CARET term(b). { rhs = a ^ b; }
expr(rhs) ::= term(a) PIPE term(b). { rhs = a | b; }
expr(rhs) ::= term(a) AMPAMP term(b). { rhs = a && b; }
expr(rhs) ::= term(a) PIPEPIPE term(b). { rhs = a || b; }
unary(rhs) ::= term(a). { rhs = a; }
unary(rhs) ::= PLUS unary(a). [BANG] { rhs = a; }
unary(rhs) ::= MINUS unary(a). [BANG] { rhs = -a; }
unary(rhs) ::= TILDE unary(a). { rhs = ~a; }
unary(rhs) ::= BANG unary(a). { rhs = !a; }
unary(rhs) ::= STAR unary(a). [BANG] { rhs = cpuMemoryReadLong(a); }
term(rhs) ::= LPAREN expr(a) RPAREN. { rhs = a; }
term(rhs) ::= INTEGER(a). { rhs = a; }
term(rhs) ::= DREGISTER(a). { rhs = cpuGetDReg(a); }
term(rhs) ::= AREGISTER(a). { rhs = cpuGetAReg(a); }
term(rhs) ::= XREGISTER(a).
{
switch(a)
{
case 0:
rhs = cpuGetPC();
break;
case 1:
rhs = cpuGetSR();
break;
default:
rhs = 0;
}
}