Ver Fonte

feat: 支持语句跳转

支持使用goto语句跳转到指定的label
支持使用label标记语句
SongZihuan há 4 anos atrás
pai
commit
75801fb4a3
13 ficheiros alterados com 307 adições e 23 exclusões
  1. 3 0
      include/run.h
  2. 14 0
      include/statement.h
  3. 5 1
      include/token.h
  4. 6 4
      include/value.h
  5. 4 2
      main.c
  6. 108 0
      parser/grammar.c
  7. 2 0
      parser/include/__grammar.h
  8. 2 0
      parser/syntax.c
  9. 46 9
      src/run.c
  10. 73 4
      src/runbranch.c
  11. 0 1
      src/runcall.c
  12. 38 0
      src/statement.c
  13. 6 2
      src/value.c

+ 3 - 0
include/run.h

@@ -18,6 +18,7 @@ bool ifBranchSafeInterStatement(INTER_FUNCTIONSIG);
 bool functionSafeInterStatement(INTER_FUNCTIONSIG);
 bool cycleBranchSafeInterStatement(INTER_FUNCTIONSIG);
 bool tryBranchSafeInterStatement(INTER_FUNCTIONSIG);
+Statement *checkLabel(Statement *base, char *label);
 
 ResultType operationStatement(INTER_FUNCTIONSIG);
 ResultType setClass(INTER_FUNCTIONSIG);
@@ -43,6 +44,8 @@ ResultType restartCode(INTER_FUNCTIONSIG);
 ResultType returnCode(INTER_FUNCTIONSIG);
 ResultType raiseCode(INTER_FUNCTIONSIG);
 ResultType assertCode(INTER_FUNCTIONSIG);
+ResultType gotoLabel(INTER_FUNCTIONSIG);
+ResultType runLabel(INTER_FUNCTIONSIG);
 
 ResultType includeFile(INTER_FUNCTIONSIG);
 ResultType importFile(INTER_FUNCTIONSIG);

+ 14 - 0
include/statement.h

