diff --git a/.gitignore b/.gitignore index 420fc9cac1c759c93d4b43b8aac398ad9745ac24..671aff97a9468e38921c985ab6923ae76fd8799d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,13 @@ +*.yy.cc +*.tab.cc +*.tab.h + *.d *.o *.out +*.output + build + +.idea +.vscode diff --git a/nemu/Makefile b/nemu/Makefile index 45175226dcbbaac3b4305275bba3696f66ad74d3..6c8e56e0edc2fa4cda6a4a96107cb2a5e953d781 100644 --- a/nemu/Makefile +++ b/nemu/Makefile @@ -36,10 +36,14 @@ $(OBJ_DIR)/%.o: src/%.cc # Depencies -include $(OBJS:.o=.d) -# Some convinient rules +# Source code generation before any targets. +SUBDIRS = src/monitor/debug/expr_impl +$(SUBDIRS): + $(MAKE) -C $@ -.PHONY: app run clean -app: $(BINARY) +# Some convinient rules +.PHONY: app run clean $(SUBDIRS) +app: $(SUBDIRS) $(BINARY) override ARGS ?= -l $(BUILD_DIR)/nemu-log.txt override ARGS += -d $(NEMU_HOME)/tools/qemu-diff/build/qemu-so diff --git a/nemu/include/macro.h b/nemu/include/macro.h index 20263916dfc743cebb8878bd52c52034cd68f683..80a72ccff98918596cd8bc1a76a1f9e5b0187ac5 100644 --- a/nemu/include/macro.h +++ b/nemu/include/macro.h @@ -1,14 +1,8 @@ #ifndef __MACRO_H__ #define __MACRO_H__ -// From rlib/macro.hpp -#ifndef _RLIB_MACRO_ENSTRING -#define _RLIB_MACRO_ENSTRING(_s) #_s -#endif - -#ifndef RLIB_MACRO_TO_CSTR -#define RLIB_MACRO_TO_CSTR(m) _RLIB_MACRO_ENSTRING(m) -#endif +// Implements origin `str()` macro. Extremely bad naming. +#include <rlib/macro.hpp> #define concat_temp(x, y) x ## y #define concat(x, y) concat_temp(x, y) diff --git a/nemu/include/monitor/expr_impl/parser_interface.h b/nemu/include/monitor/expr_impl/parser_interface.h new file mode 100644 index 0000000000000000000000000000000000000000..f6610061692669b9382d3dca6dfc0b9d929a9010 --- /dev/null +++ b/nemu/include/monitor/expr_impl/parser_interface.h @@ -0,0 +1,10 @@ +#ifndef RCPP_HUST_PARSER_INTERFACE_H_ +#define RCPP_HUST_PARSER_INTERFACE_H_ 1 + +#include <string> +#include <cstdint> + +// Implemented in src/monitor/debug/expr_impl/parser.y +int64_t parse_one(std::string expr); + +#endif \ No newline at end of file diff --git a/nemu/src/monitor/debug/expr.cc b/nemu/src/monitor/debug/expr.cc index cc38022fac998c5256d9734e5f9f5a7edbc04095..4a09ceb6ac04315eba7dff07c79ed71bfa328c1c 100644 --- a/nemu/src/monitor/debug/expr.cc +++ b/nemu/src/monitor/debug/expr.cc @@ -6,6 +6,9 @@ #include <sys/types.h> #include <regex.h> +#include "monitor/expr_impl/parser_interface.h" +#include <rlib/stdio.hpp> + enum { TK_NOTYPE = 256, TK_EQ @@ -14,7 +17,7 @@ enum { }; static struct rule { - char *regex; + const char *regex; int token_type; } rules[] = { @@ -103,7 +106,14 @@ uint32_t expr(char *e, bool *success) { } /* TODO: Insert codes to evaluate the expression. */ - TODO(); - - return 0; + try { + auto res = parse_one(std::string(e)); + *success = true; + return res; + } + catch(std::exception &e) { + rlib::println("Exception caught:", e.what()); + *success = false; + return 0; + } } diff --git a/nemu/src/monitor/debug/expr_impl/Makefile b/nemu/src/monitor/debug/expr_impl/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..71d762fe7f670e8f9ecab9225d8063a154673144 --- /dev/null +++ b/nemu/src/monitor/debug/expr_impl/Makefile @@ -0,0 +1,17 @@ +generate: parser.tab.cc lexer.yy.cc parser.tab.h + +all: parser + +parser.tab.cc parser.tab.h: parser.y + @echo Generating $@... + bison --defines=parser.tab.h -o parser.tab.cc parser.y + +lexer.yy.cc: lexer.l parser.tab.h + @echo Generating $@... + flex -o lexer.yy.cc lexer.l + +parser: generate + g++ -o parser parser.tab.cc lexer.yy.cc + +clean: + rm -f parser parser.tab.cc lexer.yy.cc parser.tab.h diff --git a/nemu/src/monitor/debug/expr_impl/lexer.l b/nemu/src/monitor/debug/expr_impl/lexer.l new file mode 100644 index 0000000000000000000000000000000000000000..7da3a976745e2d8c9538133338f0256f497f38be --- /dev/null +++ b/nemu/src/monitor/debug/expr_impl/lexer.l @@ -0,0 +1,24 @@ +%option noyywrap + +%{ + +#define YY_DECL int yylex() + +#include "parser.tab.h" +#include <stdint.h> + +%} + +%% + +[ \t\n] {} +0x[0-9]+ {yylval.ival = (int)strtol(yytext, NULL, 16); return T_INT;} +[0-9]+ {yylval.ival = atoi(yytext); return T_INT;} +"==" {return T_EQUAL;} +"!=" {return T_NEQUAL;} +"&&" {return T_LOGICAL_AND;} +[-+*/()] {return yytext[0];} + +"%"[a-z]{3} {yylval.ival = ((uint32_t)yytext[1] << 8) + yytext[2]; return T_REG;} +%% +// Registers: eax='a'+'x', ebx='b'+'x', ... diff --git a/nemu/src/monitor/debug/expr_impl/parser.y b/nemu/src/monitor/debug/expr_impl/parser.y new file mode 100644 index 0000000000000000000000000000000000000000..f53b0b54dad00710e6edd0ce8cf32113455d6fea --- /dev/null +++ b/nemu/src/monitor/debug/expr_impl/parser.y @@ -0,0 +1,112 @@ +%{ + +#include <string> +#include <rlib/stdio.hpp> +#include <cassert> +#include <cstdlib> + +extern int yylex(); +extern int yyparse(); + +typedef struct yy_buffer_state * YY_BUFFER_STATE; +extern YY_BUFFER_STATE yy_scan_string(const char * str); +void yyerror(int64_t *result, std::string s); + +uint32_t ryy_read_cpu_reg_value(int64_t which_reg); +uint32_t ryy_read_memory_value(uint32_t addr); +%} + +%union { + int64_t ival; +} + +%token<ival> T_INT T_REG // I represent REG by: (int)(REG_NAME[1] << 8 + REG_NAME[2]) +%left T_LOGICAL_AND +%left T_EQUAL T_NEQUAL +%left '+' '-' +%left '*' '/' + +%type<ival> expr + +%start entry + +%parse-param {int64_t *result} + +%% +entry: {*result = 0;} + | expr {*result = $1;} +; + +expr: T_INT { $$ = $1; } + | expr '+' expr { $$ = $1 + $3; } + | expr '-' expr { $$ = $1 - $3; } + | expr '*' expr { $$ = $1 * $3; } + | expr '/' expr { $$ = $1 / $3; } + | expr T_EQUAL expr { $$ = ($1 == $3); } + | expr T_NEQUAL expr { $$ = ($1 != $3); } + | expr T_LOGICAL_AND expr { $$ = ($1 && $3); } + | '(' expr ')' { $$ = $2; } + | '-' expr { $$ = 0 - $2; } + | '*' expr { $$ = ryy_read_memory_value((uint32_t)$2); } + | T_REG { $$ = ryy_read_cpu_reg_value($1); } +; + +%% + +#include "monitor/expr_impl/parser_interface.h" + +int64_t parse_one(std::string expr) { + yy_scan_string(expr.c_str()); + int64_t result; + assert(0 == yyparse(&result)); + return result; +} + +int ryy_test_main() { + while(!std::cin.eof()) { + rlib::println(parse_one(rlib::scanln())); + } + return 0; +} + +void yyerror(int64_t *result, std::string msg) { + rlib::println("Parse error:", msg); + exit(1); +} + +// v-cpu related code: + +#include "cpu/reg.h" +#include "memory/memory.h" +#include <rlib/macro.hpp> + +uint32_t ryy_read_cpu_reg_value(int64_t which_reg) { +#define CODE_OF(reg) (((uint32_t)RLIB_MACRO_TO_CSTR(reg)[1] << 8) + RLIB_MACRO_TO_CSTR(reg)[2]) + switch(which_reg) { + case CODE_OF(eax): + return cpu.eax; + case CODE_OF(ebx): + return cpu.ebx; + case CODE_OF(ecx): + return cpu.ecx; + case CODE_OF(edx): + return cpu.edx; + case CODE_OF(esp): + return cpu.esp; + case CODE_OF(ebp): + return cpu.ebp; + case CODE_OF(esi): + return cpu.esi; + case CODE_OF(edi): + return cpu.edi; + case CODE_OF(eip): + return cpu.eip; + default: + throw std::invalid_argument("Invalid register name."); + } +#undef CODE_OF +} + +uint32_t ryy_read_memory_value(uint32_t addr) { + return vaddr_read(addr, 4); +}