void fncChk(SymTbl *f1, SymTbl *f2) /* 関数重複チェック */ { if (f1->nmKind==fncId && f2->nmKind==fncId) { /* 両方が関数本体 */ err_ss("関数が再定義されている", f1->name); return; } /* 片方or両方が関数プロトタイプ */ if (f1->dtTyp != f2->dtTyp || f1->args != f2->args) { err_ss("関数プロトタイプが不一致", f1->name); return; } return; }
int compile(char *fname) /* コンパイル */ { initChTyp(); /* 文字種表 */ gencode2(CALL, -1); /* main関数呼出。番地-1は仮設定 */ gencode1(STOP); /* プログラム終了 */ fileOpen(fname); token = nextTkn(); while (token.kind != EofTkn) { switch (token.kind) { case Int: case Void: /* 変数か関数 */ set_type(); set_name(); /* 型名と名前を格納 */ if (token.kind == '(') fncDecl(); else varDecl(); /* 関数,変数宣言 */ break; case Semicolon: token = nextTkn(); /* 何もせず次へ */ break; default: err_ss("構文エラー", token.text); token = nextTkn(); } } if (err_ct == 0) backPatch_callAdrs(); /* 関数呼出未定番地を後埋 */ *INT_P(mem_adrs(0)) = mallocG(0); /* 静的領域サイズを0番地に格納 */ if (err_ct > 0) fprintf(stderr, "%d個のエラーが発生しました。\n", err_ct); return err_ct == 0; /* エラーなしなら真 */ }
void set_name(void) /* 名前設定 */ { if (token.kind == Ident) { tmpTb.name = s_malloc(token.text); /* 名前設定 */ token = nextTkn(); } else { err_ss("記述が不適切", token.text); tmpTb.name = "tmp$name1"; /* ありえない名前を仮設定 */ } }
void set_type(void) /* 型設定 */ { tmpTb.aryLen = tmpTb.adrs = tmpTb.args = 0; /* クリアしておく */ tmpTb.level = blkNest; /* 0:大域 1:局所 */ switch (token.kind) { case Int: tmpTb.dtTyp = INT_T; break; case Void: tmpTb.dtTyp = VOID_T; break; default: err_ss("型指定誤り", token.text); tmpTb.dtTyp = INT_T; /* Intとみなす */ } token = nextTkn(); }
void fncDecl(void) /* 関数宣言 */ { SymTbl *f1; localAdrs = START_LocalAdrs; /* 局所領域割付けカウンタ初期化 */ f1 = search_name(tmpTb.name); if (f1!=NULL && f1->nmKind!=fncId && f1->nmKind!=protId) { err_ss("識別子が重複している", f1->name); f1 = NULL; } fncPt = enter(tmpTb, fncId); /* 記号表に登録 */ token = nextTkn(); localTBL_open(); /* 局所用記号表を用意 */ switch (token.kind) { /* 引数処理 */ case Void: token = nextTkn(); break; /* 引数 (void) */ case ')': break; /* 引数なし () */ default: /* 引数あり */ for (;;) { set_type(); set_name(); enter(tmpTb, paraId); /* 引数登録 */ ++(fncPt->args); /* 引数個数を+1 */ if (token.kind != ',') break; /* 宣言終了 */ token = nextTkn(); /* 次の引数 */ } } token = chk_nextTkn(token, ')'); /* ')'のはず */ if (token.kind == ';') fncPt->nmKind = protId; /* 関数プロトタイプ */ set_adrs(fncPt); /* 関数入口番地と引数アドレス設定 */ if (f1 != NULL) fncChk(f1, fncPt); /* 関数の正しさを確認 */ switch (token.kind) { case ';': token = nextTkn(); break; /* プロトタイプ */ case '{': if (IS_MAIN(fncPt)) set_main(); /* main関数処理 */ fncDecl_begin(); /* 関数入口処理 */ block(1); /* 関数本体処理 */ fncDecl_end(); /* 関数出口処理 */ break; default: err_s("関数の ; または { がない"); exit(1); } localTBL_close(fncPt); /* 局所用記号表を解消 */ del_fncTable(f1, fncPt); /* 重複登録なら解消 */ fncPt = NULL; /* 関数処理終了 */ }
void fncCall(SymTbl *fp) /* 関数呼出 */ { int argCt = 0; token = chk_nextTkn(nextTkn(), '('); /* ( のはず */ if (token.kind != ')') { /* 引数がある */ for (;;) { expression(); /* 引数式の処理 */ ++argCt; /* 引数個数 */ if (token.kind != ',') break; /* , なら引数が続く */ token = nextTkn(); } } token = chk_nextTkn(token, ')'); /* ) のはず */ if (argCt != fp->args) /* 引数個数チェック */ err_ss("関数の引数個数が不一致", fp->name); gencode2(CALL, fp->adrs); /* 関数呼出 */ }
static void offtab_write_window(struct offtab *offtab) { size_t window_bytes; off_t window_pos; assert(offtab->ot_mode == OFFTAB_MODE_WRITE); offtab_compute_window_position(offtab, offtab->ot_window_start, &window_bytes, &window_pos); const ssize_t n_written = pwrite(offtab->ot_fd, offtab->ot_window, window_bytes, window_pos); if (n_written == -1) err_ss(1, "write initial offset table"); assert(n_written >= 0); if ((size_t)n_written != window_bytes) errx_ss(1, "partial write of initial offset bytes: %zu <= %zu", (size_t)n_written, window_bytes); }
void set_aryLen(void) /* 配列サイズ設定 */ { tmpTb.aryLen = 0; if (token.kind != '[') return; /* 配列でない */ token = nextTkn(); if (token.kind == ']') { /* []である */ err_s("添字指定がない"); token = nextTkn(); tmpTb.aryLen = 1; return; /* 1だったことにする */ } get_const(NULL); /* 定数判定準備 */ expr_with_chk(0, ']'); /* 添字を取得 */ if (get_const(&(tmpTb.aryLen))) { /* 定数式なら */ if (tmpTb.aryLen <= 0) { tmpTb.aryLen = 1; err_s("不正な添字"); /* 1だったことにする */ } } else { err_s("配列幅指定が整数定数式でない"); } if (token.kind == '[') { err_ss("多次元配列は宣言できない", token.text); } }
Token nextTkn(void) /* 次のトークン */ { Token tkn = {NulKind, "", 0}; int errF = FALSE, num, ct, n; char *p = tkn.text, *p_end31 = p+ID_SIZ; char lite[100+1], *lite_end = lite+100; static int ch = ' '; /* 前回文字を保持するためstatic */ while (isspace(ch)) { ch = nextCh(); } /* 空白読み捨て */ if (ch == EOF) { tkn.kind = EofTkn; return tkn; } /* EOF */ switch (ctyp[ch]) { case Letter: for ( ; ctyp[ch]==Letter || ctyp[ch]==Digit; ch = nextCh()) { if (p < p_end31) *p++ = ch; /* 識別子は最大31文字まで有効 */ } *p = '\0'; break; case Digit: /* 数値定数 */ for (num=0; ctyp[ch]==Digit; ch = nextCh()) { num = num*10 + (ch-'0'); } tkn.kind = IntNum; tkn.intVal = num; /* 値格納 */ sprintf(tkn.text, "%d", num); /* エラー表示用 */ break; case SngQ: /* 文字定数 */ for (ct=0,ch=nextCh(); ch!=EOF && ch!='\n' && ch!='\''; ch=nextCh()) { if (ch == '\\') { if ((ch=nextCh()) == 'n') ch = '\n'; } /* \nの処理 */ if (++ct == 1) tkn.intVal = ch; /* 文字定数値格納 */ } if (ct != 1) errF = TRUE; if (ch == '\'') ch = nextCh(); else errF = TRUE; if (errF) err_s("不正な文字定数"); tkn.kind = IntNum; /* 以降は整数定数として扱う */ sprintf(tkn.text, "'%c'", tkn.intVal); /* エラー表示用 */ break; case DblQ: /* 文字列定数 */ p = lite; ch = nextCh(); while (ch!=EOF && ch!='\n' && ch!='"') { if (errF) { ch = nextCh(); continue; } if ((n=is_kanji(ch)) > 0) { while (n--) { if (p < lite_end) P_SET(); else errF = TRUE; } continue; } if (ch == '\\') { if ((ch=nextCh()) == 'n') ch = '\n'; } /* \nの処理 */ if (p < lite_end) P_SET(); else errF = TRUE; } *p = '\0'; if (errF) err_s("文字列リテラルが長すぎる"); if (ch == '"') ch = nextCh(); else err_s("文字列リテラルが閉じていない"); tkn.kind = String; tkn.intVal = mallocS(lite); /* 文字列をメモリに確保し番地を格納 */ tkn.text[0] = '\"'; /*以下エラー表示用に文字列確保*/ strncat(tkn.text+1, lite, 29); if (strlen(tkn.text) <= 29) strcat(tkn.text, "\""); break; default: /* 記号 */ if (ch<0 || 127<ch) err_s("不正な文字が使われている"); if ((n=is_kanji(ch)) > 0) { while (n--) P_SET(); } else P_SET(); if (is_ope2(*(p-1), ch)) P_SET(); /* == など */ *p = '\0'; } if (tkn.kind == NulKind) tkn = set_kind(tkn); /* 種別設定 */ if (tkn.kind == Others) err_ss("不正なトークン", tkn.text); return tkn; }
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(); }