@@ -34,6 +34,8 @@ struct Statement{
         from_import_file,
         default_var,
         assert,
+        label_,
+        goto_,
     } type;
     union StatementU{
         struct base_value{
@@ -166,6 +168,16 @@ struct Statement{
         struct {
             struct Statement *conditions;
         } assert;
+        struct {
+            struct Statement *command;
+            struct Statement *as;
+            char *label;
+        } label_;
+        struct {
+            struct Statement *times;
+            struct Statement *return_;
+            struct Statement *label;
+        } goto_;
     }u;
     long int line;
     char *code_file;
@@ -222,6 +234,8 @@ Statement *makeIncludeStatement(Statement *file, long int line, char *file_dir);
 Statement *makeImportStatement(Statement *file, Statement *as);
 Statement *makeFromImportStatement(Statement *file, Parameter *as, Parameter *pt);
 Statement *makeDefaultVarStatement(Parameter *var, long int line, char *file_dir, enum DefaultType type);
+Statement *makeLabelStatement(Statement *var, Statement *command, char *label, long int line, char *file_dir);
+Statement *makeGotoStatement(Statement *return_, Statement *times, Statement *label, long int line, char *file_dir);
 struct Token *setOperationFromToken(Statement **st_ad, struct Token *left, struct Token *right, enum OperationType type, bool is_right);
 
 StatementList *makeStatementList(Statement *condition, Statement *var, Statement *code, int type);

+ 5 - 1
include/token.h

@@ -91,8 +91,10 @@
 #define MATHER_LAMBDA 77
 #define MATHER_NOTENTER 78
 #define MATHER_COMMENT 79
+#define MATHER_GOTO 80
+#define MATHER_LABEL 81
 
-#define MATHER_MAX 80
+#define MATHER_MAX 82
 
 // 从-6开始是为了避开status的特殊值,尽管这并没有什么影响
 #define COMMAND -6
@@ -121,6 +123,8 @@
 #define ASSERT -29
 #define DO_BRANCH -30
 #define WITH_BRANCH -31
+#define GOTO -32
+#define LABEL -33
 
 #define printTokenEnter(tk, debug, type, message) do{ \
 writeLog(debug, type, message, NULL); \

+ 6 - 4
include/value.h

@@ -73,14 +73,16 @@ struct LinkValue{
 struct Result{
     enum ResultType{
         not_return = 1,  // 无返回值
-        function_return,  // 函数返回值
-        operation_return,  // 表达式返回值
-        error_return,  // 错误
+        function_return=2,  // 函数返回值
+        operation_return=3,  // 表达式返回值
+        error_return=4,  // 错误
         break_return,
         continue_return,
         rego_return,
         restart_return,
+        goto_return,
     } type;
+    char *label;
     struct LinkValue *value;
     struct Error *error;
     int times;
@@ -129,7 +131,7 @@ void setResultOperationNone(Result *ru, Inter *inter, LinkValue *father);
 void setResultOperation(Result *ru, LinkValue *value, Inter *inter);
 void setResultOperationBase(Result *ru, LinkValue *value, Inter *inter);
 void freeResult(Result *ru);
-void freeResultSave(Result *ru);
+void freeResultSafe(Result *ru);
 
 Error *makeError(char *type, char *message, long int line, char *file);
 void freeError(Result *base);

+ 4 - 2
main.c

@@ -22,10 +22,12 @@ int main(int argc, char *argv[]) {
 
 /** TODO-szh List
  * 装饰器
+ * __call__ 设定
+ * __var__ 设定
+ * super函数
+ * 默认形参
  * 官方函数
  * 官方类
  * for 循环
- * goto 语句
- * label 标签
  * yield 语句
  */

+ 108 - 0
parser/grammar.c

@@ -103,6 +103,12 @@ void parserCommand(PASERSSIGNATURE){
         case MATHER_DEF :
             status = commandCallBack_(CALLPASERSSIGNATURE, parserDef, FUNCTION, &st, "Command: call def/class\n");
             break;
+        case MATHER_GOTO :
+            status = commandCallBack_(CALLPASERSSIGNATURE, parserGoto, GOTO, &st, "Command: call goto\n");
+            break;
+        case MATHER_LABEL :
+            status = commandCallBack_(CALLPASERSSIGNATURE, parserLabel, LABEL, &st, "Command: call label\n");
+            break;
         case MATHER_DO :
             status = commandCallBack_(CALLPASERSSIGNATURE, parserDo, DO_BRANCH, &st, "Command: call do\n");
             break;
@@ -177,7 +183,109 @@ void parserCommand(PASERSSIGNATURE){
         goto return_;
     addStatementToken(COMMAND, st, pm);
     return_: return;
+}
+
+void parserLabel(PASERSSIGNATURE){
+    Statement *st = NULL;
+    Statement *var = NULL;
+    Statement *command = NULL;
+    Token *label_tk = NULL;
+    int tmp;
+    char *label = NULL;
+    long int line = delToken(pm);
+
+    if (!checkToken(pm, MATHER_COLON)){
+        syntaxError(pm, syntax_error, line, 1, "Don't get : afther label");
+        goto error_;
+    }
+    switch (readBackToken(pm)) {
+        case MATHER_STRING:
+        case MATHER_VAR:
+            label_tk = popNewToken(pm->tm);
+            label = memStrcpy(label_tk->data.str);
+            freeToken(label_tk, false);
+            break;
+        default:
+            syntaxError(pm, syntax_error, line, 1, "Don't get a label name");
+            goto error_;
+    }
+
+    if ((tmp = readBackToken(pm)) == MATHER_ENTER || tmp == MATHER_SEMICOLON || tmp == MATHER_EOF)
+        goto make;
+    if (tmp != MATHER_COLON) {
+        if (!checkToken(pm, MATHER_AS)) {
+            syntaxError(pm, syntax_error, line, 1, "Don't get as afther goto label");
+            goto error_;
+        } else if (!callChildStatement(CALLPASERSSIGNATURE, parserOperation, OPERATION, &var, "Don't get a goto var"))
+            goto error_;
+    }
+
+    if ((tmp = readBackToken(pm)) == MATHER_ENTER || tmp == MATHER_SEMICOLON || tmp == MATHER_EOF)
+        goto make;
+    else if (!checkToken(pm, MATHER_COLON)){
+        syntaxError(pm, syntax_error, line, 1, "Don't get : afther goto var");
+        goto error_;
+    }
+    else if (!callChildStatement(CALLPASERSSIGNATURE, parserCommand, COMMAND, &command, "Don't get a label command"))
+        goto error_;
+
+    make:
+    st = makeLabelStatement(var, command, label, line, pm->file);
+    addStatementToken(LABEL, st, pm);
+    memFree(label);
+    return;
+
+    error_:
+    freeStatement(var);
+    freeStatement(command);
+    memFree(label);
+    return;
+}
+
+void parserGoto(PASERSSIGNATURE){
+    Statement *st = NULL;
+    Statement *label = NULL;
+    Statement *times = NULL;
+    Statement *return_ = NULL;
+    int tmp;
+    long int line = delToken(pm);
+
+    if (!checkToken(pm, MATHER_AT)){
+        syntaxError(pm, syntax_error, line, 1, "Don't get @ afther goto");
+        goto error_;
     }
+    if (!callChildStatement(CALLPASERSSIGNATURE, parserOperation, OPERATION, &label, "Don't get a goto times"))
+        goto error_;
+
+    if ((tmp = readBackToken(pm)) == MATHER_ENTER || tmp == MATHER_SEMICOLON || tmp == MATHER_EOF)
+        goto make;
+    else if (!checkToken(pm, MATHER_COLON)){
+        syntaxError(pm, syntax_error, line, 1, "Don't get : afther goto label");
+        goto error_;
+    }
+    else if (!checkToken(pm, MATHER_COLON) && !callChildStatement(CALLPASERSSIGNATURE, parserOperation, OPERATION, &times, "Don't get a goto times"))
+        goto error_;
+
+    if ((tmp = readBackToken(pm)) == MATHER_ENTER || tmp == MATHER_SEMICOLON || tmp == MATHER_EOF)
+        goto make;
+    else if (times != NULL && !checkToken(pm, MATHER_COLON)){
+        syntaxError(pm, syntax_error, line, 1, "Don't get : afther goto times");
+        goto error_;
+    }
+    else if (!callChildStatement(CALLPASERSSIGNATURE, parserOperation, OPERATION, &return_, "Don't get a goto return"))
+        goto error_;
+
+    make:
+    st = makeGotoStatement(return_, times, label, line, pm->file);
+    addStatementToken(GOTO, st, pm);
+    return;
+
+    error_:
+    freeStatement(label);
+    freeStatement(times);
+    freeStatement(return_);
+    return;
+}
 
 /**
  * import 匹配

+ 2 - 0
parser/include/__grammar.h

@@ -36,6 +36,8 @@ void parserFactor(PASERSSIGNATURE);
 void parserAssignment(PASERSSIGNATURE);
 void parserTuple(PASERSSIGNATURE);
 void parserImport(PASERSSIGNATURE);
+void parserLabel(PASERSSIGNATURE);
+void parserGoto(PASERSSIGNATURE);
 void parserVarControl(PASERSSIGNATURE);
 
 void syntaxError(ParserMessage *pm, int status,long int line , int num, ...);

+ 2 - 0
parser/syntax.c

@@ -325,6 +325,8 @@ int getMatherStatus(LexFile *file, LexMathers *mathers) {
         strMatherMacro(MATHER_FROM, "from");
         strMatherMacro(MATHER_ASSERT, "assert");
         strMatherMacro(MATHER_LAMBDA, "lambda");
+        strMatherMacro(MATHER_GOTO, "goto");
+        strMatherMacro(MATHER_LABEL, "label");
 
         status = checkoutMather(mathers, MATHER_MAX);
     }

+ 46 - 9
src/run.c

@@ -88,6 +88,9 @@ ResultType runStatement(INTER_FUNCTIONSIG) {
         case assert:
             type = assertCode(CALL_INTER_FUNCTIONSIG(st, var_list, result, father));
             break;
+        case goto_:
+            type = gotoLabel(CALL_INTER_FUNCTIONSIG(st, var_list, result, father));
+            break;
         default:
             setResult(result, inter, father);
             break;
@@ -117,11 +120,25 @@ ResultType iterStatement(INTER_FUNCTIONSIG) {
     }
 
     do {
-        for (base_st = st; base_st != NULL; base_st = base_st->next) {
+        for (base_st = st; base_st != NULL; PASS) {
             freeResult(result);
             type = runStatement(CALL_INTER_FUNCTIONSIG(base_st, var_list, result, father));
-            if (!run_continue_type(type))
+            if (type == goto_return && result->times == 0){
+                Statement *label_st = checkLabel(st, result->label);
+                if (label_st == NULL){
+                    setResultError(result, inter, "GotoException", "Don't find label", st, father, true);
+                    type = error_return;
+                    break;
+                }
+                type = runLabel(CALL_INTER_FUNCTIONSIG(label_st, var_list, result, father));
+                if (!run_continue_type(type))
+                    break;
+                base_st = label_st->next;
+            }
+            else if (!run_continue_type(type))
                 break;
+            else
+                base_st = base_st->next;
         }
     } while (type == restart_return && result->times == 0);
 
@@ -142,13 +159,26 @@ ResultType globalIterStatement(Result *result, LinkValue *base_father, Inter *in
     Statement *base_st = NULL;
     VarList *var_list = NULL;
     enum ResultType type;
-
     do {
-        for (base_st = st, var_list = inter->var_list; base_st != NULL; base_st = base_st->next) {
+        for (base_st = st, var_list = inter->var_list; base_st != NULL; PASS) {
             freeResult(result);
             type = runStatement(CALL_INTER_FUNCTIONSIG(base_st, var_list, result, father));
-            if (!run_continue_type(type))
+            if (type == goto_return){
+                Statement *label_st = checkLabel(st, result->label);
+                if (label_st == NULL){
+                    setResultError(result, inter, "GotoException", "Don't find label", st, father, true);
+                    type = error_return;
+                    break;
+                }
+                type = runLabel(CALL_INTER_FUNCTIONSIG(label_st, var_list, result, father));
+                if (!run_continue_type(type))
+                    break;
+                base_st = label_st->next;
+            }
+            else if (!run_continue_type(type))
                 break;
+            else
+                base_st = base_st->next;
         }
     } while (type == restart_return && result->times == 0);
 
@@ -178,7 +208,7 @@ bool ifBranchSafeInterStatement(INTER_FUNCTIONSIG){
         if (result->times < 0)
             return false;
     }
-    if (type == restart_return)
+    if (type == restart_return || type == goto_return)
         result->times--;
     return true;
 }
@@ -194,7 +224,7 @@ bool cycleBranchSafeInterStatement(INTER_FUNCTIONSIG){
         if (result->times < 0)
             return false;
     }
-    if (type == restart_return)
+    if (type == restart_return || type == goto_return)
         result->times--;
     return true;
 }
@@ -205,7 +235,7 @@ bool tryBranchSafeInterStatement(INTER_FUNCTIONSIG){
     if (run_continue_type(type)){
         return false;
     }
-    if (type == restart_return)
+    if (type == restart_return || type == goto_return)
         result->times--;
     return true;
 }
@@ -221,4 +251,11 @@ bool functionSafeInterStatement(INTER_FUNCTIONSIG){
     }
     result->type = not_return;
     return false;
-}
+}
+
+Statement *checkLabel(Statement *base, char *label){
+    for (PASS; base != NULL; base = base->next)
+        if (base->type == label_ && eqString(base->u.label_.label, label))
+            return base;
+    return NULL;
+}

+ 73 - 4
src/runbranch.c

@@ -8,6 +8,14 @@ bool checkNumber(INTER_FUNCTIONSIG){
     return true;
 }
 
+bool checkString(INTER_FUNCTIONSIG){
+    if (!isType(result->value->value, string)) {
+        setResultError(result, inter, "TypeException", "Don't get a string value", st, father, true);
+        return false;
+    }
+    return true;
+}
+
 bool checkBool(Value *value){
     switch (value->type) {
         case number:
@@ -370,7 +378,7 @@ ResultType breakCycle(INTER_FUNCTIONSIG){
     if (operationSafeInterStatement(CALL_INTER_FUNCTIONSIG(st->u.break_cycle.times, var_list, result, father)))
         return result->type;
 
-    if (checkNumber(CALL_INTER_FUNCTIONSIG(st, var_list, result, father)))
+    if (!checkNumber(CALL_INTER_FUNCTIONSIG(st, var_list, result, father)))
         return result->type;
     times_int = (int)result->value->value->data.num.num;
     freeResult(result);
@@ -392,7 +400,7 @@ ResultType continueCycle(INTER_FUNCTIONSIG){
     if (operationSafeInterStatement(CALL_INTER_FUNCTIONSIG(st->u.continue_cycle.times, var_list, result, father)))
         return result->type;
 
-    if (checkNumber(CALL_INTER_FUNCTIONSIG(st, var_list, result, father)))
+    if (!checkNumber(CALL_INTER_FUNCTIONSIG(st, var_list, result, father)))
         return result->type;
     times_int = (int)result->value->value->data.num.num;
     freeResult(result);
@@ -414,7 +422,7 @@ ResultType regoIf(INTER_FUNCTIONSIG){
     if (operationSafeInterStatement(CALL_INTER_FUNCTIONSIG(st->u.rego_if.times, var_list, result, father)))
         return result->type;
 
-    if (checkNumber(CALL_INTER_FUNCTIONSIG(st, var_list, result, father)))
+    if (!checkNumber(CALL_INTER_FUNCTIONSIG(st, var_list, result, father)))
         return result->type;
     times_int = (int)result->value->value->data.num.num;
     freeResult(result);
@@ -436,7 +444,7 @@ ResultType restartCode(INTER_FUNCTIONSIG){
     if (operationSafeInterStatement(CALL_INTER_FUNCTIONSIG(st->u.restart.times, var_list, result, father)))
         return result->type;
 
-    if (checkNumber(CALL_INTER_FUNCTIONSIG(st, var_list, result, father)))
+    if (!checkNumber(CALL_INTER_FUNCTIONSIG(st, var_list, result, father)))
         return result->type;
     times_int = (int)result->value->value->data.num.num;
     freeResult(result);
@@ -492,3 +500,64 @@ ResultType assertCode(INTER_FUNCTIONSIG){
         setResultError(result, inter, "AssertException", "Raise by user", st, father, true);
     return result->type;
 }
+
+ResultType gotoLabel(INTER_FUNCTIONSIG){
+    int times_int = 0;
+    char *label = NULL;
+    setResultCore(result);
+
+    if (operationSafeInterStatement(CALL_INTER_FUNCTIONSIG(st->u.goto_.label, var_list, result, father)))
+        return result->type;
+    if (!checkString(CALL_INTER_FUNCTIONSIG(st, var_list, result, father)))
+        return result->type;
+    label = memStrcpy(result->value->value->data.str.str);
+
+    freeResult(result);
+    if (st->u.goto_.times == NULL)
+        goto not_times;
+    if (operationSafeInterStatement(CALL_INTER_FUNCTIONSIG(st->u.goto_.times, var_list, result, father))) {
+        memFree(label);
+        return result->type;
+    }
+    if (!checkNumber(CALL_INTER_FUNCTIONSIG(st, var_list, result, father))) {
+        memFree(label);
+        return result->type;
+    }
+    times_int = (int)result->value->value->data.num.num;
+    freeResult(result);
+    not_times:
+    if (st->u.goto_.return_ == NULL)
+        setResult(result, inter, father);
+    else if (operationSafeInterStatement(CALL_INTER_FUNCTIONSIG(st->u.goto_.return_, var_list, result, father))) {
+        memFree(label);
+        return result->type;
+    }
+
+    result->times = times_int;
+    result->type = goto_return;
+    result->label = label;
+    return result->type;
+}
+
+ResultType runLabel(INTER_FUNCTIONSIG) {
+    // goto的值通过result传入
+    LinkValue *goto_value = result->value;
+    result->value = NULL;
+    freeResult(result);
+    var_list = pushVarList(var_list, inter);
+    if (st->u.label_.as != NULL)
+        assCore(st->u.label_.as, goto_value, CALL_INTER_FUNCTIONSIG_NOT_ST(var_list, result, father));
+    gc_freeTmpLink(&goto_value->gc_status);
+    if (st->u.label_.as != NULL && !run_continue(result))
+        goto return_;
+
+    freeResult(result);
+    if (st->u.label_.command != NULL)
+        operationSafeInterStatement(CALL_INTER_FUNCTIONSIG(st->u.label_.command, var_list, result, father));
+    else
+        setResult(result, inter, father);
+
+    return_:
+    popVarList(var_list);
+    return result->type;
+}

+ 0 - 1
src/runcall.c

@@ -88,7 +88,6 @@ ResultType callBack(INTER_FUNCTIONSIG) {
         return result->type;
     }
 
-
     setResultError(result, inter, NULL, NULL, st, father, false);
     return_:
     return result->type;

+ 38 - 0
src/statement.c

@@ -256,6 +256,24 @@ Statement *makeDefaultVarStatement(Parameter *var, long int line, char *file_dir
     return tmp;
 }
 
+Statement *makeLabelStatement(Statement *var, Statement *command, char *label, long int line, char *file_dir) {
+    Statement *tmp = makeStatement(line, file_dir);
+    tmp->type = label_;
+    tmp->u.label_.as = var;
+    tmp->u.label_.command = command;
+    tmp->u.label_.label = memStrcpy(label);
+    return tmp;
+}
+
+Statement *makeGotoStatement(Statement *return_, Statement *times, Statement *label, long int line, char *file_dir) {
+    Statement *tmp = makeStatement(line, file_dir);
+    tmp->type = goto_;
+    tmp->u.goto_.return_ = return_;
+    tmp->u.goto_.times = times;
+    tmp->u.goto_.label = label;
+    return tmp;
+}
+
 void connectStatement(Statement *base, Statement *new){
     for (PASS; base->next != NULL; base = base->next)
         PASS;
@@ -377,6 +395,16 @@ void freeStatement(Statement *st){
             case assert:
                 freeStatement(st->u.assert.conditions);
                 break;
+            case label_:
+                freeStatement(st->u.label_.command);
+                freeStatement(st->u.label_.as);
+                memFree(st->u.label_.label);
+                break;
+            case goto_:
+                freeStatement(st->u.goto_.return_);
+                freeStatement(st->u.goto_.times);
+                freeStatement(st->u.goto_.label);
+                break;
             default:
                 break;
         }
@@ -515,6 +543,16 @@ Statement *copyStatementCore(Statement *st){
         case assert:
             new->u.assert.conditions = copyStatement(st->u.assert.conditions);
             break;
+        case label_:
+            new->u.label_.command = copyStatement(st->u.label_.command);
+            new->u.label_.as = copyStatement(st->u.label_.as);
+            new->u.label_.label = memStrcpy(st->u.label_.label);
+            break;
+        case goto_:
+            new->u.goto_.times = copyStatement(st->u.goto_.times);
+            new->u.goto_.return_ = copyStatement(st->u.goto_.return_);
+            new->u.goto_.label = copyStatement(st->u.goto_.label);
+            break;
         default:
             break;
     }

+ 6 - 2
src/value.c

@@ -184,6 +184,7 @@ void setResultCore(Result *ru) {
     ru->times = 0;
     ru->error = NULL;
     ru->value = NULL;
+    ru->label = NULL;
 }
 
 void setResult(Result *ru, Inter *inter, LinkValue *father) {
@@ -231,16 +232,19 @@ void setResultOperationBase(Result *ru, LinkValue *value, Inter *inter) {
 }
 
 void freeResult(Result *ru){
-    freeResultSave(ru);
+    memFree(ru->label);
+    ru->label = NULL;
+    freeResultSafe(ru);
     if (ru->value != NULL) {
         gc_freeTmpLink(&ru->value->gc_status);
         ru->value = NULL;
     }
 }
 
-void freeResultSave(Result *ru){
+void freeResultSafe(Result *ru){
     if (ru->error != NULL)
         freeError(ru);
+    ru->error = NULL;
 }
 
 void printValue(Value *value, FILE *debug){