Browse Source

feat: 支持编译源文件为字节码

SongZihuan 3 years ago
parent
commit
efd47a83d0
7 changed files with 194 additions and 11 deletions
  1. 1 0
      include/runtime/aFunlang.h
  2. 1 0
      include/tool/file.h
  3. 8 0
      src/__main_build.h
  4. 76 3
      src/main.c
  5. 39 0
      src/main_build.c
  6. 45 5
      src/runtime/aFunlang.c
  7. 24 3
      src/tool/file.c

+ 1 - 0
include/runtime/aFunlang.h

@@ -18,4 +18,5 @@ AFUN_LANG_EXPORT int runCodeFromMemory(af_Code *code, af_Environment *env);
 AFUN_LANG_EXPORT int runCodeFromMemoryAsImport(af_Code *code, af_Environment *env);
 AFUN_LANG_EXPORT int runCodeFromFileByte(FilePath file, FILE *error_file, af_Environment *env);
 AFUN_LANG_EXPORT int runCodeFromFile(FilePath file, FILE *error_file, bool save_afb, af_Environment *env);
+AFUN_LANG_EXPORT int buildFile(FilePath out, FilePath in, FILE *error_file);
 #endif //AFUN_AFUNLANG_H

+ 1 - 0
include/tool/file.h

@@ -5,6 +5,7 @@
 /* 文件处理工具 */
 AFUN_TOOL_EXPORT int checkFile(char *path);
 AFUN_TOOL_EXPORT time_t getFileMTime(char *path);
+AFUN_TOOL_EXPORT char *joinPath(char *path, char *name, char *suffix);
 AFUN_TOOL_EXPORT char *getFileName(char *path_1);
 AFUN_TOOL_EXPORT char *getFileNameWithPath(char *path_1);
 AFUN_TOOL_EXPORT char *getFileSurfix(char *path);

+ 8 - 0
src/__main_build.h

@@ -0,0 +1,8 @@
+#ifndef AFUN_MAIN_BUILD_H_
+#define AFUN_MAIN_BUILD_H_
+
+int buildFileOutput(FilePath out, FilePath in, bool force);
+int buildFileToPath(FilePath path, FilePath in, bool force);
+int buildFileToSelf(FilePath in, bool force);
+
+#endif //AFUN_MAIN_BUILD_H_

+ 76 - 3
src/main.c

@@ -1,6 +1,7 @@
 #include <stdio.h>
 #include "aFun.h"
 #include "__main_run.h"
+#include "__main_build.h"
 
 ff_defArg(help, true)
                 ff_argRule('h', help, not, 'h')
@@ -17,7 +18,8 @@ ff_defArg(run, false)
 ff_endArg(run, false);
 
 ff_defArg(build, false)
-                ff_argRule('o', out, not, 'o')
+                ff_argRule('o', out, must, 'o')
+                ff_argRule('p', path, must, 'p')
                 ff_argRule('f', fource, not, 'f')
 ff_endArg(build, false);
 
@@ -30,6 +32,7 @@ static int mainHelp(ff_FFlags *ff);
 static void printVersion(void);
 static void printHelp(void);
 static int mainRun(ff_FFlags *ff);
