From 7b1e1ef1eb55c330d31341392d1ccb4cc7752e7a Mon Sep 17 00:00:00 2001 From: zzy <2450266535@qq.com> Date: Mon, 26 Aug 2024 18:01:03 +0800 Subject: [PATCH] framework init --- .gitignore | 8 +++ Makefile | 5 ++ README.md | 3 ++ common.h | 17 ++++++ debug.h | 67 ++++++++++++++++++++++++ expr.cpp | 122 ++++++++++++++++++++++++++++++++++++++++++++ gen-expr/gen-expr.c | 75 +++++++++++++++++++++++++++ main.c | 117 ++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 414 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 README.md create mode 100644 common.h create mode 100644 debug.h create mode 100644 expr.cpp create mode 100644 gen-expr/gen-expr.c create mode 100644 main.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6a11570 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.* +!.gitignore + +*.o +*.out + +*.obj +*.exe \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a3a5001 --- /dev/null +++ b/Makefile @@ -0,0 +1,5 @@ +CXX = g++ +CXX_FLAG = -g -std=c++11 -Wall -Werror + +all: + $(CXX) $(CXX_FLAG) -o main.out main.c expr.cpp \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..2397a57 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +注意 由于使用c++的regex库,所以需要编译时需要注意大于等于c++11语法 +注意 这是一个多文件编译的项目,需要你结合main.c和expr.cpp使用 +注意 gen-expr里面需要命令行里编译c语言,所以Windows需要自行配置以保证可以使用system命令编译,以及popen的路径 \ No newline at end of file diff --git a/common.h b/common.h new file mode 100644 index 0000000..d908c13 --- /dev/null +++ b/common.h @@ -0,0 +1,17 @@ +// Modified by: Zhiyi Zhang in 2024.08 + +#ifndef __COMMON_H__ +#define __COMMON_H__ + +#include +#include +#include +#include +#include +#include +#include +#include "debug.h" + +#define ARRLEN(arr) ((int)(sizeof(arr) / sizeof(arr[0]))) + +#endif \ No newline at end of file diff --git a/debug.h b/debug.h new file mode 100644 index 0000000..9a8900e --- /dev/null +++ b/debug.h @@ -0,0 +1,67 @@ +/*************************************************************************************** +* Copyright (c) 2014-2022 Zihao Yu, Nanjing University +* +* NEMU is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* +* See the Mulan PSL v2 for more details. +***************************************************************************************/ +// Modified by: Zhiyi Zhang in 2024.08 + +#ifndef __DEBUG_H__ +#define __DEBUG_H__ + +#include +#include + +// ----------- log ----------- + +#define ANSI_FG_BLACK "\33[1;30m" +#define ANSI_FG_RED "\33[1;31m" +#define ANSI_FG_GREEN "\33[1;32m" +#define ANSI_FG_YELLOW "\33[1;33m" +#define ANSI_FG_BLUE "\33[1;34m" +#define ANSI_FG_MAGENTA "\33[1;35m" +#define ANSI_FG_CYAN "\33[1;36m" +#define ANSI_FG_WHITE "\33[1;37m" +#define ANSI_BG_BLACK "\33[1;40m" +#define ANSI_BG_RED "\33[1;41m" +#define ANSI_BG_GREEN "\33[1;42m" +#define ANSI_BG_YELLOW "\33[1;43m" +#define ANSI_BG_BLUE "\33[1;44m" +#define ANSI_BG_MAGENTA "\33[1;35m" +#define ANSI_BG_CYAN "\33[1;46m" +#define ANSI_BG_WHITE "\33[1;47m" +#define ANSI_NONE "\33[0m" + +#define ANSI_FMT(str, fmt) fmt str ANSI_NONE + +#define _Log(...) \ + do { \ + printf(__VA_ARGS__); \ + } while (0) + +#define Log(format, ...) \ + _Log(ANSI_FMT("[%s:%d %s] " format, ANSI_FG_BLUE) "\n", \ + __FILE__, __LINE__, __func__, ## __VA_ARGS__) + +#define Assert(cond, format, ...) \ + do { \ + if (!(cond)) { \ + fflush(stdout); \ + fprintf(stderr, ANSI_FMT(format, ANSI_FG_RED) "\n", ## __VA_ARGS__); \ + assert(cond); \ + } \ + } while (0) + +#define panic(format, ...) Assert(0, format, ## __VA_ARGS__) + +#define TODO() panic("please implement me") + +#endif diff --git a/expr.cpp b/expr.cpp new file mode 100644 index 0000000..07e595f --- /dev/null +++ b/expr.cpp @@ -0,0 +1,122 @@ +/*************************************************************************************** +* Copyright (c) 2014-2022 Zihao Yu, Nanjing University +* +* NEMU is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* +* See the Mulan PSL v2 for more details. +***************************************************************************************/ +// Modified by: Zhiyi Zhang in 2024.08 + +#include "common.h" +/* We use the POSIX regex functions to process regular expressions. + * Type 'man regex' for more information about POSIX regex functions. + */ +#include + +enum { + TK_NOTYPE = 256, TK_EQ, + + /* TODO: Add more token types */ + +}; + +static struct rule { + const char *regex; + int token_type; +} rules[] = { + + /* TODO: Add more rules. + * Pay attention to the precedence level of different rules. + */ + + {" +", TK_NOTYPE}, // spaces + {"\\+", '+'}, // plus + {"==", TK_EQ}, // equal +}; + +#define NR_REGEX ARRLEN(rules) + +static std::regex re[NR_REGEX] = {}; + +/* Rules are used for many times. + * Therefore we compile them only once before any usage. + */ +void init_regex() { + for (int i = 0; i < NR_REGEX; i ++) { + try { + re[i] = std::regex(rules[i].regex, std::regex_constants::ECMAScript); + } + catch(const std::regex_error & e) { + panic("regex compilation failed: %s\n%s", e.what(), rules[i].regex); + } + } +} + +typedef struct token { + int type; + char str[32]; +} Token; + +static Token tokens[32] __attribute__((used)) = {}; +static int nr_token __attribute__((used)) = 0; + +static bool make_token(char *e) { + int position = 0; + int i; + std::cmatch pmatch; + + nr_token = 0; + + while (e[position] != '\0') { + /* Try all rules one by one. */ + for (i = 0; i < NR_REGEX; i ++) { + // if (regexec(&re[i], e + position, 1, &pmatch, 0) == 0 && pmatch.rm_so == 0) { + if (std::regex_search(e + position, pmatch, re[i], std::regex_constants::match_continuous)) { + char *substr_start = e + position; + int substr_len = pmatch.length(); + + Log("match rules[%d] = \"%s\" at position %d with len %d: %.*s", + i, rules[i].regex, position, substr_len, substr_len, substr_start); + + position += substr_len; + + /* TODO: Now a new token is recognized with rules[i]. Add codes + * to record the token in the array `tokens'. For certain types + * of tokens, some extra actions should be performed. + */ + + switch (rules[i].token_type) { + default: TODO(); + } + + break; + } + } + + if (i == NR_REGEX) { + printf("no match at position %d\n%s\n%*.s^\n", position, e, position, ""); + return false; + } + } + + return true; +} + +uint32_t expr(char *e, bool *success) { + if (!make_token(e)) { + *success = false; + return 0; + } + + /* TODO: Insert codes to evaluate the expression. */ + TODO(); + + return 0; +} \ No newline at end of file diff --git a/gen-expr/gen-expr.c b/gen-expr/gen-expr.c new file mode 100644 index 0000000..5917576 --- /dev/null +++ b/gen-expr/gen-expr.c @@ -0,0 +1,75 @@ +/*************************************************************************************** +* Copyright (c) 2014-2022 Zihao Yu, Nanjing University +* +* NEMU is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* +* See the Mulan PSL v2 for more details. +***************************************************************************************/ +// Modified by: Zhiyi Zhang in 2024.08 + +#define TMP_FILE_PATH "/tmp" +#define TMP_C_SRC_FILE_PATH TMP_FILE_PATH "/.code.c" +#define TMP_C_EXE_FILE_PATH TMP_FILE_PATH "/.expr" +#define TMP_COMPILE_CMD "gcc -o " TMP_C_EXE_FILE_PATH " " TMP_C_SRC_FILE_PATH + +#include +#include +#include +#include +#include +#include + +// this should be enough +static char buf[65536] = {}; +static char code_buf[65536 + 128] = {}; // a little larger than `buf` +static char *code_format = +"#include \n" +"int main() { " +" unsigned result = %s; " +" printf(\"%%u\", result); " +" return 0; " +"}"; + +static void gen_rand_expr() { + buf[0] = '\0'; +} + +int main(int argc, char *argv[]) { + int seed = time(0); + srand(seed); + int loop = 1; + if (argc > 1) { + sscanf(argv[1], "%d", &loop); + } + int i; + for (i = 0; i < loop; i ++) { + gen_rand_expr(); + + sprintf(code_buf, code_format, buf); + + FILE *fp = fopen(TMP_C_SRC_FILE_PATH, "w"); + assert(fp != NULL); + fputs(code_buf, fp); + fclose(fp); + + int ret = system(TMP_COMPILE_CMD); + if (ret != 0) continue; + + fp = popen("." TMP_C_EXE_FILE_PATH, "r"); + assert(fp != NULL); + + int result; + ret = fscanf(fp, "%d", &result); + pclose(fp); + + printf("%u %s\n", result, buf); + } + return 0; +} \ No newline at end of file diff --git a/main.c b/main.c new file mode 100644 index 0000000..5414848 --- /dev/null +++ b/main.c @@ -0,0 +1,117 @@ +/*************************************************************************************** +* Copyright (c) 2014-2022 Zihao Yu, Nanjing University +* +* NEMU is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* +* See the Mulan PSL v2 for more details. +***************************************************************************************/ +// Modified by: Zhiyi Zhang in 2024.08 + +#include "common.h" + +void init_regex(void); +uint32_t expr(char *e, bool *success); + +static int cmd_q(char *args) { + return -1; +} + +static int cmd_help(char *args); + +static int cmd_p(char *args) { + bool success = true; + uint32_t res = expr(args, &success); + if (success) { + printf("$res = % " PRIdLEAST32 "\n", res); + } + return success; +} + +static struct { + const char *name; + const char *description; + int (*handler) (char *); +} cmd_table [] = { + { "help", "Display information about all supported commands", cmd_help }, + { "p", "p EXPR: To evaluate an expression EXPR and output the result", cmd_p }, + { "q", "Exit NEMU", cmd_q }, + + /* TODO: Add more commands */ + +}; + +#define NR_CMD ARRLEN(cmd_table) + +static void print_help() { + for (int i = 0; i < NR_CMD; i ++) { + printf("%s - %s\n", cmd_table[i].name, cmd_table[i].description); + } +} + +static int cmd_help(char *args) { + /* extract the first argument */ + char *arg = strtok(NULL, " "); + int i; + + if (arg == NULL) { + /* no argument given */ + print_help(); + } + else { + for (i = 0; i < NR_CMD; i ++) { + if (strcmp(arg, cmd_table[i].name) == 0) { + printf("%s - %s\n", cmd_table[i].name, cmd_table[i].description); + return 0; + } + } + printf("Unknown command '%s'\n", arg); + } + return 0; +} + + +int main(int argc, char **argv) { + static char str[1024] = { 0 }; + init_regex(); + print_help(); + bool running = true; + + while (running) { + if (!fgets(str, 1024, stdin)) { + continue; + } + str[strlen(str) - 1] = '\0'; + char *str_end = str + strlen(str); + + /* extract the first token as the command */ + char *cmd = strtok(str, " "); + if (cmd == NULL) { continue; } + + /* treat the remaining string as the arguments, + * which may need further parsing + */ + char *args = cmd + strlen(cmd) + 1; + if (args >= str_end) { + args = NULL; + } + + int i; + for (i = 0; i < NR_CMD; i ++) { + if (strcmp(cmd, cmd_table[i].name) == 0) { + if (cmd_table[i].handler(args) < 0) { return -1; } + break; + } + } + + if (i == NR_CMD) { printf("Unknown command '%s'\n", cmd); } + + } + return 0; +} \ No newline at end of file