framework init

This commit is contained in:
zzy 2024-08-26 18:01:03 +08:00
commit 7b1e1ef1eb
8 changed files with 414 additions and 0 deletions

8
.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
.*
!.gitignore
*.o
*.out
*.obj
*.exe

5
Makefile Normal file
View File

@ -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

3
README.md Normal file
View File

@ -0,0 +1,3 @@
注意 由于使用c++的regex库所以需要编译时需要注意大于等于c++11语法
注意 这是一个多文件编译的项目需要你结合main.c和expr.cpp使用
注意 gen-expr里面需要命令行里编译c语言所以Windows需要自行配置以保证可以使用system命令编译以及popen的路径

17
common.h Normal file
View File

@ -0,0 +1,17 @@
// Modified by: Zhiyi Zhang in 2024.08
#ifndef __COMMON_H__
#define __COMMON_H__
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <inttypes.h>
#include "debug.h"
#define ARRLEN(arr) ((int)(sizeof(arr) / sizeof(arr[0])))
#endif

67
debug.h Normal file
View File

@ -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 <stdio.h>
#include <assert.h>
// ----------- 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

122
expr.cpp Normal file
View File

@ -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 <regex>
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;
}

75
gen-expr/gen-expr.c Normal file
View File

@ -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 <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
#include <string.h>
// this should be enough
static char buf[65536] = {};
static char code_buf[65536 + 128] = {}; // a little larger than `buf`
static char *code_format =
"#include <stdio.h>\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;
}

117
main.c Normal file
View File

@ -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;
}