浏览代码

feat: 字节码文件添加HEAD信息

SongZihuan 3 年之前
父节点
当前提交
40bd8e32c3
共有 12 个文件被更改,包括 212 次插入52 次删除
  1. 6 3
      CMakeLists.txt
  2. 1 0
      include/core/aFunCore.h
  3. 10 0
      include/core/bytecode.h
  4. 5 5
      include/core/code.h
  5. 5 0
      include/tool/md5.h
  6. 114 0
      src/core/bytecode.c
  7. 35 15
      src/core/code.c
  8. 25 15
      src/runtime/aFunlang.c
  9. 9 12
      src/tool/md5.c
  10. 二进制
      test/af/test1.aub
  11. 二进制
      test/af/test2.aub
  12. 2 2
      test/src/byte_code.c

+ 6 - 3
CMakeLists.txt

@@ -52,10 +52,13 @@ set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
 set(CMAKE_MACOSX_RPATH TRUE)
 include_directories(${CMAKE_SOURCE_DIR}/include ${CMAKE_BINARY_DIR}/${INSTALL_INCLUDEDIR})  # 添加默认的include路径
 set(base_compile_definitions
-    aFunVersion="${aFunVersion}"
-    aFunDescription="${aFunDescription}"
+    aFunVersion="${PROJECT_VERSION}"
+    aFunDescription="${PROJECT_DESCRIPTION}"
     systemName="${CMAKE_SYSTEM_NAME}"
-    compilerID="${CMAKE_C_COMPILER_ID}")  # 默认的预定义宏
+    compilerID="${CMAKE_C_COMPILER_ID}"
+    aFunMajorVersion=${PROJECT_VERSION_MAJOR}
+    aFunMinorVersion=${PROJECT_VERSION_MINOR}
+    aFunPatchVersion=${PROJECT_VERSION_PATCH})  # 默认的预定义宏
 add_compile_definitions(${base_compile_definitions})
 
 include(${CMAKE_CURRENT_LIST_DIR}/deps/deps.cmake)  # 安装依赖

+ 1 - 0
include/core/aFunCore.h

@@ -13,6 +13,7 @@
 #include "core_init.h"
 #include "run.h"
 #include "code.h"
+#include "bytecode.h"
 #include "env.h"
 #include "gc.h"
 #include "func.h"

+ 10 - 0
include/core/bytecode.h

@@ -0,0 +1,10 @@
+#ifndef AFUN_BYTECODE_H
+#define AFUN_BYTECODE_H
+
+AFUN_CORE_EXPORT extern char const * const writeByteCodeError[5];
+AFUN_CORE_EXPORT extern char const * const readByteCodeError[7];
+
+AFUN_CORE_EXPORT int readByteCode(af_Code **code, FilePath path);
+AFUN_CORE_EXPORT int writeByteCode(af_Code *code, FilePath path);
+
+#endif //AFUN_BYTECODE_H

+ 5 - 5
include/core/code.h

@@ -10,8 +10,8 @@ typedef uint32_t CodeUInt;  // Code int
 typedef int64_t LayerInt;  // 只有当layer会小于0时使用
 
 enum af_CodeType {
-    code_element = 0,
-    code_block,  // 括号
+    code_element = 'e',
+    code_block = 'm',  // 括号
 };
 
 /* 括号类型 */
@@ -31,8 +31,8 @@ AFUN_CORE_EXPORT void freeAllCode(af_Code *bt);
 AFUN_CORE_EXPORT af_Code *pushCode(af_Code **base, af_Code *next);
 AFUN_CORE_EXPORT af_Code *copyAllCode(af_Code *base, FilePath *path);
 AFUN_CORE_EXPORT af_Code *copyCode(af_Code *base, FilePath *path);
-AFUN_CORE_EXPORT bool writeAllCode(af_Code *bt, FilePath path);
-AFUN_CORE_EXPORT bool readAllCode(af_Code **bt, FilePath path);
+AFUN_CORE_EXPORT bool writeAllCode(af_Code *bt, FILE *file);
+AFUN_CORE_EXPORT bool readAllCode(af_Code **bt, FilePath path, FILE *file);
 
 /* 代码块 属性访问 */
 AFUN_CORE_EXPORT af_Code *getCodeNext(af_Code *bt);
