void factor() /* 인자 */ { TknKind kd = code.kind; if (syntaxChk_mode) { /* 구문 chk 시 */ switch (kd) { case Not: case Minus: case Plus: code = nextCode(); factor(); stk.pop(); stk.push(1.0); break; case Lparen: expression('(', ')'); break; case IntNum: case DblNum: stk.push(1.0); code = nextCode(); break; case Gvar: case Lvar: (void)get_memAdrs(code); stk.push(1.0); break; case Toint: case Input: sysFncExec_syntax(kd); break; case Fcall: fncCall_syntax(code.symNbr); break; case EofLine: err_exit("식이 바르지 않습니다."); default: err_exit("식 오류:", kind_to_s(code)); /* a + = 등에서 발생 */ } return; } switch (kd) { /* 실행시 */ case Not: case Minus: case Plus: code = nextCode(); factor(); /* 다음 값을 획득 */ if (kd == Not) stk.push(!stk.pop()); /* !처리한다 */ if (kd == Minus) stk.push(-stk.pop()); /* -처리한다 */ break; /* 단항 +는 아무것도 하지 않는다 */ case Lparen: expression('(', ')'); break; case IntNum: case DblNum: stk.push(code.dblVal); code = nextCode(); break; case Gvar: case Lvar: chk_dtTyp(code); /* 값 설정을 마친 변수인가 */ stk.push(Dmem.get(get_memAdrs(code))); break; case Toint: case Input: sysFncExec(kd); break; case Fcall: fncCall(code.symNbr); break; } }
void factor(void) /* 因子関連処理 */ { SymTbl *tp; TknKind kd = token.kind; switch (kd) { case Plus: case Minus: case Not: case Incre: case Decre: /* + - ! ++ -- */ token = nextTkn(); factor(); if (kd==Incre || kd==Decre) to_leftVal(); /* 左辺値にする */ gencode_Unary(kd); /* 単項命令生成 */ break; case IntNum: /* 整数定数 */ gencode2(LDI, token.intVal); token = nextTkn(); break; case Lparen: /* ( 式 ) */ expr_with_chk('(', ')'); break; case Printf: case Input: case Exit: if (kd != Input) err_ss("void型関数が式の中で使われている", token.text); sys_fncCall(kd); /* 組込関数呼出 */ break; case Ident: /* 識別子 */ tp = search(token.text); /* 記号表位置 */ switch (tp->nmKind) { case fncId: case protId: /* 関数呼出 */ if (tp->dtTyp == VOID_T) err_ss("void型関数が式の中で使われている", tp->name); fncCall(tp); /* 関数呼出 */ break; case varId: case paraId: /* 変数 */ if (tp->aryLen == 0) { /* 単純変数 */ gencode3(LOD, b_flg(tp), tp->adrs); token = nextTkn(); } else { /* 配列 */ token = nextTkn(); if (token.kind == '[') { /* []がある */ gencode3(LDA, b_flg(tp), tp->adrs); /* 配列名アドレス */ expr_with_chk('[', ']'); /* 添字を取得 */ gencode2(LDI, INTSIZE); /* 1要素サイズ */ gencode1(MUL); /* 添字×1要素サイズ */ gencode1(ADD); /* それを配列アドレスに加算 */ gencode1(VAL); /* 内容取出 */ } else { /* []がない */ err_s("添字指定がない"); /* 処理は続行 */ } } if (token.kind==Incre || token.kind==Decre) { /* 後置++ */ to_leftVal(); /* 左辺値(アドレス表現)にする */ if (token.kind==Incre) {gencode1(INC); gencode2(LDI,1); gencode1(SUB);} else {gencode1(DEC); gencode2(LDI,1); gencode1(ADD);} token = nextTkn(); } break; } break; default: err_ss("不正な記述", token.text); } }
/* この関数内のラベル処理(飛先処理)の明快さのために以下のマクロを使用する */ #define UPLABEL(pos) pos=nextCodeCt() /* 上ジャンプ用ラベル機能 */ #define JMP_UP(pos) gencode2(JMP,pos) /* JMPでUPLABELへ */ #define JPT_UP(pos) gencode2(JPT,pos) /* JPTでUPLABELへ */ #define JMP_DOWN(pos) pos=gencode2(JMP,0) /* JMPでDWNLABELへ */ #define JPF_DOWN(pos) pos=gencode2(JPF,0) /* JPFでDWNLABELへ */ #define DWNLABEL(pos) backPatch(pos,nextCodeCt()) /* 下ジャンプ用ラベル機能 */ void statement(void) /* 文の処理 */ { TknKind kd; SymTbl *tp; DtType ret_typ = fncPt->dtTyp; int i, val; int LB_TOP, LB_EXP2, LB_EXP3, LB_BODY, LB_ELSE, LB_END, LB_TBL; kd = token.kind; if (kd==While || kd==Do || kd==Switch) continue_break_begin(kd); switch (kd) { case Break: if (loopNest_ct == 0) err_s("不正なbreak"); else { gencode2(JMP, NO_FIX_BREAK_ADRS); /* 該当末尾位置へ */ loopNest[loopNest_ct].break_flg = TRUE; /* breakありを記憶 */ } token = chk_nextTkn(nextTkn(), ';'); /* ; のはず */ break; case Continue: gencode2(JMP, get_loopTop()); /* ループ開始行へジャンプ */ token = chk_nextTkn(nextTkn(), ';'); /* ; のはず */ break; case Case: token = nextTkn(); get_const(NULL); /* 定数判定準備 */ expr_with_chk(0, ':'); /* [式]の処理 */ if (!get_const(&val)) err_s("case式が定数式でない"); else if (swchNest_ct == 0) err_s("対応するswitch文がない"); else { for (i=swchNest[swchNest_ct].startCaseList; i<=caseList_ct; i++) { if (caseList[i].value == val) { err_s("case式の値が重複している"); break; } } incVar(&caseList_ct, CASE_SIZ, "case句が%d個を超えました。"); caseList[caseList_ct].value = val; /* case値設定 */ caseList[caseList_ct].adrs = nextCodeCt(); /* 対応番地設定 */ } statement(); /* 文の処理 */ break; case Default: if (swchNest_ct == 0) err_s("対応するswitch文がない"); else if (swchNest[swchNest_ct].def_adrs != -1) err_s("defaultが重複している"); else swchNest[swchNest_ct].def_adrs = nextCodeCt(); /* 番地設定 */ token = chk_nextTkn(nextTkn(), ':'); /* : のはず */ statement(); /* 文の処理 */ break; case For: /*[式1]*/ token = chk_nextTkn(nextTkn(), '('); /* ( のはず */ if (token.kind == ';') token = nextTkn(); /* 式1なし */ else { expr_with_chk(0, ';'); /* [式1]の処理 */ remove_val(); /* 式値不要 */ } /*[式2]*/ UPLABEL(LB_EXP2); /* ←┐ */ if (token.kind == ';') { /* │式2なし */ gencode2(LDI, 1); /* │真(1)にする */ token = nextTkn(); /* │ */ } else { /* │ */ expr_with_chk(0, ';'); /* │[式2]の処理 */ } /* │ */ JPF_DOWN(LB_END); /* ─┼┐ false時 */ JMP_DOWN(LB_BODY); /* ─┼┼┐true時 */ /* │││ */ /*[式3]*/ /* │││ */ continue_break_begin(kd); /* │││ */ UPLABEL(LB_EXP3); /* ←┼┼┼┐ */ if (token.kind == ')') /* ││││ */ token = nextTkn(); /* ││││式3なし */ else { /* ││││ */ expr_with_chk(0, ')'); /* ││││[式3]の処理 */ remove_val(); /* ││││式値不要 */ } /* ││││ */ JMP_UP(LB_EXP2); /* ─┘│││ */ /* │││ */ /*[本体]*/ /* │││ */ DWNLABEL(LB_BODY); /* ←─┼┘│ */ statement(); /* │ │[文]の処理 */ JMP_UP(LB_EXP3); /* ──┼─┘繰り返し */ /* │ */ /*[末尾]*/ /* │ */ DWNLABEL(LB_END); /* ←─┘終端 */ break; case If: token = nextTkn(); expr_with_chk('(', ')'); /* [式]の処理 */ JPF_DOWN(LB_ELSE); /* ─┐ false時 */ statement(); /* │ [文1]の処理 */ if (token.kind != Else) { /* │ */ DWNLABEL(LB_ELSE); /* ←┘elseない時の終端 */ break; /* │ */ } /* │elseある時 */ JMP_DOWN(LB_END); /* ─┼┐ */ DWNLABEL(LB_ELSE); /* ←┘│ */ token = nextTkn(); /* │ */ statement(); /* │[文2]の処理 */ DWNLABEL(LB_END); /* ←─┘ */ break; case While: token = nextTkn(); UPLABEL(LB_TOP); /* ←┐ */ expr_with_chk('(', ')'); /* │ [式]の処理 */ JPF_DOWN(LB_END); /* ─┼┐false時 */ statement(); /* ││[文]の処理 */ JMP_UP(LB_TOP); /* ─┘│繰り返し */ DWNLABEL(LB_END); /* ←─┘ */ break; case Do: token = nextTkn(); UPLABEL(LB_TOP); /* ←┐ */ statement(); /* │[文]の処理 */ if (token.kind == While) { /* │ */ token = nextTkn(); /* │ */ expr_with_chk('(', ')'); /* │[式]の処理 */ token = chk_nextTkn(token, ';'); /* │; のはず */ JPT_UP(LB_TOP); /* ─┘true時 */ } else { err_s("do終端のwhileがない"); } break; case Switch: token = nextTkn(); expr_with_chk('(', ')'); /* [式]の処理 */ JMP_DOWN(LB_TBL); /* ─┐ テーブル処理へ */ swch_begin(); /* │ */ statement(); /* case,default文の処理. */ JMP_DOWN(LB_END); /* ─┼┐末尾へ */ DWNLABEL(LB_TBL); /* ←┘│ */ swch_end(); /* │テーブル処理 */ DWNLABEL(LB_END); /* ←─┘ */ break; case Return: token = nextTkn(); if (token.kind == ';') { /* 戻値なし */ if (ret_typ != VOID_T) err_s("return文に戻り値がない"); } else { /* 戻値あり */ expression(); /* 戻値作成 */ if (ret_typ == VOID_T) err_s("void型関数に値を返すreturn文がある"); } gencode2(JMP, NO_FIX_RET_ADRS); /* 関数出口処理へ */ token = chk_nextTkn(token, ';'); /* ; のはず */ break; case Printf: case Exit: /* void型組込関数 */ sys_fncCall(kd); token = chk_nextTkn(token, ';'); /* printf() + b; を防止 */ break; case Input: /* 非void型組込関数 */ expr_with_chk(0, ';'); /* 通常の式解析 */ remove_val(); /* 式値不要 */ break; case Incre: case Decre: /* ++var --var */ expr_with_chk(0, ';'); remove_val(); /* 式値不要 */ break; case Ident: /* 識別子(関数か変数) */ tp = search(token.text); /* 記号表位置 */ if ((tp->nmKind==fncId || tp->nmKind==protId) && tp->dtTyp==VOID_T) { fncCall(tp); /* void型関数はここで処理 */ token = chk_nextTkn(token, ';'); /* ; のはず */ } else { expr_with_chk(0, ';'); /* 通常の式解析 */ remove_val(); /* 式値不要 */ } break; case Lbrace: /* 複合文{} */ block(0); /* 0:非関数ブロック */ break; case Semicolon: /* 空文,forの実行文等で出現 */ token = nextTkn(); break; case EofTkn: /* 最後の } を忘れた場合などに発生 */ err_s("意図しない終了。'}'不足? "); exit(1); default: err_ss("不正な記述", token.text); token = nextTkn(); } if (kd==For || kd==While || kd==Do || kd==Switch) continue_break_end(); }
void statement() /* 문 */ { CodeSet save; int top_line, end_line, varAdrs; double wkVal, endDt, stepDt; if (Pc>maxLine || exit_Flg) return; /* 프로그램 종료 */ code = save = firstCode(Pc); top_line = Pc; end_line = code.jmpAdrs; /* 제어 범위의 시작과 끝 */ if (code.kind == If ) end_line = endline_of_If(Pc); /* if문일 때의 끝 */ switch (code.kind) { case If: // if if (get_expression(If, 0)) { /* 참(TRUE)이면 */ ++Pc; block(); Pc = end_line + 1; /* 실행하고 */ return; /* 종료 */ } Pc = save.jmpAdrs; /* 다음으로 */ // elif while (lookCode(Pc) == Elif) { save = firstCode(Pc); code = nextCode(); if (get_expression()) { /* 참(TRUE)이면 */ ++Pc; block(); Pc = end_line + 1; /* 실행하고 */ return; /* 종료 */ } Pc = save.jmpAdrs; /* 다음으로 */ } // else if (lookCode(Pc) == Else) { /* else를 */ ++Pc; block(); Pc = end_line + 1; /* 실행하고 */ return; /* 종료 */ } // end ++Pc; break; case While: for (;;) { /* */ if (!get_expression(While, 0)) break; /* false 종료 */ ++Pc; block(); /* [실행] */ if (break_Flg || return_Flg || exit_Flg) { /* */ break_Flg = false; break; /* 중단 */ } /* */ Pc = top_line; code = firstCode(Pc); /* 맨 앞으로 */ } /* */ Pc = end_line + 1; /* */ break; case For: /* for 제어변수, 초깃값, 최종값, 증분식 */ save = nextCode(); varAdrs = get_memAdrs(save); /* 제이변수 주소 구하기 */ expression('=', 0); /* 초깃값 */ set_dtTyp(save, DBL_T); /* 형 확정 */ Dmem.set(varAdrs, stk.pop()); /* 초깃값을 설정 */ endDt = get_expression(To, 0); /* 최종값을 보존 */ /* 증분값을 보존 */ if (code.kind == Step) stepDt = get_expression(Step, 0); else stepDt = 1.0; for (;; Pc=top_line) { /* */ if (stepDt >= 0) { /* 증가 루프 */ if (Dmem.get(varAdrs) > endDt) break; /* 거짓이면 종료 */ } else { /* 감소 루프 */ if (Dmem.get(varAdrs) < endDt) break; /* 거짓이면 종료 */ } /* */ ++Pc; block(); /* [ 실행 ] */ if (break_Flg || return_Flg || exit_Flg) { /* */ break_Flg = false; break; /* 중단 */ } /* */ Dmem.add(varAdrs, stepDt); /* 값 갱신 */ } /* */ Pc = end_line + 1; /* */ break; case Fcall: /* 대입이 없는 함수 호출 */ fncCall(code.symNbr); (void)stk.pop(); /* 반환 값 불필요 */ ++Pc; break; case Func: /* 함수 정의는 건너뀜 */ Pc = end_line + 1; break; case Print: case Println: sysFncExec(code.kind); ++Pc; break; case Gvar: case Lvar: /* 대입문 */ varAdrs = get_memAdrs(code); expression('=', 0); set_dtTyp(save, DBL_T); /* 대입할 때 형 확정*/ Dmem.set(varAdrs, stk.pop()); ++Pc; break; case Return: wkVal = returnValue; code = nextCode(); if (code.kind!='?' && code.kind!=EofLine) /* '식'이 있으면 반환 값을 계산 */ wkVal = get_expression(); post_if_set(return_Flg); /* ?가 있으면 처리 */ if (return_Flg) returnValue = wkVal; if (!return_Flg) ++Pc; break; case Break: code = nextCode(); post_if_set(break_Flg); /* ? 가 있으면 처리 */ if (!break_Flg) ++Pc; break; case Exit: code = nextCode(); exit_Flg = true; break; case Option: case Var: case EofLine: /* 실행 시는 무시 */ ++Pc; break; default: err_exit("잘못된 기술입니다: ", kind_to_s(code.kind)); } }