+static int mainBuild(ff_FFlags *ff);
 
 int main(int argc, char **argv) {
     int exit_code = EXIT_SUCCESS;
@@ -42,13 +45,14 @@ int main(int argc, char **argv) {
     if (EQ_STR(child, "run"))
         exit_code = mainRun(ff);
     else if (EQ_STR(child, "build"))
-        printf("build");
+        exit_code = mainBuild(ff);
     else
         exit_code = mainHelp(ff);
 
     ff_freeFFlags(ff);
 
-    printf("Enter any key to continue...");
+    printf("aFunlang exit as: %d\n", exit_code);
+    printf("Enter any key to continue...\n");
     getc(stdin);
     return exit_code;
 }
@@ -176,4 +180,73 @@ static int mainRun(ff_FFlags *ff) {
     destructAFunEnvironment(env);
     freeAllRunList(rl);
     return exit_code;
+}
+
+static int mainBuild(ff_FFlags *ff) {
+    char *text = NULL;
+    char *out_put = NULL;
+    char *path = NULL;
+    bool force = false;
+    int mark;
+
+    while (1) {
+        mark = ff_getopt(&text, ff);
+
+        switch (mark) {
+            case 'o':
+                if (path != NULL)
+                    goto error;
+                out_put = text;
+                break;
+            case 'p':
+                if (out_put != NULL)
+                    goto error;
+                path = text;
+                break;
+            case 'f':
+                force = true;
+                break;
+            case -1:
+                goto out;
+            default:
+                printError(ff);
+                return EXIT_FAILURE;
+        }
+    }
+
+out:
+
+    if (out_put != NULL) {
+        FilePath in = NULL;
+
+        /* 如果没有参数 */
+        if (!ff_getopt_wild(&text, ff)) {
+            fprintf(stderr, "No source file to build.\n");
+            printHelp();
+            return EXIT_FAILURE;
+        } else
+            in = text;
+
+        /* 如果还有第二个参数 */
+        if (ff_getopt_wild(&text, ff)) {
+            fprintf(stderr, "Too many source file to build.\n");
+            printHelp();
+            return EXIT_FAILURE;
+        }
+
+        return buildFileOutput(out_put, in, force);
+    } else if (path != NULL) {
+        int exit_code = 0;
+        while (ff_getopt_wild(&text, ff) && exit_code == 0)
+            exit_code = buildFileToPath(path, text, force);
+        return exit_code;
+    }
+
+    int exit_code = 0;
+    while (ff_getopt_wild(&text, ff) && exit_code == 0)
+        exit_code = buildFileToSelf(text, force);
+    return exit_code;
+
+error:
+    return EXIT_FAILURE;
 }

+ 39 - 0
src/main_build.c

@@ -0,0 +1,39 @@
+#include "aFun.h"
+
+int buildFileOutput(FilePath out, FilePath in, bool force) {
+    if (!force) {
+        time_t time_1 = getFileMTime(in);
+        time_t time_2 = getFileMTime(out);
+
+        if (time_1 == 0 && time_2 == 0) {
+            fprintf(stderr, "File not exists [%s].", in);
+            return -1;
+        }
+
+        if (time_2 >= time_1)
+            return 0;
+    }
+
+    return buildFile(out, in, stderr);
+}
+
+int buildFileToPath(FilePath path, FilePath in, bool force) {
+    char *name = getFileName(in);
+    char *out = joinPath(path, name, ".aub");
+
+    int res = buildFileOutput(out, in, force);
+
+    free(name);
+    free(out);
+    return res;
+}
+
+int buildFileToSelf(FilePath in, bool force) {
+    char *path = getFileNameWithPath(in);
+    char *out = strJoin(path, ".aub", true, false);
+
+    int res = buildFileOutput(out, in, force);
+
+    free(out);
+    return res;
+}

+ 45 - 5
src/runtime/aFunlang.c

@@ -82,7 +82,7 @@ int runCodeFromFileSource(FilePath file, FILE *error_file, bool save_afb, FilePa
 
     char *sufix = getFileSurfix(file);
     if (sufix == NULL || !EQ_STR(".aun", sufix)) {
-        fprintf(error_file, "Is not .aun file[%s].", (sufix == NULL ? "" : sufix));
+        fprintf(error_file, "Is not .aun file[%s].\n", (sufix == NULL ? "" : sufix));
         return -2;
     }
 
@@ -154,7 +154,7 @@ int runCodeFromFileByte(FilePath file, FILE *error_file, af_Environment *env) {
 
     char *sufix = getFileSurfix(file);
     if (sufix == NULL || !EQ_STR(".aub", sufix)) {
-        fprintf(error_file, "Is not .aub file[%s].", (sufix == NULL ? "" : sufix));
+        fprintf(error_file, "Is not .aub file[%s].\n", (sufix == NULL ? "" : sufix));
         return -2;
     }
 
@@ -181,8 +181,8 @@ int runCodeFromFile(FilePath file, FILE *error_file, bool save_afb, af_Environme
         error_file = stderr;
 
     char *sufix = getFileSurfix(file);
-    if (sufix == NULL || (!EQ_STR(".aun", sufix) && EQ_STR(".aub", sufix))) {  // 不是源文件或字节码文件
-        fprintf(error_file, "Is not .aun/.aub file[%s].", (sufix == NULL ? "" : sufix));
+    if (sufix != NULL && !EQ_STR(".aun", sufix) && !EQ_STR(".aub", sufix)) {  // 不是源文件, 字节码文件或无后缀文件
+        fprintf(error_file, "Is not .aun/.aub file[%s].\n", sufix);
         return -2;
     }
 
@@ -194,7 +194,7 @@ int runCodeFromFile(FilePath file, FILE *error_file, bool save_afb, af_Environme
     time_t time_2 = getFileMTime(path_2);
 
     if (time_1 == 0 && time_2 == 0) {
-        fprintf(error_file, "File not exists [%s].", file);
+        fprintf(error_file, "File not exists [%s].\n", file);
         free(path_1);
         free(path_2);
         return -3;
@@ -210,3 +210,43 @@ int runCodeFromFile(FilePath file, FILE *error_file, bool save_afb, af_Environme
     free(path_2);
     return exit_code;
 }
+
+/*
+ * 函数名: buildFile
+ * 目标: 生成字节码文件
+ */
+int buildFile(FilePath out, FilePath in, FILE *error_file) {
+    if (out == NULL || in == NULL)
+        return -1;
+
+    if (error_file == NULL)
+        error_file = stderr;
+
+    char *suffix_in = getFileSurfix(in);
+    char *suffix_out = getFileSurfix(out);
+    if (suffix_in == NULL || !EQ_STR(".aun", suffix_in)) {  // 不是源文件
+        fprintf(error_file, "Input file is not .aun file[%s].\n", (suffix_in == NULL ? "" : suffix_in));
+        return -2;
+    }
+
+    if (suffix_out == NULL || !EQ_STR(".aub", suffix_out)) {  // 不是字节码文件
+        fprintf(error_file, "Output file is not .aub file[%s].\n", (suffix_out == NULL ? "" : suffix_out));
+        return -2;
+    }
+
+    af_Parser *parser = makeParserByFile(in, error_file);
+    af_Code *code = parserCode(in, parser);
+    freeParser(parser);
+    if (code == NULL)
+        return -2;
+
+    bool res = writeAllCode(code, out);
+    freeAllCode(code);
+
+    if (!res) {
+        fprintf(error_file, "Build error.\n");
+        return -3;
+    }
+
+    return 0;
+}

+ 24 - 3
src/tool/file.c

@@ -40,6 +40,22 @@ time_t getFileMTime(char *path) {
     return my_stat.st_mtime;
 }
 
+char *joinPath(char *path, char *name, char *suffix) {
+    char *name_suffix = strJoin(name, suffix, false, false);
+    char *res = NULL;
+
+    if (path != NULL && path[STR_LEN(path) - 1] == SEP_CH)
+        res = strJoin(path, name_suffix, false, true);
+    else if (path != NULL) {
+        res = strJoin(path, SEP, false, false);
+        res = strJoin(res, name_suffix, true, true);
+    } else
+        res = name_suffix;
+
+    /* name_suffix已经在上述的strJoin释放 */
+    return res;
+}
+
 /*
  * 函数: getFileName
  * 目标: 给定路径获取该路径所指定的文件名
@@ -57,7 +73,7 @@ char *getFileName(char *path_1){
     else
         slash++;
 
-    if ((point = strchr(path, '.')) != NULL)
+    if ((point = getFileSurfix(path)) != NULL)
         *point = NUL;
 
     char *res = strCopy(slash);
@@ -74,7 +90,7 @@ char *getFileNameWithPath(char *path_1){
     char *path = strCopy(path_1);  // 复制数组, 避免path_1是常量字符串导致无法修改其值
     char *res;
 
-    if ((point = strchr(path, '.')) != NULL)
+    if ((point = getFileSurfix(path)) != NULL)
         *point = NUL;
 
     res = strCopy(path);
@@ -87,7 +103,12 @@ char *getFileNameWithPath(char *path_1){
  * 目标: 获取文件后缀 (不会生成新字符串)
  */
 char *getFileSurfix(char *path) {
-    return strchr(path, '.');
+    char *last_ = strrchr(path, SEP_CH);
+
+    if (last_ != NULL)
+        return strrchr(last_ + 1, '.');
+    else
+        return strrchr(path, '.');
 }
 
 /*