@@ -44,5 +44,5 @@ AFUN_CORE_EXPORT char getCodePrefix(af_Code *code);
 AFUN_CORE_EXPORT CodeUInt getCodeEndCount(af_Code *code);
 AFUN_CORE_EXPORT char *getCodeElementData(af_Code *code);
 AFUN_CORE_EXPORT CodeUInt getCodeElementCount(af_Code *code);
-
+AFUN_CORE_EXPORT char *getCodeMD5(af_Code *code);
 #endif //AFUN_BYTECODE

+ 5 - 0
include/tool/md5.h

@@ -8,6 +8,11 @@
 #define MD5_STR_LEN (MD5_SIZE * 2)  // md5str的长度
 #define MD5_STRING (MD5_STR_LEN + 1)
 
+typedef struct MD5_CTX MD5_CTX;
+
+AFUN_TOOL_EXPORT MD5_CTX *MD5Init(void);
+AFUN_TOOL_EXPORT void MD5Final(MD5_CTX *context, unsigned char digest[16]);
+AFUN_TOOL_EXPORT void MD5Update(MD5_CTX *context, unsigned char *input, unsigned int input_len);
 AFUN_TOOL_EXPORT char *getFileMd5(const char *path);
 
 #endif //AFUN_MD5_H

+ 114 - 0
src/core/bytecode.c

@@ -0,0 +1,114 @@
+#include "aFunCore.h"
+#include "tool.h"
+
+#define HEAD "aFun-BytecodeFile"
+#define Done(write) do{if(!(write)){re = 0; goto RETURN_;}}while(0)
+
+/* aFun在一般情况下, 主版本号向下兼容 */
+static bool checkVersion(uint32_t major, uint32_t minor, uint32_t patch) {
+    if (major <= aFunMajorVersion)
+        return true;
+    return false;
+}
+
+char const * const writeByteCodeError[5] = {
+        "File write error.",  // 0
+        NULL,  // 无错误
+        "File open error.",  // 2
+        "Code md5 error.",  // 3
+        "Write code error."  // 4
+};
+
+char const * const readByteCodeError[7] = {
+        "File write error.",  // 0
+        NULL,  // 无错误
+        "File open error.",  // 2
+        "The file is not an aFun Bytecode file.",  // 3
+        "Incompatible version.",  // 4
+        "Read code error.",  // 5
+        "Code is broken."  // 6
+};
+
+int writeByteCode(af_Code *code, FilePath path) {
+    if (code == NULL || path == NULL)
+        return 0;
+
+    char *md5 = getCodeMD5(code);
+    if (md5 == NULL)
+        return 3;
+
+    int re = 1;
+    FILE *file = fopen(path, "wb");
+    if (file == NULL) {
+        re = 2;
+        goto RETURN_;
+    }
+
+    Done(byteWriteStr(file, HEAD));
+    Done(byteWriteUint_32(file, aFunMajorVersion));
+    Done(byteWriteUint_32(file, aFunMinorVersion));
+    Done(byteWriteUint_32(file, aFunPatchVersion));
+    Done(byteWriteStr(file, md5));
+    if (!writeAllCode(code, file)) {
+        re = 4;
+        goto RETURN_;
+    }
+
+
+RETURN_:
+    free(md5);
+    return re;
+}
+
+int readByteCode(af_Code **code, FilePath path) {
+    if (code == NULL || path == NULL || *code != NULL)
+        return 0;
+
+    int re = 1;
+    FILE *file = fopen(path, "rb");
+    if (file == NULL)
+        return 2;
+
+    char *head = NULL;
+    uint32_t major = 0;
+    uint32_t minor = 0;
+    uint32_t patch = 0;
+    char *md5str = NULL;
+    char *code_md5 = NULL;
+
+    Done(byteReadStr(file, &head));
+    if (!EQ_STR(head, HEAD)) {
+        re = 3;
+        goto RETURN_;
+    }
+
+    Done(byteReadUint_32(file, &major));
+    Done(byteReadUint_32(file, &minor));
+    Done(byteReadUint_32(file, &patch));
+    Done(byteReadStr(file, &md5str));
+
+    if (!checkVersion(major, minor, patch)) {
+        re = 4;
+        goto RETURN_;
+    }
+
+    if (!readAllCode(code, path, file)) {
+        re = 5;
+        freeAllCode(*code);
+        goto RETURN_;
+    }
+
+    code_md5 = getCodeMD5(*code);
+    if (code_md5 == NULL || !EQ_STR(code_md5, md5str)) {
+        re = 6;
+        freeAllCode(*code);
+        goto RETURN_;
+    }
+
+RETURN_:
+    free(head);
+    free(md5str);
+    free(code_md5);
+    fclose(file);
+    return re;
+}

