Advertisement
Guest User

Untitled

a guest
Jun 16th, 2019
81
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 20.78 KB | None | 0 0
  1. // ci0.c 2013.10.03 Hatada
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5.  
  6. //----------------------------------------------------------------------------//
  7. // 字句解析 //
  8. //----------------------------------------------------------------------------//
  9. #define SIZETOKEN 1000 // トークン配列のサイズ
  10. #define OPERATOR2 "== != <= >= |= += -= *= /= >> << ++ -- && || -> "
  11.  
  12. int fToken, fTrace, fCode; // コマンド引数オプション
  13. char *Token[SIZETOKEN]; // トークン配列
  14. int nToken; // トークン数
  15. int tix = -1; //カレントトークン.構文解析で使用.エラー関数共用のためここに置く
  16.  
  17. void error(const char *format, ...) {
  18. vfprintf(stderr, format, (char*)&format + sizeof(char*));
  19. if (tix >= 0) fprintf(stderr, "\n Token[%d] = \"%s\"\n", tix, Token[tix]);
  20. exit(1);
  21. } // 移植性のために、一般には stdarg.h のマクロを使う方がよい。
  22. int isAlpha(int c) { return (isalpha(c) || c == '_'); }
  23. int isAlNum(int c) { return isAlpha(c) || isdigit(c); }
  24. int isKanji(int c) { return (c>=0x81 && c<=0x9F) || (c>=0xE0 && c<=0xFC); }
  25.  
  26. void lex(const char *srcfile) {
  27. char linebuf[256], buf[128], op2[4], *p, *pBgn;
  28. FILE *fpSrc = fopen(srcfile, "r");
  29. if (fpSrc == NULL) error("file '%s' can't open", srcfile);
  30. while (fgets(linebuf, sizeof(linebuf), fpSrc) != NULL) {
  31. for (p = linebuf; *p != '\0'; ) { // 一行分の字句解析
  32. if (*p <= ' ') { p++; continue; } // 空白文字をスキップする
  33. if (p[0]=='/' && p[1]=='/') break; // コメント. 行末までスキップ
  34. pBgn = p;
  35. if (*p == '"') { // 文字列. escape文字,2byte文字のとき2byte目をスキップ
  36. for (p++; *p != '\0' && *p != '"'; p++)
  37. if (*p == '\\' || isKanji(*p)) p++;
  38. if (*p++ != '"') error("後ろの引用符がありません<%s>", pBgn);
  39. } else if (isdigit(*p)) { // 数値(10進)
  40. for (p++; *p != '\0' && isdigit(*p); p++) ;
  41. } else if (strncmp(pBgn,"char*",5) == 0) { // char*
  42. p += 5;
  43. } else if (isAlpha(*p)) { // 識別子, 予約語
  44. for (p++; *p != '\0' && isAlNum(*p); ) p++;
  45. } else { // 演算子
  46. sprintf(op2, "%c%c ", p[0], p[1]);
  47. p += strstr(OPERATOR2, op2) != NULL ? 2 : 1;
  48. }
  49. sprintf(buf, "%.*s", p - pBgn, pBgn);
  50. if (nToken == SIZETOKEN) error("トークン配列オーバフロー");
  51. Token[nToken++] = strdup(buf);
  52. if (fToken) printf(strchr(";{}",*buf)!=NULL ? "%s\n" : "%s ", buf);
  53. }
  54. }
  55. fclose(fpSrc);
  56. }
  57.  
  58. //----------------------------------------------------------------------------//
  59. // 名前管理 //
  60. //----------------------------------------------------------------------------//
  61. #define SIZEGLOBAL 1000 // グローバル名前管理表のサイズ
  62. #define SIZELOCAL 1000 // ローカル名前管理表のサイズ
  63. enum { NM_VAR = 0x01, NM_FUNC = 0x02 }; // 名前の種別
  64. enum { AD_DATA = 0, AD_STACK, AD_CODE }; // アドレスの種別
  65.  
  66. typedef struct _Name {
  67. int type; // NM_VAR: 変数、NM_FUNC: 関数
  68. char *dataType, *name; // データ型, 変数名または関数名
  69. int addrType, address; // アドレスの種別, 相対アドレス
  70. } Name;
  71.  
  72. Name *GName[SIZEGLOBAL], *LName[SIZELOCAL]; // 名前管理表.
  73. int nGlobal, nLocal; // 同上現在の登録数
  74.  
  75. // 関数または変数情報を名前管理表に登録する
  76. Name *appendName(int nB, int type, char *dataType, char *name, int addrType, int addr) {
  77. Name nm = { type, dataType, name, addrType, addr };
  78. Name *pNew = calloc(1, sizeof(Name));
  79. if (pNew == NULL) error("appendName: メモリが足りません");
  80. memcpy(pNew, &nm, sizeof(Name));
  81. if (nB == 0 && nGlobal < SIZEGLOBAL-1) GName[nGlobal++] = pNew;
  82. else if (nB == 1 && nLocal < SIZELOCAL-1) LName[nLocal++] = pNew;
  83. else error("appendName: 引数エラーまたは配列オーバーフロー");
  84. return pNew; // 新しいエントリのアドレスを返す
  85. }
  86.  
  87. // 指定された名前表から指定された名前を探す
  88. Name *getNameFromTable(int nB, int type, char *name, int fErr) {
  89. int n;
  90. int nEntry = nB==0 ? nGlobal : nLocal;
  91. for (n = 0; n < nEntry; n++) {
  92. Name *e = nB==0 ? GName[n] : LName[n];
  93. if (strcmp(e->name,name) == 0 && (e->type&type) != 0) return e;
  94. }
  95. if (fErr && nB==0) error("'%s' undeclared", name);
  96. return NULL; // 見つからなかった。
  97. }
  98.  
  99. // 最初にローカル名前表、なければグローバル名前表から指定された名前を探す
  100. Name *getNameFromAllTable(int type, char *name, int fErr) {
  101. Name *pName = getNameFromTable(1, type, name, fErr);
  102. if (pName != NULL) return pName;
  103. return getNameFromTable(0, type, name, fErr);
  104. }
  105.  
  106. //----------------------------------------------------------------------------//
  107. // 構文解析 //
  108. //----------------------------------------------------------------------------//
  109. void expression(int mode); // 式の構文解析
  110. void statement(int locBreak, int locContinue); // 文の構文解析
  111.  
  112. typedef struct _INSTRUCT { int opcode, type, val; } INSTRUCT;
  113. enum { PUSH = 0, ENTRY, POP, MOV, ADD, ADDSP, SUB, MUL, DIV, MOD, RET, CALL,
  114. JZ, JMP, CMP, LT, GT, LE, GE, EQ, NE, FUNC, LABEL };
  115. char *OPCODE[] = { "push", "entry", "pop", "mov", "add", "addsp", "sub", "mul", "div", "mod",
  116. "ret", "call", "jz", "jmp", "cmp", "lt", "gt", "le", "ge", "eq", "ne", "func", "label" };
  117. enum { NIL, IMM, STR, MEM, REF, SKV, SKR, LOC, SP };
  118. char *TYPE[] = { "nil", "int", "str", "mem", "ref", "stack-val", "stack-ref", "loc", "sp" };
  119. #define SIZEDATASECT 1000
  120. enum { VAL=0, ADDR }; // VAL: 変数の内容, ADDR: 変数のアドレス
  121. enum { ST_FUNC=0, ST_GVAR }; // ST_FUNC: 関数定義中, ST_GVAR: 変数宣言中
  122. char *DataSection[SIZEDATASECT]; // グローバル変数、文字列管理配列
  123. int ixData; // データの登録数
  124. int baseSpace; // スタック上の相対アドレス
  125. int numLabel = 1; // ラベルの通し番号(ラベル配列の添え字)
  126. INSTRUCT Inst[1000]; // 命令配列
  127. int nInst = 0; // 命令数
  128. int entryPoint; // 命令を格納するとき main関数の位置を記録しておく
  129.  
  130. int loc() { return numLabel++; }
  131. int is(char *s) { return strcmp(Token[tix],s) == 0; }
  132. int ispp(char *s) { if (is(s)) { tix++; return 1; } return 0; }
  133. int isTypeSpecifier() { return is("void") || is("int") || is("char*"); }
  134. int isFunctionDefinition() { return *Token[tix+2] == '('; }
  135. void skip(char *s) { if (!ispp(s)) error("'%s' expected", s); }
  136.  
  137. void printInst(int n, INSTRUCT *pI) {
  138. printf("%d: %s ", n, OPCODE[pI->opcode]);
  139. if (pI->type == NIL) printf("\n");
  140. else printf(pI->type==STR ? "%s %s\n" : "%s %d\n", TYPE[pI->type], pI->val);
  141. }
  142.  
  143. INSTRUCT *outInst2(int opcode, int type, int val) {
  144. INSTRUCT inst = { opcode, type, val };
  145. return memcpy(&Inst[nInst++], &inst, sizeof(inst));
  146. }
  147. INSTRUCT *outInst(int code){ return outInst2(code, 0,0); }
  148.  
  149. //================================== 式の構文解析 ==============================
  150. /// PrimExpression ::= Identifier | "(" Expr ")" | Constant | FunctionCall
  151. void functionCall() { // 優先順位 #1
  152. int n, nParam, posParam[20], nInstSave, ixDataSave, ixNext, rtn;
  153. char *name = Token[tix++];
  154. Name *pName = getNameFromTable(0, NM_FUNC, name, 1);
  155. skip("(");
  156. // 引数は最後から順にスタックに積むため、まず位置を求める
  157. nInstSave = nInst;
  158. ixDataSave = ixData;
  159. for (nParam = 0; !is(")"); nParam++) {
  160. posParam[nParam] = tix; // 各引数の先頭トークンの位置
  161. expression(VAL);
  162. ispp(",");
  163. }
  164. ixNext = tix + 1; // ")" の次
  165. nInst = nInstSave;
  166. ixData = ixDataSave; // 生成したデータを廃棄する
  167. for (n = nParam; --n >= 0; ) {
  168. tix = posParam[n];
  169. expression(VAL); // 引数を最後から順に評価して、スタックに積む
  170. }
  171. tix = ixNext;
  172. if (pName->address > 0) outInst2(CALL, IMM, pName->address);
  173. else outInst2(CALL, STR, (int)pName->name);
  174. outInst2(ADDSP, IMM, nParam); // スタックポインタ回復
  175. }
  176.  
  177. void primaryExpression(int mode) { // 優先順位 #1
  178. if (isdigit(*Token[tix])) { // Constant 数値
  179. outInst2(PUSH, IMM, atoi(Token[tix++]));
  180. } else if (*Token[tix] == '"') { // Constant 文字列
  181. outInst2(PUSH, STR, (int)Token[tix++]);
  182. } else if (ispp("(")) { // "(" Expr ")"
  183. expression(VAL);
  184. skip(")");
  185. } else if (*Token[tix+1] == '(') { // FuctionCall
  186. functionCall();
  187. } else if (isAlpha(*Token[tix])) { // Identifier
  188. Name *pName = getNameFromAllTable(NM_VAR, Token[tix], 1);
  189. int type = (pName->addrType==AD_STACK)? (mode==VAL?SKV:SKR):(mode==VAL?MEM:REF);
  190. outInst2(PUSH, type, pName->address);
  191. tix++;
  192. } else {
  193. error("primExpr: <%s>", Token[tix]);
  194. }
  195. }
  196.  
  197. /// MulExpression ::= PrimaryExpression ( ("*" | "/" | "%") PrimaryExpression )*
  198. void mulExpression(int mode) { // #4
  199. int fMul=0, fDiv=0;
  200. primaryExpression(mode); // [左辺の値]
  201. while ((fMul=ispp("*")) || (fDiv=ispp("/")) || ispp("%")) {
  202. primaryExpression(mode); // [右辺の値,左辺の値]
  203. outInst(fMul ? MUL : fDiv ? DIV : MOD);
  204. }
  205. }
  206.  
  207. /// AddExpression ::= MulExpression ( ("+" | "-") MulExpression )*
  208. void addExpression(int mode) { // #5
  209. int fAdd;
  210. mulExpression(mode); // [左辺の値]
  211. while ((fAdd=ispp("+")) || ispp("-")) {
  212. mulExpression(mode); // [右辺の値,左辺の値]
  213. outInst(fAdd ? ADD : SUB);
  214. }
  215. }
  216.  
  217. /// RelationalExpression ::= addExpr [("<" | ">" | "<=" | ">=") addExpr]
  218. void relationalExpression(int mode) { // #7 // 符号付き整数に対応
  219. int fLT=0, fGT=0, fLE=0;
  220. addExpression(mode); // [左辺の値]
  221. if ((fLT=ispp("<")) || (fGT=ispp(">")) || (fLE=ispp("<=")) || ispp(">=")){
  222. addExpression(mode); // [右辺の値,左辺の値]
  223. outInst(fLT ? LT : fGT ? GT : fLE ? LE : GE);
  224. }
  225. }
  226.  
  227. /// EqualityExpression ::= RelationalExpr [ ("==" | "!=") RelationalExpr ]
  228. void equalityExpression(int mode) { // #8
  229. int fEQ;
  230. relationalExpression(mode); // [左辺の値]
  231. if ((fEQ=ispp("==")) || ispp("!=")) {
  232. relationalExpression(mode); // [右辺の値,左辺の値]
  233. outInst(fEQ ? EQ : NE);
  234. }
  235. }
  236.  
  237. /// expression ::= [Identifier "="] addExpression
  238. void assign() {
  239. primaryExpression(ADDR); // [左辺変数アドレス]
  240. skip("=");
  241. addExpression(VAL); // [右辺の値,左辺変数アドレス]
  242. outInst(MOV); // Mem[st1] = st0
  243. }
  244.  
  245. void expression(int mode) { // #15
  246. if (strcmp(Token[tix+1],"=") == 0) assign();
  247. else equalityExpression(mode);
  248. }
  249.  
  250. //================================ 文の構文解析 ================================
  251. /// TypeSpecifier ::= "void" | "char*" | "int"
  252. char *typeSpecifier() {
  253. if (!isTypeSpecifier()) error("'%s' not typespecfier", Token[tix]);
  254. return Token[tix++]; // データ型
  255. }
  256.  
  257. /// VarDeclarator ::= Identifier
  258. char *varDeclarator() { return Token[tix++]; } // 変数名または関数名
  259.  
  260. /// VariableDeclaration ::= TypeSpecifier VarDeclarator ["=" Initializer]
  261. /// ("," VarDeclarator ["=" Initializer])*
  262. void variableDeclaration(int status) {
  263. char *varType = typeSpecifier();
  264. do {
  265. char *varName = varDeclarator();
  266. if (status == ST_FUNC) {
  267. appendName(1, NM_VAR, varType, varName, AD_STACK, --baseSpace);
  268. if (is("=")) { tix--; assign(); }
  269. } else {
  270. appendName(0, NM_VAR, varType, varName, AD_DATA, ixData);
  271. if (ispp("=")) DataSection[ixData++] = Token[tix++];
  272. }
  273. } while (ispp(","));
  274. }
  275.  
  276. /// CompoundStatement ::= "{" (Statements)* "}"
  277. void compoundStatement(int locBreak, int locContinue) {
  278. for (skip("{"); tix < nToken && isTypeSpecifier(); skip(";"))
  279. variableDeclaration(ST_FUNC); // ローカル変数の宣言
  280. while (!ispp("}")) statement(locBreak, locContinue);
  281. }
  282.  
  283. /// IfStatement ::= "if" "(" Expression ")" Statement [ "else" Statement ]
  284. void ifStatement(int locBreak, int locContinue) {
  285. int locElse, locEnd;
  286. skip("(");
  287. expression(VAL);
  288. skip(")");
  289. outInst2(JZ, IMM, locElse=loc());
  290. statement(locBreak, locContinue); // then_statement
  291. if (is("else")) outInst2(JMP, IMM, locEnd=loc());
  292. outInst2(LABEL, IMM, locElse);
  293. if (ispp("else")) {
  294. statement(locBreak, locContinue); // else_statement
  295. outInst2(LABEL, IMM, locEnd);
  296. }
  297. }
  298.  
  299. /// WhileStatement ::= "while" "(" Expression ")" Statement
  300. void whileStatement(int locBreak, int locContinue) {
  301. int locExpr, locNext;
  302. outInst2(LABEL, IMM, locExpr=loc());
  303. skip("(");
  304. expression(VAL);
  305. skip(")");
  306. outInst2(JZ, IMM, locNext=loc()); // expressionの値が 0 ならば、locNextへジャンプ
  307. statement(locNext, locExpr); // locBreak, locContinue
  308. outInst2(JMP, IMM, locExpr); // 判定式へ無条件ジャンプ
  309. outInst2(LABEL, IMM, locNext); // 次の文を指すラベル
  310. }
  311.  
  312. /// ReturnStatement ::= "return" [Expression] ";"
  313. void returnStatement() {
  314. if (!is(";")) expression(VAL);
  315. skip(";");
  316. outInst(RET);
  317. }
  318.  
  319. /// Statement ::= CompoundStmt | IfStmt | ReturnStmt| Expression ";" | ";"
  320. void statement(int locBreak, int locContinue) {
  321. if (ispp(";")) ; // null statement
  322. else if (is("{")) compoundStatement(locBreak, locContinue);
  323. else if (ispp("if")) ifStatement(locBreak, locContinue);
  324. else if (ispp("while")) whileStatement(locBreak, locContinue);
  325. else if (ispp("return")) returnStatement();
  326. else { expression(VAL); skip(";"); }
  327. }
  328.  
  329. /// FunctionDefinition ::= TypeSpecifier VarDeclarator
  330. /// "(" [ VarDeclaration ("," VarDeclaration)* ] ")" CompoundStatement
  331. void functionDefinition() {
  332. int locFunc = loc(); // この関数の識別番号を得る
  333. char *varType = typeSpecifier(); // 返り値のデータ型
  334. char *varName = varDeclarator(); // 関数名
  335. nLocal = 0; // ローカル変数表初期化(メモリ解放省略)
  336. outInst2(FUNC, STR, (int)varName);
  337. outInst2(LABEL, IMM, locFunc);
  338. if (strcmp(varName,"main") == 0) entryPoint = nInst;
  339. appendName(0, NM_FUNC, varType, varName, AD_CODE, locFunc);
  340. baseSpace = 2; // 戻り番地と旧bpの分.
  341. outInst(ENTRY); // push ebp; mov ebp,espに相当
  342. INSTRUCT *pSub = outInst2(ADDSP, IMM, 0); // sp -= imm; immの値は後で書き換え
  343. for (skip("("); !ispp(")"); ispp(",")) {
  344. varType = typeSpecifier();
  345. varName = varDeclarator();
  346. appendName(1, NM_VAR, varType, varName, AD_STACK, baseSpace++);
  347. }
  348. baseSpace = 0; // ここからローカル変数領域
  349. compoundStatement(0, 0); // 関数本体
  350. pSub->val = baseSpace; // ここで imm の値を変更
  351. if (Inst[nInst-1].opcode != RET) outInst(RET);
  352. }
  353.  
  354. //============================ 最上位の構文解析 =============================
  355. /// Program ::= (FunctionDefinition | VariableDeclaration ";")*
  356. void program() {
  357. for (tix = 0; tix < nToken; ) {
  358. if (fTrace) printf("%3d: %s\n", tix, Token[tix]);
  359. if (isFunctionDefinition()) functionDefinition(); // 関数定義
  360. else { variableDeclaration(ST_GVAR); skip(";"); } // 外部変数宣言
  361. }
  362. }
  363.  
  364. void parser() {
  365. appendName(0, NM_FUNC, "int", "printf", AD_CODE, 0);
  366. program();
  367. }
  368.  
  369. //-----------------------------------------------------------------------------//
  370. // 命令実行 //
  371. //-----------------------------------------------------------------------------//
  372. #define MAXMEM 1000
  373. int mem[MAXMEM]; // メモリ
  374. int sp, bp, pc; // スタックポインタ、ベースポインタ、プログラムカウンタ
  375. int pos = 0; // メモリインデックス. データは上から、スタックは下から
  376. int location[1000]; // ラベルのアドレス配列
  377.  
  378. void push(int val) {
  379. if (sp <= pos) error("stack overflow!");
  380. mem[--sp] = val;
  381. }
  382.  
  383. int pop() {
  384. if (sp >= MAXMEM) error("stack empty!");
  385. return mem[sp++];
  386. }
  387.  
  388. int getStr(char *str) {
  389. int n = strlen(str);
  390. if (str[n-1] == '"') str[n-1] = '\0';
  391. return str+1;
  392. }
  393.  
  394. void execute() {
  395. int n, addr, type, val, rtn;
  396. if (fTrace) printf("entryPoint = %d\n", entryPoint);
  397. for (n = 0; n < nInst; n++) {
  398. if (fCode) printInst(n, &Inst[n]);
  399. if (Inst[n].opcode == LABEL) location[Inst[n].val] = n;
  400. }
  401. for (n = 0; n < ixData; n++)
  402. mem[pos++] = atoi(DataSection[n]);
  403. sp = MAXMEM; // スタックポインタの初期化
  404. for (pc = entryPoint; pc < nInst; ) {
  405. if (fTrace) printInst(pc, &Inst[pc]);
  406. type = Inst[pc].type;
  407. val = Inst[pc].val;
  408. switch (Inst[pc++].opcode) {
  409. case FUNC: break;
  410. case LABEL: break;
  411. case ENTRY: // 関数の入り口
  412. push(bp);
  413. bp = sp;
  414. break;
  415. case ADDSP:
  416. rtn = pop(); // 関数戻り値がスタックのトップに置かれている
  417. sp += val; // 引数分を削除
  418. push(rtn); // 改めてスタックのトップに関数戻り値を置く
  419. break;
  420. case PUSH:
  421. if (type == SKV) push(mem[bp+val]); // ローカル変数の値をpush
  422. else if (type == SKR) push(bp+val); // ローカル変数のアドレスをpush
  423. else if (type == STR) push(getStr((char*)val)); // 文字列のアドレスをpush
  424. else if (type == IMM) push(val);
  425. else error("exec.PUSH: %d", type);
  426. break;
  427. case MOV:
  428. val = pop();
  429. addr = pop();
  430. mem[addr] = val;
  431. break;
  432. case ADD: mem[sp+1] += mem[sp]; sp++; break;
  433. case SUB: mem[sp+1] -= mem[sp]; sp++; break;
  434. case MUL: mem[sp+1] *= mem[sp]; sp++; break;
  435. case DIV: mem[sp+1] /= mem[sp]; sp++; break;
  436. case MOD: mem[sp+1] %= mem[sp]; sp++; break;
  437. case GT: mem[sp+1] = (mem[sp+1] > mem[sp]); sp++; break;
  438. case GE: mem[sp+1] = (mem[sp+1] >= mem[sp]); sp++; break;
  439. case LT: mem[sp+1] = (mem[sp+1] < mem[sp]); sp++; break;
  440. case LE: mem[sp+1] = (mem[sp+1] <= mem[sp]); sp++; break;
  441. case EQ: mem[sp+1] = (mem[sp+1] == mem[sp]); sp++; break;
  442. case NE: mem[sp+1] = (mem[sp+1] != mem[sp]); sp++; break;
  443. case JZ: if (mem[sp++] == 0) pc = location[val]; break;// jz xxx
  444. case JMP: pc = location[val]; break;
  445. case CMP: mem[sp+1] -= mem[sp]; sp++; break;
  446. case CALL:
  447. if (type == STR) { // native function call
  448. rtn = printf((char*)mem[sp], mem[sp+1], mem[sp+2], mem[sp+3]);
  449. push(rtn);
  450. } else {
  451. push(pc); // 戻り番地格納
  452. pc = location[val]; // 関数先頭番地を pc にセット
  453. }
  454. break;
  455. case RET: // 関数からの戻り
  456. rtn = pop(); // 関数の戻り値
  457. sp = bp; // スタックポインタ回復
  458. bp = pop(); // ベースポインタ回復
  459. if (sp == MAXMEM) break; // main関数からのリターン
  460. pc = pop(); // pcにCALL命令の次の命令アドレスをセット
  461. push(rtn); // スタックの一番上に関数の戻り値を置く
  462. break;
  463. default: error("unknown opcode: %d\n", Inst[pc-1].opcode);
  464. }
  465. }
  466. }
  467.  
  468. void main(int argc, char *argv[]) {
  469. char *srcfile = NULL;
  470. int n;
  471. for (n = 1; n < argc; n++) {
  472. if (strcmp(argv[n], "-token") == 0) fToken = 1;
  473. else if (strcmp(argv[n], "-trace") == 0) fTrace = 1;
  474. else if (strcmp(argv[n], "-code") == 0) fCode = 1;
  475. else srcfile = argv[n];
  476. }
  477. lex(srcfile); //==== 字句解析. 結果はToken配列に格納 ====//
  478. parser(); //==== 構文解析・意味解析・中間語コード生成 ====//
  479. tix = -1; // エラー表示で Token[tix] の表示をやめるため
  480. execute();
  481. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement