Răsfoiți Sursa

feat: 异常处理

允许使用try...except分支进行异常捕获
允许使用raise抛出异常
不支持try xxx as var语句, 但grammar允许匹配
SongZihuan 4 ani în urmă
părinte
comite
4c260fdcda
10 a modificat fișierele cu 196 adăugiri și 14 ștergeri
  1. 1 0
      include/__grammar.h
  2. 3 1
      include/run.h
  3. 8 0
      include/statement.h
  4. 5 2
      include/token.h
  5. 0 2
      main.c
  6. 86 7
      parser/grammar.c
  7. 2 1
      parser/syntax.c
  8. 16 0
      src/run.c
  9. 54 0
      src/runbranch.c
  10. 21 1
      src/statement.c

+ 1 - 0
include/__grammar.h

@@ -29,6 +29,7 @@ void parserControl(PASERSSIGNATURE, Statement *(*callBack)(Statement *), int typ
 void parserDef(PASERSSIGNATURE);
 void parserIf(PASERSSIGNATURE);
 void parserWhile(PASERSSIGNATURE);
+void parserTry(PASERSSIGNATURE);
 void parserCode(PASERSSIGNATURE);
 void parserOperation(PASERSSIGNATURE);
 void parserPolynomial(PASERSSIGNATURE);

+ 3 - 1
include/run.h

@@ -11,16 +11,18 @@ bool operationSafeInterStatement(Result *result, INTER_FUNCTIONSIG);
 bool ifBranchSafeInterStatement(Result *result, INTER_FUNCTIONSIG);
 bool functionSafeInterStatement(Result *result, INTER_FUNCTIONSIG);
 bool cycleBranchSafeInterStatement(Result *result, INTER_FUNCTIONSIG);
+bool tryBranchSafeInterStatement(Result *result, INTER_FUNCTIONSIG);
 Result setFunction(INTER_FUNCTIONSIG);
 Result callFunction(INTER_FUNCTIONSIG);
 Result getBaseVar(INTER_FUNCTIONSIG);
 Result getBaseValue(INTER_FUNCTIONSIG);
 Result ifBranch(INTER_FUNCTIONSIG);
 Result whileBranch(INTER_FUNCTIONSIG);
-
+Result tryBranch(INTER_FUNCTIONSIG);
 Result breakCycle(INTER_FUNCTIONSIG);
 Result continueCycle(INTER_FUNCTIONSIG);
 Result regoIf(INTER_FUNCTIONSIG);
 Result restartCode(INTER_FUNCTIONSIG);
 Result returnCode(INTER_FUNCTIONSIG);
+Result raiseCode(INTER_FUNCTIONSIG);
 #endif //VIRTUALMATH_RUN_H

+ 8 - 0
include/statement.h

@@ -20,6 +20,7 @@ typedef struct Statement{
         rego_if,
         restart,
         return_code,
+        raise_code,
     } type;
     union StatementU{
         struct base_value{
@@ -96,6 +97,9 @@ typedef struct Statement{
         struct {
             struct Statement *value;
         } return_code;
+        struct {
+            struct Statement *value;
+        } raise_code;
     }u;
     struct Statement *next;
 } Statement;
@@ -104,6 +108,8 @@ typedef struct StatementList{
     enum {
         if_b,
         do_b,
+        while_b,
+        except_b,
     } type;
     struct Statement *condition;
     struct Statement *var;
@@ -119,11 +125,13 @@ Statement *makeFunctionStatement(Statement *name, Statement *function);
 Statement *makeCallStatement(Statement *function);
 Statement *makeIfStatement();
 Statement *makeWhileStatement();
+Statement *makeTryStatement();
 Statement *makeBreakStatement(Statement *times);
 Statement *makeContinueStatement(Statement *times);
 Statement *makeRegoStatement(Statement *times);
 Statement *makeRestartStatement(Statement *times);
 Statement *makeReturnStatement(Statement *value);
+Statement *makeRaiseStatement(Statement *value);
 
 void connectStatement(Statement *base, Statement *new);
 void freeStatement(Statement *st);

+ 5 - 2
include/token.h

@@ -82,9 +82,10 @@
 #define MATHER_COMMA 70
 #define MATHER_COLON 71
 #define MATHER_SEMICOLON 72
-#define MATHER_Link 73
+#define MATHER_LINK 73
+#define MATHER_RAISE 74
 
-#define MATHER_MAX 74
+#define MATHER_MAX 75
 
 // 从-5开始是为了避开status的特殊值,尽管这并没有什么影响
 #define COMMANDLIST -5
@@ -104,6 +105,8 @@
 #define REGO -19
 #define RETURN -20
 #define RESTART -20
+#define TRY_BRANCH -21
+#define RAISE -20
 
 typedef struct Token{
     int token_type;  // 记录token的类型,大于0的数字均为lex匹配器所匹配,小于0的为syntax解析器所匹配

+ 0 - 2
main.c

@@ -118,9 +118,7 @@ void freeArgs(){
 }
 
 /*
- *  TODO-szh try...except 分支
  *  TODO-szh 抛出异常
- *  TODO-szh restart语句
  *  TODO-szh 函数参数
  *  TODO-szh 列表、字典
  */

+ 86 - 7
parser/grammar.c

@@ -117,10 +117,13 @@ void parserCommand(PASERSSIGNATURE){
             status = commandCallBack_(CALLPASERSSIGNATURE, parserDef, FUNCTION, &st, "Command: call def\n");
             break;
         case MATHER_IF :
-            status = commandCallBack_(CALLPASERSSIGNATURE, parserIf, IF_BRANCH, &st, "Command: call def\n");
+            status = commandCallBack_(CALLPASERSSIGNATURE, parserIf, IF_BRANCH, &st, "Command: call if\n");
             break;
         case MATHER_WHILE :
-            status = commandCallBack_(CALLPASERSSIGNATURE, parserWhile, WHILE_BRANCH, &st, "Command: call def\n");
+            status = commandCallBack_(CALLPASERSSIGNATURE, parserWhile, WHILE_BRANCH, &st, "Command: call while\n");
+            break;
+        case MATHER_TRY :
+            status = commandCallBack_(CALLPASERSSIGNATURE, parserTry, TRY_BRANCH, &st, "Command: call try\n");
             break;
         case MATHER_BREAK :
             status = commandCallControl_(CALLPASERSSIGNATURE, makeBreakStatement, BREAK, &st, "Command: call break\n");
@@ -137,8 +140,11 @@ void parserCommand(PASERSSIGNATURE){
         case MATHER_RETURN :
             status = commandCallControl_(CALLPASERSSIGNATURE, makeReturnStatement, RETURN,  &st, "Command: call return\n");
             break;
+        case MATHER_RAISE :
+            status = commandCallControl_(CALLPASERSSIGNATURE, makeRaiseStatement, RAISE,  &st, "Command: call raise\n");
+            break;
         default :
-            status = commandCallBack_(CALLPASERSSIGNATURE, parserOperation, OPERATION, &st, "Command: call def\n");
+            status = commandCallBack_(CALLPASERSSIGNATURE, parserOperation, OPERATION, &st, "Command: call operation\n");
             break;
     }
     if (!status)
@@ -280,7 +286,7 @@ void parserWhile(PASERSSIGNATURE){
             }
             if (sl != NULL)
                 freeStatementList(sl);
-            sl = makeStatementList(condition_tmp, var_tmp, code_tmp, if_b);
+            sl = makeStatementList(condition_tmp, var_tmp, code_tmp, while_b);
             goto again;
         }
         case MATHER_DO:
@@ -332,6 +338,79 @@ void parserWhile(PASERSSIGNATURE){
     return;
 }
 
+void parserTry(PASERSSIGNATURE){
+    struct Statement *st = NULL, *try_st = NULL, *else_st = NULL, *finally_st = NULL;
+    StatementList *sl = NULL;
+
+    again:
+    switch (readBackToken(pm)) {
+        case MATHER_TRY:{
+            if (try_st != NULL)
+                goto default_;
+            delToken(pm);
+            if (!callParserCode(CALLPASERSSIGNATURE, &try_st, "Don't get a try code"))
+                goto error_;
+            goto again;
+        }
+        case MATHER_EXCEPT: {
+            Statement *code_tmp = NULL, *var_tmp = NULL, *condition_tmp = NULL;
+            delToken(pm);
+            callChildStatement(CALLPASERSSIGNATURE, parserOperation, OPERATION, &condition_tmp, NULL);
+
+            if (!callParserAs(CALLPASERSSIGNATURE, &var_tmp, "Don't get a except var")){
+                freeStatement(condition_tmp);
+                goto error_;
+            }
+            if (!callParserCode(CALLPASERSSIGNATURE, &code_tmp, "Don't get a except code")) {
+                freeStatement(condition_tmp);
+                freeStatement(var_tmp);
+                goto error_;
+            }
+            sl = makeConnectStatementList(sl, condition_tmp, var_tmp, code_tmp, except_b);
+            goto again;
+        }
+        case MATHER_ELSE:
+            if (else_st != NULL) {
+                syntaxError(pm, syntax_error, 1, "get else after else\n");
+                goto error_;
+            }
+            delToken(pm);
+            if (!callParserCode(CALLPASERSSIGNATURE, &else_st, "Don't get a try...else code"))
+                goto error_;
+            goto again;
+        case MATHER_FINALLY:
+            delToken(pm);
+            if (!callParserCode(CALLPASERSSIGNATURE, &finally_st, "Don't get a try...finally code"))
+                goto error_;
+            break;
+        case MATHER_ENTER:
+            delToken(pm);
+            goto again;
+        case MATHER_SEMICOLON:
+            break;
+        default: {
+            default_:
+            addEnter(pm);
+            break;
+        }
+    }
+
+    st = makeTryStatement();
+    st->u.try_branch.try = try_st;
+    st->u.try_branch.except_list = sl;
+    st->u.try_branch.else_list = else_st;
+    st->u.try_branch.finally = finally_st;
+    addStatementToken(TRY_BRANCH, st, pm);
+    return;
+
+    error_:
+    freeStatement(try_st);
+    freeStatement(else_st);
+    freeStatement(finally_st);
+    freeStatementList(sl);
+    return;
+}
+
 void parserDef(PASERSSIGNATURE){
     struct Statement *st = NULL, *name_tmp = NULL, *code_tmp = NULL;
     delToken(pm);
@@ -382,8 +461,10 @@ void parserCode(PASERSSIGNATURE){
     }
     code_token = popAheadToken(pm);
     writeLog_(pm->grammar_debug, GRAMMAR_DEBUG, "parserCode: call parserCommandList success\n", NULL);
-    if (!checkToken_(pm, MATHER_RC))
+    if (!checkToken_(pm, MATHER_RC)) {
+        syntaxError(pm, syntax_error, 1, "Don't get the }");
         goto error_;
+    }
 
     return_:
     addStatementToken(CODE, st, pm);
@@ -391,9 +472,7 @@ void parserCode(PASERSSIGNATURE){
     return;
 
     error_:
-    syntaxError(pm, syntax_error, 1, "Don't get the }");
     freeToken(code_token, true, true);
-    freeStatement(st);
 }
 
 /**

+ 2 - 1
parser/syntax.c

@@ -279,7 +279,8 @@ int getMatherStatus(LexFile *file, LexMathers *mathers, FILE *debug) {
         charMatherMacro(MATHER_COLON, ':');
         charMatherMacro(MATHER_SEMICOLON, ';');
 
-        strMatherMacro(MATHER_Link, "->");
+        strMatherMacro(MATHER_LINK, "->");
+        strMatherMacro(MATHER_RAISE, "raise");
 
         status = checkoutMather(mathers, MATHER_MAX, debug);
         writeLog_(debug, LEXICAL_DEBUG, "get status: %d\n", status);

+ 16 - 0
src/run.c

@@ -32,6 +32,9 @@ Result runStatement(INTER_FUNCTIONSIG) {
         case while_branch:
             result = whileBranch(CALL_INTER_FUNCTIONSIG(st, var_list));
             break;
+        case try_branch:
+            result = tryBranch(CALL_INTER_FUNCTIONSIG(st, var_list));
+            break;
         case break_cycle:
             result = breakCycle(CALL_INTER_FUNCTIONSIG(st, var_list));
             break;
@@ -47,6 +50,9 @@ Result runStatement(INTER_FUNCTIONSIG) {
         case return_code:
             result = returnCode(CALL_INTER_FUNCTIONSIG(st, var_list));
             break;
+        case raise_code:
+            result = raiseCode(CALL_INTER_FUNCTIONSIG(st, var_list));
+            break;
         default:
             setResult(&result, true, inter);
             break;
@@ -149,6 +155,16 @@ bool cycleBranchSafeInterStatement(Result *result, INTER_FUNCTIONSIG){
     return true;
 }
 
+bool tryBranchSafeInterStatement(Result *result, INTER_FUNCTIONSIG){
+    *result = iterStatement(CALL_INTER_FUNCTIONSIG(st, var_list));
+    if (result->type == not_return || result->type == operation_return){
+        return false;
+    }
+    if (result->type == restart_return)
+        result->times--;
+    return true;
+}
+
 bool functionSafeInterStatement(Result *result, INTER_FUNCTIONSIG){
     *result = iterStatement(CALL_INTER_FUNCTIONSIG(st, var_list));
     if (result->type == error_return){

+ 54 - 0
src/runbranch.c

@@ -133,6 +133,46 @@ Result whileBranch(INTER_FUNCTIONSIG) {
     return result;
 }
 
+Result tryBranch(INTER_FUNCTIONSIG) {
+    Result result, try_result, except_result, else_tmp, finally_tmp;
+    StatementList *except_list = st->u.try_branch.except_list;
+    bool set_result = true;
+
+    var_list = pushVarList(var_list, inter);
+    if (!tryBranchSafeInterStatement(&try_result, CALL_INTER_FUNCTIONSIG(st->u.try_branch.try, var_list))){
+        goto not_except;
+    }
+    if (except_list == NULL) {
+        result = try_result;
+        set_result = false;
+        goto not_else;
+    }
+    if (except_list->var != NULL)
+        assCore(except_list->var, try_result.value, inter, var_list);
+    if (tryBranchSafeInterStatement(&except_result, CALL_INTER_FUNCTIONSIG(except_list->code, var_list))){
+        result = except_result;
+        set_result = false;
+    }
+    goto not_else;
+
+    not_except:
+    if (st->u.try_branch.else_list != NULL && tryBranchSafeInterStatement(&else_tmp, CALL_INTER_FUNCTIONSIG(st->u.try_branch.else_list, var_list))){
+        set_result = false;
+        result = else_tmp;
+    }
+
+    not_else:
+    if (st->u.try_branch.finally != NULL && tryBranchSafeInterStatement(&finally_tmp, CALL_INTER_FUNCTIONSIG(st->u.try_branch.finally, var_list))){
+        set_result = false;
+        result = finally_tmp;
+    }
+
+    var_list = popVarList(var_list, inter);
+    if (set_result)
+        setResult(&result, true, inter);
+    return result;
+}
+
 Result breakCycle(INTER_FUNCTIONSIG){
     Result result, times;
     int times_int = 0;
@@ -215,3 +255,17 @@ Result returnCode(INTER_FUNCTIONSIG){
     result.type = function_return;
     return result;
 }
+
+Result raiseCode(INTER_FUNCTIONSIG){
+    Result result;
+    if (st->u.raise_code.value == NULL) {
+        setResult(&result, true, inter);
+        goto set_result;
+    }
+    if (operationSafeInterStatement(&result, CALL_INTER_FUNCTIONSIG(st->u.raise_code.value, var_list)))
+        return result;
+
+    set_result:
+    result.type = error_return;
+    return result;
+}

+ 21 - 1
src/statement.c

@@ -65,6 +65,16 @@ Statement *makeWhileStatement(){
     return tmp;
 }
 
+Statement *makeTryStatement(){
+    Statement *tmp = makeStatement();
+    tmp->type = try_branch;
+    tmp->u.try_branch.except_list = NULL;
+    tmp->u.try_branch.else_list = NULL;
+    tmp->u.try_branch.finally = NULL;
+    tmp->u.try_branch.try = NULL;
+    return tmp;
+}
+
 Statement *makeBreakStatement(Statement *times){
     Statement *tmp = makeStatement();
     tmp->type = break_cycle;
@@ -96,7 +106,14 @@ Statement *makeRestartStatement(Statement *times){
 Statement *makeReturnStatement(Statement *value){
     Statement *tmp = makeStatement();
     tmp->type = return_code;
-    tmp->u.rego_if.times = value;
+    tmp->u.return_code.value = value;
+    return tmp;
+}
+
+Statement *makeRaiseStatement(Statement *value){
+    Statement *tmp = makeStatement();
+    tmp->type = raise_code;
+    tmp->u.raise_code.value = value;
     return tmp;
 }
 
@@ -173,6 +190,9 @@ void freeStatement(Statement *st){
             case return_code:
                 freeStatement(st->u.return_code.value);
                 break;
+            case raise_code:
+                freeStatement(st->u.raise_code.value);
+                break;
             default:
                 break;
         }