+ 35 - 15
src/core/code.c

@@ -265,14 +265,10 @@ static bool writeCode(af_Code *bt, FILE *file) {
  * 目标: 将Code写入字节码文件中
  * 备注: 写入字节码时不做语义检查, 在读取时最语义检查即可
  */
-bool writeAllCode(af_Code *bt, FilePath path) {
+bool writeAllCode(af_Code *bt, FILE *file) {
     if (bt == NULL || bt->path == NULL)
         return false;
 
-    FILE *file = fopen(path, "wb");
-    if (file == NULL)
-        return false;
-
     for (NULL; bt != NULL; bt = bt->next) {
         if (!writeCode(bt, file))
             goto RETURN_FALSE;
@@ -282,11 +278,9 @@ bool writeAllCode(af_Code *bt, FilePath path) {
         Done(byteWriteUint_8(file, (bt->next == NULL)));  // 记录是否为最后一位
     }
 
-    fclose(file);
     return true;
 
 RETURN_FALSE:
-    fclose(file);
     return false;
 }
 
@@ -324,14 +318,10 @@ static bool readCode(af_Code **bt, FILE *file) {
     return true;
 }
 
-bool readAllCode(af_Code **bt, FilePath path) {
+bool readAllCode(af_Code **bt, FilePath path, FILE *file) {
     af_Code **base = bt;
     *bt = NULL;
 
-    FILE *file = fopen(path, "rb");
-    if (file == NULL)
-        return false;
-
     for (NULL; true;bt = &((*bt)->next)) {
         if(!readCode(bt, file))
             goto RETURN_FALSE;
@@ -346,11 +336,9 @@ bool readAllCode(af_Code **bt, FilePath path) {
 
     if (*base != NULL)
         (*base)->path = strCopy(path);
-    fclose(file);
     return true;
 
 RETURN_FALSE:
-    fclose(file);
     return false;
 }
 
@@ -525,4 +513,36 @@ CodeUInt getCodeElementCount(af_Code *code) {
     if (countElement(code->next, &count, NULL) == 0)
         return 0;
     return count;
-}
+}
+
+char *getCodeMD5(af_Code *code) {
+    char *md5str = calloc(MD5_STR_LEN + 1, sizeof(char));
+    char md5_value[MD5_SIZE];
+    MD5_CTX *md5 = MD5Init();
+
+    for (NULL; code != NULL; code = code->next) {
+        char *tmp = NULL;
+        char head[] = {code->type, code->prefix, 'x', 'x', NUL};
+        char tail[512] = {0};
+
+        if (code->prefix == NUL)
+            head[1] = '-';
+        if (code->type == code_block) {
+            head[2] = code->block.is_empty ? 'e' : 'n';
+            head[3] = code->block.type;
+        } else
+            tmp = strCopy(code->element.data);
+        snprintf(tail, 512, "%d:%d", code->code_end, code->line);
+        tmp = strJoin(head, tmp, false, true);
+        tmp = strJoin(tmp, tail, true, false);
+
+        MD5Update(md5, (unsigned char *)tmp, strlen((char *)tmp));
+        free(tmp);
+    }
+
+    MD5Final(md5, (unsigned char *)md5_value);
+
+    for(int i = 0; i < MD5_SIZE; i++)
+        snprintf((char *)md5str + i * 2, 2 + 1, "%02x", md5_value[i]);
+    return md5str;
+}

+ 25 - 15
src/runtime/aFunlang.c

@@ -2,7 +2,8 @@
 #include "aFunCore.h"
 #include "__env.h"
 
-static int runCode_(FilePath name, af_Parser *parser, int mode, FilePath save_path, af_Environment *env);
+static int
+runCode_(FilePath name, af_Parser *parser, int mode, FilePath save_path, FILE *error_file, af_Environment *env);
 
 void aFunInit() {
     aFunCoreInit();
@@ -10,7 +11,7 @@ void aFunInit() {
 
 af_Environment *creatAFunEnviroment(void) {
     af_Environment *env = makeEnvironment(grt_count);
-    af_Code *code;
+    af_Code *code = NULL;
 
     runtimeTool("base", &code, NULL, env->core->protect, env);
 
@@ -31,7 +32,7 @@ void destructAFunEnvironment(af_Environment *env) {
     freeEnvironment(env);
 }
 
-static int runCode_(FilePath name, af_Parser *parser, int mode, FilePath save_path, af_Environment *env){
+static int runCode_(FilePath name, af_Parser *parser, int mode, FilePath save_path, FILE *error_file, af_Environment *env){
     if (parser == NULL)
         return -1;
 
@@ -41,8 +42,11 @@ static int runCode_(FilePath name, af_Parser *parser, int mode, FilePath save_pa
         return -2;
 
     /* 写入文件 */
-    if (save_path != NULL)
-        writeAllCode(bt_code, save_path);
+    if (save_path != NULL) {
+        int res = writeByteCode(bt_code, save_path);
+        if (res != 1)
+            fprintf(error_file, "Save aFun Bytecode file error [%s] [save at %s].\n", writeByteCodeError[res], save_path);
+    }
 
     bool res = iterCode(bt_code, mode, env);
     freeAllCode(bt_code);
@@ -66,7 +70,7 @@ int runCodeFromString(char *code, char *string_name, FILE *error_file, af_Enviro
     if (error_file == NULL)
         error_file = stderr;
     af_Parser *parser = makeParserByString(code, false, error_file);
-    return runCode_(string_name, parser, 1, NULL, env);
+    return runCode_(string_name, parser, 1, NULL, error_file, env);
 }
 
 /*
@@ -96,7 +100,7 @@ int runCodeFromFileSource(FilePath file, FILE *error_file, bool save_afb, FilePa
         save_path = NULL;
 
     af_Parser *parser = makeParserByFile(file, error_file);
-    int exit_code = runCode_(file, parser, 1, save_path, env);
+    int exit_code = runCode_(file, parser, 1, save_path, error_file, env);
     if (free_save_path)
         free(save_path);
     return exit_code;
@@ -116,7 +120,7 @@ int runCodeFromStdin(char *name, FILE *error_file, af_Environment *env) {
     if (error_file == NULL)
         error_file = stderr;
     af_Parser *parser = makeParserByStdin(error_file);
-    return runCode_(name, parser, 0, NULL, env);
+    return runCode_(name, parser, 0, NULL, error_file, env);
 }
 
 /*
@@ -158,8 +162,10 @@ int runCodeFromFileByte(FilePath file, FILE *error_file, af_Environment *env) {
         return -2;
     }
 
-    af_Code *code;
-    if(!readAllCode(&code, file)) {
+    af_Code *code = NULL;
+    int res = readByteCode(&code, file);
+    if(res != 1) {
+        fprintf(error_file, "Load bytecode file error [%s] [Load at %s].\n", readByteCodeError[res], file);
         freeAllCode(code);
         return -2;
     }
@@ -201,10 +207,14 @@ int runCodeFromFile(FilePath file, FILE *error_file, bool save_afb, af_Environme
     }
 
     int exit_code;
-    if (time_2 >= time_1)
+    if (time_2 >= time_1) {
         exit_code = runCodeFromFileByte(path_2, error_file, env);
-    else
+        if (exit_code != 0)
+            goto RUN_SOURCE_CODE;
+    } else {
+RUN_SOURCE_CODE:
         exit_code = runCodeFromFileSource(path_1, error_file, save_afb, path_2, env);
+    }
 
     free(path_1);
     free(path_2);
@@ -240,11 +250,11 @@ int buildFile(FilePath out, FilePath in, FILE *error_file) {
     if (code == NULL)
         return -2;
 
-    bool res = writeAllCode(code, out);
+    int res = writeByteCode(code, out);
     freeAllCode(code);
 
-    if (!res) {
-        fprintf(error_file, "Build error.\n");
+    if (res != 1) {
+        fprintf(error_file, "Build error [%s] [Build %s].\n", writeByteCodeError[res], in);
         return -3;
     }
 

+ 9 - 12
src/tool/md5.c

@@ -15,11 +15,6 @@ struct MD5_CTX {
     unsigned char buffer[64];
 };
 
-typedef struct MD5_CTX MD5_CTX;
-
-static void MD5Init(MD5_CTX *context);
-static void MD5Update(MD5_CTX *context,unsigned char *input,unsigned int input_len);
-static void MD5Final(MD5_CTX *context,unsigned char digest[16]);
 static void MD5Transform(unsigned int state[4],unsigned char block[64]);
 static void MD5Encode(unsigned char *output,const unsigned int *input,unsigned int len);
 static void MD5Decode(unsigned int *output,const unsigned char *input,unsigned int len);
@@ -31,16 +26,18 @@ unsigned char PADDING[] = {
                 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
         };
 
-static void MD5Init(MD5_CTX *context) {
+MD5_CTX *MD5Init(void) {
+    MD5_CTX *context = calloc(1, sizeof(MD5_CTX));
     context->count[0] = 0;
     context->count[1] = 0;
     context->state[0] = 0x67452301;
     context->state[1] = 0xEFCDAB89;
     context->state[2] = 0x98BADCFE;
     context->state[3] = 0x10325476;
+    return context;
 }
 
-static void MD5Update(MD5_CTX *context, unsigned char *input, unsigned int input_len) {
+void MD5Update(MD5_CTX *context, unsigned char *input, unsigned int input_len) {
     unsigned int i;
     unsigned int index;
     unsigned int part_len;
@@ -67,7 +64,7 @@ static void MD5Update(MD5_CTX *context, unsigned char *input, unsigned int input
     memcpy(&context->buffer[index], &input[i], input_len - i);
 }
 
-static void MD5Final(MD5_CTX *context, unsigned char digest[16]) {
+void MD5Final(MD5_CTX *context, unsigned char digest[16]) {
     unsigned int index;
     unsigned int pad_len;
     unsigned char bits[8];
@@ -78,6 +75,7 @@ static void MD5Final(MD5_CTX *context, unsigned char digest[16]) {
     MD5Update(context, PADDING, pad_len);
     MD5Update(context, bits, 8);
     MD5Encode(digest, context->state, 16);
+    free(context);
 }
 
 static void MD5Encode(unsigned char *output,const unsigned int *input, unsigned int len) {
@@ -196,22 +194,21 @@ char *getFileMd5(const char *path) {
     unsigned long ret;
     unsigned char data[READ_DATA_SIZE];
     unsigned char md5_value[MD5_SIZE];
-    MD5_CTX md5;
 
     if ((fd = fopen(path, "rb")) == NULL)
         return NULL;
 
     char *md5str = calloc(MD5_STRING, sizeof(char));
-    MD5Init(&md5);
+    MD5_CTX *md5 = MD5Init();
     while (1) {
         ret = fread(data, 1, READ_DATA_SIZE, fd);
-        MD5Update(&md5, data, ret);
+        MD5Update(md5, data, ret);
         if (ret < READ_DATA_SIZE)
             break;
     }
 
     fclose(fd);
-    MD5Final(&md5, md5_value);
+    MD5Final(md5, md5_value);
 
     for(int i = 0; i < MD5_SIZE; i++)
         snprintf(md5str + i * 2, 2 + 1, "%02x", md5_value[i]);

二进制
test/af/test1.aub


二进制
test/af/test2.aub


+ 2 - 2
test/src/byte_code.c

@@ -16,13 +16,13 @@ int main() {
     af_Code *bt5 = makeBlockCode(parentheses, bt3, 0, 1, NULL, NULL);
     pushCode(&bt2, bt5);
 
-    if(!writeAllCode(bt1, "test.aub")) {
+    if(writeByteCode(bt1, "test.aub") != 1) {
         fprintf(stderr, "Write test.aub error.\n");
         return EXIT_FAILURE;
     }
 
     af_Code *get;
-    if(!readAllCode(&get, "test.aub")) {
+    if(readByteCode(&get, "test.aub") != 1) {
         fprintf(stderr, "Read test.aub error.\n");
         return EXIT_FAILURE;
     }