Tiny Compiler ๋ฅผ ์์ ํ์ฌ C ๋ฌธ๋ฒ์ Subset์ธ C-Minus๋ฅผ ์ง์ ์ ์ํ์ฌ ๋ณธ๋ค.
- OS X Yosemite (10.10.3)
- Ubuntu 14.04 LTS
- GCC
- FLEX
- BISON
์ค์บ๋ ์ ์์ ์ํด ํค์๋, ์ฌ๋ณผ์ ์ ์ํ๊ณ DFA๋ฅผ ์ด์ฉํด ์ฃผ์ด์ง ์์คํ์ผ์ ๋ฌธ์์ด์ ํ ํฐ ๋จ์๋ก ๋ถ์(Lexical Analysis)ํ๋ค.
$ make cminus
$ ./cminus test.cm
$ make cminus_flex
$ ./cminus_flex test.cm
- else
- if
- int
- return
- void
- while
- +
- -
- *
- /
- <
- <=
- >
- >=
- ==
- !=
- =
- ;
- ,
- (
- )
- [
- ]
- {
- }
- /* */
- ๐ผ๐ท = ๐๐๐ก๐ก๐๐ ๐๐๐ก๐ก๐๐*
- ๐๐๐ = ๐๐๐๐๐ก ๐๐๐๐๐ก *
- ๐๐๐ก๐ก๐๐ = a | ... | z | A | ... | Z
- ๐๐๐๐๐ก = 0 | 1 | ... | 9
๋จผ์ ์ค์บ๋๋ง ์ ์ํ๊ธฐ ์ํด main.c ์ FLAG๋ค์ ์กฐ์ ํ๋ค.
int EchoSource = TRUE;
int TraceScan = TRUE;
int TraceParse = FALSE;
int TraceAnalyze = FALSE;
int TraceCode = FALSE;ํค์๋์ ์ฌ๋ณผ ๋ฑ๋ก์ ์ํด global.h ์ enum ๊ฐ์ ์์ ํ๋ค. ์ด ๋ MAXRESERVED์ ๊ฐ์๋ฅผ ํค์๋ ์์ ๋ฐ๋์ ๊ฐ๊ฒ ํด ์ฃผ์ด์ผ ํ๋ค. ํค์๋์ ์ฒ์๊ณผ ๋์ KEYWORD_START, KEYWORD_END ๋ผ๋ enum์ ์ถ๊ฐํ์ฌ ๊ด๋ฆฌ ํ๋ฉด ์ค์๋ฅผ ๋ฐฉ์ง ํ ์ ์์ ๊ฒ์ด๋ค. ์ปดํ์ผ ์ค๋ฅ ๋ฐฉ์ง๋ฅผ ์ํด tiny ์์ ์ฐ๋ enum์ ๋จ๊ฒจ๋๊ณ , fixme๋ฅผ ์ถ๊ฐํ๋ค.
/* MAXRESERVED = the number of reserved words */
#define MAXRESERVED 6
typedef enum
/* book-keeping tokens */
{ENDFILE,ERROR,
/* reserved words */
ELSE,IF,INT,RETURN,VOID,WHILE,
/* multicharacter tokens */
ID,NUM,
/* special symbols */
PLUS,MINUS,TIMES,OVER,LT,LTEQ,GT,GTEQ,EQ,NEQ,ASSIGN,SEMI,COMMA,
LPAREN,RPAREN,LBRACK,RBRACK,LBRACE,RBRACE,
/* OLD symbols for compile */
/* FIXME: Remove this symbols */
THEN,END,UNTIL,REPEAT,READ,WRITE,
} TokenType;๋ณธ๊ฒฉ์ ์ธ DFA๋ฅผ ์ํํ๊ธฐ ์ํด scan.c๋ฅผ ์์ ํ๋ค. tiny์์ ๋ฐฉ์ ๊ทธ๋๋ก ํ๋์ฉ ๋ฐ๋๋, 2๊ธ์ ์ง๋ฆฌ ์ฐ์ฐ์๋ค์ ์กฐ์ฌ์ค๋ฝ๊ฒ ์ถ๊ฐํ๋ค.
ํนํ /* */ ๋ฅผ ์ถ๊ฐํ ๋ ์ฃผ์ํ๋ค. ์ฒซ slash๊ฐ ๋์์๋, *๊ฐ ๋์์๋, 2๋ฒ์งธ *์ด ๋์์๋์ state๋ฅผ ๊ฐ๊ฐ ๋๋ ์ฒ๋ฆฌํ๋ค.
case INSLASH:
if (c == '*')
{ state = INCOMMENT;
save = FALSE;
}
else
{ state = DONE;
ungetNextChar();
currentToken = OVER;
}
break;
case INCOMMENT:
save = FALSE;
if (c == EOF)
{ state = DONE;
currentToken = ENDFILE;
}
else if (c == '*') state = INCOMMENTSTAR;
break;
case INCOMMENTSTAR:
save = FALSE;
if (c == EOF)
{ state = DONE;
currentToken = ENDFILE;
}
else if (c == '/') state = START;
else state = INCOMMENT;
break;TINY COMPILATION: test.cm
1: /* A Program to perform Euclid`s
2: Algorithm to computer gcd */
3:
4: int gcd (int u, int v)
4: reserved word: int
4: ID, name= gcd
4: (
4: reserved word: int
4: ID, name= u
4: ,
4: reserved word: int
4: ID, name= v
4: )
5: {
5: {
6: if (v == 0) return u;
6: reserved word: if
6: (
6: ID, name= v
6: ==
6: NUM, val= 0
6: )
6: reserved word: return
6: ID, name= u
6: ;
7: else return gcd(v,u-u/v*v);
7: reserved word: else
7: reserved word: return
7: ID, name= gcd
7: (
7: ID, name= v
7: ,
7: ID, name= u
7: -
7: ID, name= u
7: /
7: ID, name= v
7: *
7: ID, name= v
7: )
7: ;
8: /* u-u/v*v == u mod v */
9: }
9: }
10:
11: void main(void)
11: reserved word: void
11: ID, name= main
11: (
11: reserved word: void
11: )
12: {
12: {
13: int x; int y;
13: reserved word: int
13: ID, name= x
13: ;
13: reserved word: int
13: ID, name= y
13: ;
14: x = input(); y = input();
14: ID, name= x
14: =
14: ID, name= input
14: (
14: )
14: ;
14: ID, name= y
14: =
14: ID, name= input
14: (
14: )
14: ;
15: output(gcd(x,y));
15: ID, name= output
15: (
15: ID, name= gcd
15: (
15: ID, name= x
15: ,
15: ID, name= y
15: )
15: )
15: ;
16: }
16: }
17: EOF$ make cminus_flex
$ ./cminus_flex test.cm
flex ๋ฅผ ์ฌ์ฉํ์ฌ C-Minus์ lexer๋ฅผ ์๋์ผ๋ก ์์ฑํ๊ณ ์ฌ์ฉํ๋ค.
๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ข ์์ฑ์ ์์ ๊ธฐ ์ํด noyywrap ๋ฅผ ์ฌ์ฉํ์ง ์๋๋ก cminus.l์์ ์ต์ ์ ์ถ๊ฐํ๋ค.
%option noyywrap
Makefile ์ ์๋ ํญ๋ชฉ์ ์ถ๊ฐํ๋ค. ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ข ์์ฑ์ ์ ๊ฑฐํ์๊ธฐ ๋๋ฌธ์ -l ์ต์ ์ด ํ์ ์๋ค.
cminus_flex: main.o globals.h util.o lex.yy.o
$(CC) $(CFLAGS) main.o util.o lex.yy.o -o cminus_flex
lex.yy.o: cminus.l scan.h util.h globals.h
flex -o lex.yy.c cminus.l
$(CC) $(CFLAGS) -c lex.yy.clex/tiny.l์ ๊ธฐ๋ฐ์ผ๋ก cminus.l์ ์์ฑํ๋ค. ํธ๋ฆฌํ ๋ฌธ๋ฒ์ ์ ๊ณตํด ์ฃผ์ด์ ๋ณ๋ค๋ฅธ ์ด๋ ค์ ์์ด cminus์ ๋ฌธ๋ฒ๋ค์ ๊ตฌํ ํ ์ ์๋ค.
TINY COMPILATION: test.cm
4: reserved word: int
4: ID, name= gcd
4: (
4: reserved word: int
4: ID, name= u
4: ,
4: reserved word: int
4: ID, name= v
4: )
5: {
6: reserved word: if
6: (
6: ID, name= v
6: ==
6: NUM, val= 0
6: )
6: reserved word: return
6: ID, name= u
6: ;
7: reserved word: else
7: reserved word: return
7: ID, name= gcd
7: (
7: ID, name= v
7: ,
7: ID, name= u
7: -
7: ID, name= u
7: /
7: ID, name= v
7: *
7: ID, name= v
7: )
7: ;
9: }
11: reserved word: void
11: ID, name= main
11: (
11: reserved word: void
11: )
12: {
13: reserved word: int
13: ID, name= x
13: ;
13: reserved word: int
13: ID, name= y
13: ;
14: ID, name= x
14: =
14: ID, name= input
14: (
14: )
14: ;
14: ID, name= y
14: =
14: ID, name= input
14: (
14: )
14: ;
15: ID, name= output
15: (
15: ID, name= gcd
15: (
15: ID, name= x
15: ,
15: ID, name= y
15: )
15: )
15: ;
16: }
17: EOFtiny์ ์์ค๊ฐ ๋ฏธ๋๋ฉํ๊ฒ ์ ์ง์ ธ ์์ด์ ๊ณผ์ ๋ ๋ณ๋ค๋ฅธ ์ด๋ ค์ ์์ด ์ํ ํ ์ ์์๋ค. ์ด๋ฒ ๊ณผ์ ์ ์์ฌ์ด ์ ์ด๋ผ๋ฉด ๊ธฐ๊ป ์๋ก์ด ์ปดํ์ผ๋ฌ๋ฅผ ์ ์ํ๋๋ฐ C์ Subset์ธ ์ธ์ด๋ฅผ ๋ง๋ ๋ค๋ ์ ์ด๋ค. ์ด ์ธ์ด๋ ์๋ฌด๋ฆฌ ์ ๋ง๋ค์ด๋ด์ผ C์ ํ์ ํธํ์ด๊ณ ๋ณ๋ค๋ฅธ ์ธ๋ชจ๊ฐ ์์ด ๋ณด์ธ๋ค. ์ฐจ๋ผ๋ฆฌ DSL(Domain-Specific Language)๋ฅผ ํ๋ ์ ์ํ์ฌ ์ง์ ๊ตฌํํด ๋ณด๊ฑฐ๋ ๋ฌธ๋ฒ์ด ๊ฐ๋จํ๋ฉด์๋ First-Class Function์ ์ง์ํ๋ JavaScript๋ฅผ ์ง์ ๊ตฌํํด๋ณด๋ฉด ๋ ์ฌ๋ฐ๊ณ ๋ณด๋์ฐฌ ๊ณผ์ ๊ฐ ๋์ง ์์์๊น ํ๋ค.
- Flex๋ฅผ ์ด์ฉํ์ฌ ๊ตฌํํ C-Minus Scanner๋ฅผ ์ด์ฉ
- Yacc (bison)๋ฅผ ์ฌ์ฉํ์ฌ ์ป์ ์์ค ์ฝ๋๋ฅผ ํฉํ์ฌ Parser๋ฅผ ๊ตฌํํ๋ค.
$ make cminus
$ ./cminus test.cm
$ make test
Parser ์ฒ๋ฆฌ๋ฅผ ์ํด ์์๋ค์ ์์ ํ์๋ค. bison์ ์ฌ์ฉ ํ๊ธฐ ์ํด Global ๋ณ์๋ค์ ์์ ํ์๋ค.
#define NO_PARSE FALSE
int EchoSource = TRUE;
int TraceScan = FALSE;
int TraceParse = TRUE;yacc/globals.h ํ์ผ์ ๋ณต์ฌํ์ฌ ์์ ํ์๋ค. ํ ํฐ๋ค์ ์ ์๋ฅผ ๋ฐ์์ค๊ธฐ ์ํด bison์์ ์์ฑ๋๋ y.tab.h๋ฅผ include ํ์๋ค.
bison์ ์ฌ์ฉํด y.tab.c๋ฅผ ์๋์ผ๋ก ์์ฑํ๊ณ ์ปดํ์ผ ํ๊ธฐ ์ํด Makefile์ ์์ ํ์๋ค.
# yacc์์ token๋ค์ ์ ์ํ๊ธฐ ๋๋ฌธ์ ๊ฐ์ฅ ๋จผ์ ์ปดํ์ผ ๋์ด์ผ ํ๋ค.
# ์ปดํ์ผ ์๋ฌ๋ฅผ ๋ง๊ธฐ ์ํด, analyze.o, cgen.o๋ฅผ ์ปดํ์ผ ํ์ง ์๋๋ค.
OBJS = y.tab.o lex.yy.o main.o util.o symtab.o
y.tab.o: cminus.y globals.h
bison -d cminus.y --yacc
$(CC) $(CFLAGS) -c y.tab.c
BNF์์ Decl, Param, Type Node๊ฐ ์ถ๊ฐ๋์์ผ๋ฏ๋ก ์ด๋ฅผ ์์ฑํ๋ ํจ์๋ฅผ ๋ง๋ ๋ค.
๋ํ ์์ฑ๋ parse tree๋ฅผ ์ถ๋ ฅ ํ ์ ์๋๋ก printTree๋ฅผ ์์ ํ์๋ค.
yacc/tiny.y ํ์ผ์ ๋ณต์ฌํ์ฌ ์์ ํ์๋ค. ๋๋ถ๋ถ์ ๋ฌธ๋ฒ๋ค์ tiny์ ํฌ๊ฒ ๋ค๋ฅด์ง ์์ ์์ ํ๋๊ฒ ๋ณ ๋ฌธ์ ๊ฐ ์์์ผ๋, ID(๋ณ์๋ช ์ด๋ ํจ์๋ช )์ ๊ฐ์ ธ์์ผ ํ๋ ๊ฒฝ์ฐ ID๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ์ํด ๋ณ๋์ ์ฒ๋ฆฌ๊ฐ ํ์ํ์๋ค. ๋ง์ง๋ง ํ ํฐ๋ง ์ ์ฅํ๋ฏ๋ก, ๋ค์ ํ ํฐ์ ์ฒ๋ฆฌํด ๋ฒ๋ฆฌ๋ฉด token์ด ๋ ์๊ฐ๋ฒ๋ ค identifier๋ฅผ ์ฝ์ ์ ์๋ ๊ฒ์ด๋ค.
saveName : ID
{ savedName = copyString(tokenString);
savedLineNo = lineno;
}
saveNumber : NUM
{ savedNumber = atoi(tokenString);
savedLineNo = lineno;
}์ ๋ ๋ฌธ๋ฒ์ ์ถ๊ฐ๋ก ์ ์ํ์ฌ, ID์ NUM์ ์ฌ์ฉ ํ๋ ๊ณณ์ ๋์ฒดํ์ฌ ์ฌ์ฉํ์๋ค.
var_decl : type_spec saveName SEMI
{ $$ = newDeclNode(VarK);
$$->child[0] = $1; /* type */
$$->lineno = lineno;
$$->attr.name = savedName;
saveName์ ์ด์ฉํด ID๋ฅผ ๋ณ๋๋ก ์ ์ฅํด๋์๋ค๊ณ ํด๋ ์ ์ฅํ๋ ๋ณ์๊ฐ global variable์ด๋ค ๋ณด๋ ๋ฎ์ด์จ์ง๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๊ธฐ ๋๋ฌธ์ saveName์ดํ ๋ saveName์ ์ฌ์ฉ ํ ๊ฒฝ์ฐ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์๋ค. saveName์ stack์ ์ฌ์ฉํ๋ค๋ฉด ํ๋์ฉ ๊ฐ์ ธ์ค๋ ๊ฒ๋ ๊ฐ๋ฅ ํ๊ฒ ๋ค๊ณ ์๊ฐํ์์ง๋ง, ๊ตณ์ด stack์ ์ฌ์ฉํ์ง ์์๋ ํด๊ฒฐ ๊ฐ๋ฅํ ๋ฌธ์ ์๊ธฐ์ ์ฌ์ฉํ์ง ์์๋ค. saveName์ ์ด์ฉํ๋๋ผ๋ ๋ฐ๋ก ํ์ฑ ๊ฒฐ๊ณผ๋ฅผ ์ ์ฅํ๋๋ก ๋ณ๊ฒฝํ์ฌ, savedName์ด ๋ฎ์ด์จ์ง๋ ๊ฒฝ์ฐ๋ฅผ ๋ฐฉ์งํ์๋ค. ์๋ ์์ ์ ๊ฒฝ์ฐ saveName ๋ฐ๋ก ๋ค์์ name์ ์ ์ฅํ์ง ์๋๋ค๋ฉด args์์์ savedName์ ๋ฎ์ด์ฐ๊ธฐ ๋๋ค.
call : saveName {
$$ = newExpNode(CallK);
$$->attr.name = savedName;
}
LPAREN args RPAREN
{ $$ = $2;
$$->child[0] = $4;
}bison ๋ฒ์ ์ ๋ฌธ์ ์ธ์ง yylex function์ ์ ์ธ์ ์ฐพ์ง ๋ชปํด ์ปดํ์ผ ์๋ฌ๊ฐ ๋ฐ์, cminus.y ์ ์๋จ์ yylex์ ์ ์ธํด์ฃผ์๋ค.
static int yylex(void);./cminus test.cm
TINY COMPILATION: test.cm
Syntax tree:
Function Dec: gcd
Type: int
Parameter: u
Type: int
Parameter: v
Type: int
Compound Statment
If
Op: ==
Id: v
Const: 0
Return
Id: u
Return
Call(followings are args) : gcd
Id: v
Op: -
Id: u
Op: *
Op: /
Id: u
Id: v
Id: v
Function Dec: main
Type: void
Compound Statment
Var Dec: x
Type: int
Var Dec: y
Type: int
Assign
Id: x
Call(followings are args) : input
Assign
Id: y
Call(followings are args) : input
Call(followings are args) : output
Call(followings are args) : gcd
Id: x
Id: y
๊ณผ์ ๋ช ์ธ์ ์์ ์ ๊ฒฐ๊ณผ๊ฐ ์กฐ๊ธ ๋ค๋ฅด์ง๋ง, ํ์ฑ ์ด ์ ์์ ์ผ๋ก ์ผ์ด๋ฌ์์ ํ์ธ ํ ์ ์๋ค.
์์ ์ ๋ค๋ฅธ ๊ณณ์ ์ ์ธ์์์ Type๋ถ๋ถ์ธ๋ฐ, type์ cminus์์ void์ int๋ง ์ ์ธํ์ฌ์ ๊ทธ๋ ์ง ์ค์ C์์ const, static ๋ฑ์ ์ ๋์ฌ๊ฐ ๋ถ์ ์๋ ์๊ธฐ ๋๋ฌธ์ ํ์ฅ์ฑ์ ์ํด ํจ์ ์ ์ธ๊ณผ ๋ณ์ ์ ์ธํด์ type์ child๋ก ๊ฐ์ง๋๋ก ํ์๋ค.
BNF์์ array๊ฐ ์กด์ฌํ๋๋ฐ, test.cm์์ array๋ฅผ ํ ์คํธ ํ์ง ๋ชปํด ์ถ๊ฐ์ ์ธ ํ ์คํธ๋ฅผ ์ํํ์๋ค.
int aaa[1234];
int function (int a,int b, int c[], int d) { }Syntax tree:
Var Dec(following const:array length): aaa 1234
Type: int
Function Dec: function
Type: int
Parameter: a
Type: int
Parameter: b
Type: int
Array Parameter: c
Type: int
Parameter: d
Type: int
Compound Statment
parse.c๋ฅผ ์ง์ ์์ฑํ๋ ๊ฒ์ด ์ฝ๋ค๊ณ ์ด์ผ๊ธฐ๋ฅผ ๋ค์์ผ๋, ์ถํ ์ง์ ๋ค๋ฅธ ์ธ์ด๋ฅผ ๋ง๋ค์ด ๋ณผ๋๋ฅผ ๋๋นํ์ฌ yacc๋ฅผ ์ตํ๋๋ ๊ฒ์ด ์ข์ ๊ฒ ๊ฐ์ yacc๋ฅผ ์ด์ฉํ์ฌ ์์ฑํ์๋ค. bison์ด BNF๋ก ๋ฌธ๋ฒ๋ง ์ ์ํ๋ฉด ์์์ c code์ parser๋ฅผ ์์ฑํด์ฃผ๋ ๋งค์ฐ High ํ ์์ค์ธ์ง ์์๋๋ฐ, BNF์์ฑ์ผ๋ก ๋๋๋ ๊ฒ์ด ์๋๋ผ tree์ ๋ด์ฉ๋ค์ ์ ์ฅํด ์ฃผ๋ ๊ณผ์ ๋ ํ์ํ๋ค๋ ๊ฒ์ ๋๋ฌ๋ค. ํ์ง๋ง ํธ๋ฆฌํ ๋๊ตฌ์์ด ๋ถ๋ช ํ๋ฉฐ, bison์ ์ฌ์ฉํด ๋ณด์๋ค๋ ๊ฒ ์์ฒด๊ฐ ์ด๋ฒ ๊ณผ์ ๋ฅผ ํตํด ์ป์ ๊ฐ์ฅ ํฐ ๊ฒฝํ์ธ ๊ฒ ๊ฐ๋ค.
- C-Minus์ Symbol Table ๊ตฌํ
- C-Minus์ Type Checker ๊ตฌํ
$ make cminus
$ ./cminus test.cm
$ make cminus_flex
$ ./cminus_flex test.cm
- Compound Statement๋ณ Scope ์ ์ฉ
- ์ ์ธ๋์ง ์์ ๋ณ์๊ฐ ์ฌ์ฉ๋๋ฉด ์๋ฌ
- ๊ธฐ๋ณธํจ์๋ ํญ์ ํฌํจํ๊ณ ์์ด์ผ ํจ
- int input(), void output(int arg)
โ void๋ ํจ์์์๋ง ์ฌ์ฉ ๊ฐ๋ฅ โ return type ํ์ธ โ Assignํ ๋ ๋ ํผ์ฐ์ฐ์(operand)์ ํ์ ์ผ์น ํ์ธ โ Function Call ํ ๋ argument ์ ํ์ธ
- If๋ While์ Expression์ด ๊ฐ์ ๊ฐ์ง๋์ง ํ์ธ
- ๊ทธ ์ธ ๋ค๋ฅธ ์ฌ๋ฌ ๊ฐ์ง๋ฅผ C-Minus ๋ฌธ๋ฒ์ ์ฐธ์กฐํ์ฌ ํ์ธ
Semantic Analysis๋ฅผ ์ํํ๊ธฐ ์ํด main.c์ ์ต์ ์ ์์ ํ์๋ค.
#define NO_ANALYZE FALSE
int TraceParse = FALSE;
int TraceAnalyze = TRUE;
BucketList๋ฅผ Wrapping ํ๋ Scope ๊ตฌ์กฐ์ฒด๋ฅผ ์์ฑํฉ๋๋ค.
typedef struct ScopeRec
{ char * funcName;
int nestedLevel;
struct ScopeRec * parent;
BucketList hashTable[SIZE]; /* the hash table */
} * Scope;
Static Scope๋ฅผ ๊ตฌํํ๊ธฐ ์ํด Scope๋ฅผ Stack ํํ๋ก ๊ด๋ฆฌ ํ๋ Function๋ค์ ์ถ๊ฐํฉ๋๋ค.
Scope sc_top( void );
void sc_pop( void );
void sc_push( Scope scope );
Analyze๋ฅผ ๋๊ธฐ ์ํ ํจ์๋ฅผ ์ถ๊ฐํฉ๋๋ค.
Compound State๋ฅผ ์ถ๊ฐ ํ ๋ ๋ง๋ค ์๋ก์ด Scope๋ฅผ ๋ง๋ค์ด Stack์ Push ํฉ๋๋ค. Scopmpound State๋ฅผ ๋น ์ ธ๋๊ฐ๋ Stack์ Pop ํฉ๋๋ค. ์ด ๋, Function์ ๊ฒฝ์ฐ argument๋ค๊ณผ Declaration์ Scope๊ฐ ๊ฐ๋๋ก ์ฃผ์ํฉ๋๋ค.
์๋ก์ด ์ ์ธ์ด ์์ ๋๋ ํ์ฌ์ Scope์ ๊ฒ์ฌํ์ฌ ์ค๋ณต์ด ์๋์ง๋ฅผ ํ์ธ, ์ค๋ณต์ด ์์ผ๋ฉด ์๋ฌ๋ฅผ ๋ฐ์์ํต๋๋ค.
๋ณ์๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ Scope์ Stack์ ๊ฐ๊น์ด ์์๋๋ก ๊ฒ์ํ์ฌ ๋ณ์๊ฐ ์๋์ง ํ์ธํ๊ณ , ์์ผ๋ฉด ์๋ฌ๋ฅผ ๋ฐ์์ํต๋๋ค.
Input, Output Function์ ์ถ๊ฐํฉ๋๋ค. line number๋ -1๋ก ์ค์ ํ์์ต๋๋ค.
๋ช ์ธ์ ์ฃผ์ด์ง๋๋ก Type๋ค์ ์ฑํฌํฉ๋๋ค.
./cminus test.cm
TINY COMPILATION: test.cm
Building Symbol Table...
Symbol table:
<global scope> (nested level: 0)
Symbol Name Sym.Type Data Type Line Numbers
------------- -------- ----------- ------------
main Function Void 11
input Function Integer -1 14 14
output Function Void -1 15
gcd Function Integer 4 7 15
function name: gcd (nested level: 1)
Symbol Name Sym.Type Data Type Line Numbers
------------- -------- ----------- ------------
u Variable Integer 4 6 7 7
v Variable Integer 4 6 7 7 7
function name: main (nested level: 1)
Symbol Name Sym.Type Data Type Line Numbers
------------- -------- ----------- ------------
x Variable Integer 13 14 15
y Variable Integer 13 14 15
Checking Types...
Type Checking Finished
if compound ์์ scope์ function์ scope๊ฐ ๋ฌ๋ผ์ง์ ํ์ธ
int scope (int a) {
if (a==1){
int a;
output(a);
}
}
./cminus scope.cm
TINY COMPILATION: scope.cm
Building Symbol Table...
Symbol table:
<global scope> (nested level: 0)
Symbol Name Sym.Type Data Type Line Numbers
------------- -------- ----------- ------------
scope Function Integer 1
input Function Integer -1
output Function Void -1 4
function name: scope (nested level: 1)
Symbol Name Sym.Type Data Type Line Numbers
------------- -------- ----------- ------------
a Variable Integer 1 2
function name: scope (nested level: 2)
Symbol Name Sym.Type Data Type Line Numbers
------------- -------- ----------- ------------
a Variable Integer 3 4
Checking Types...
Type Checking Finished
void a;
Symbol error at line 1: variable should have non-void type
(Table ์๋ต)
void func(void) {
return 1;
}
(Table ์๋ต)
Type error at line 2: expected no return value
์ ๋ฒ ๊ณผ์ ์ธ Syntax Analysis๊น์ง๋ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด๋ก ์์๋ ๊ตฌํ ํด๋ณด์๋ ๋ด์ฉ์ด์์ง๋ง, Semantic Analysis๋ฅผ ์ค์ ๋ก ๊ตฌํํด ๋ณด๋ ๊ฒ์ ์ฒ์์ด๋ผ ์ํ์ฐฉ์ค๊ฐ ๋ง์๋ค. scope๋ stack๊ตฌ์กฐ๋ก๋ง ๋ฐ๊ฟ์ฃผ๊ธฐ๋ง ํ๋ฉด ๋์ ํฐ ์ด๋ ค์์ด ์์์ง๋ง type check์ ๊ฒฝ์ฐ flex, bison ๊ณผ ๊ฐ์ ์ธ๋ถ ํด์ ๋์๋ ๋ฐ์ ์ ์์ด ๋ฐ๋ก c์ switch case๋ก ๊ตฌํ ํ๋ ค๋ ์ฌ๋ฌ๊ฐ์ง ๊ฒฝ์ฐ์ ์๋ฅผ ์๊ฐํ์ฌ์ผ ํด์ ํผ๋์ค๋ฌ์ ๋ค. ๋ฌธ๋ฒ์๋ฌ๊ฐ ์ฐ์์ผ๋ก ๋ฐ์ ํ ๊ฒฝ์ฐ ์๊ฐ์น ๋ชปํ ์์ธ๋ก Segfault๊ฐ ๋ฐ์ํ๊ธฐ๋ ํ๋ ๋ฑ ๊ณ ๋ คํ ์ฌํญ์ด ๋ง์๋ค. ์๋ฌ ์ฒ๋ฆฌ๋ฅผ ์ ํด์ฃผ๋ ํ๋์ ์ปดํ์ผ๋ฌ ์ ์์๋ค์๊ฒ ๊ฐ์ฌํ๋ฉฐ ๊ณผ์ ๋ฅผ ๋ง๋ฌด๋ฆฌ ํฉ๋๋ค.
- ๊ธฐ์กด๊ณผ์ ๋ฅผ ํ ๋๋ก ํ์ฌ Tiny Machine์์ ๋์ํ๋ Code ์์ฑ
$ make cminus
$ ./cminus test.cm
(๊ทธ๋ฆผ)
- Function Call์ด ์ผ์ด๋๋ฉด local variable, parameters, return address, function address๊ฐ ์ฐจ๋ก๋ก ์์ธ๋ค.
- ์ฆ, function pointer๋ฅผ fp๋ผ๊ณ ํ ๋
- fp-1 : return address
- fp-2 : 1st parameter
- fp-3 : 2nd parameter
- ...
- fp-n : last parameter
- fp-n-1 : 1st local variable
- fp-n-2 : 2nd local variable
- ...
Code Generation์ ์ํํ๊ธฐ ์ํด flag๋ฅผ ์์
#define NO_CODE FALSE
int TraceAnalyze = FALSE;
int TraceCode = TRUE;
์ง๋ ๊ณผ์ ์์๋ location์ scope์ ๊น์ด๋ก ์ ์ํ์์์ง๋ง, ์ด๋ฒ์๋ scope๋ด์ ๋ณ์์ ์์น๋ก ๋ณ๊ฒฝํ์๋ค. function pointer๋ฅผ fp๋ผ๊ณ ํ ๋ fp-2-loc์ ๋ณ์๊ฐ ์ ์ฅ๋๊ฒ ๋๋ค.
์์ ์์
syntaxTree๋ฅผ ์ํํ๋ฉฐ ์ฝ๋๋ฅผ ์์ฑํฉ๋๋ค. ๊ฐ tree์ ํ์ ๋ณ๋ก genStmt, genExp, genDecl, genParam ์ด๋ผ๋ ํจ์๋ฅผ ๊ฐ๊ฐ ์์ฑํฉ๋๋ค.
- If, While : tiny์ ์ฝ๋๋ฅผ ๊ทธ๋๋ก ์ฌ์ฉ
- Compound : Scope๋ฅผ ์ถ๊ฐํด ์ค
- Return : return address(fp-1)๋ก expression ๊ฐ์ ๋ด๋ณด๋
- OP, Const : tiny์ ์ฝ๋๋ฅผ ๊ทธ๋๋ก ์ฌ์ฉ
- Id : Scope๋ฅผ ๊ณ ๋ คํ์ฌ ๋ณ์์ ์ฃผ์ ๊ฐ์ ๊ณ์ฐ
- Assign : lhs(lvalue)๋ ์ฃผ์๋ฅผ ๊ฐ์ ธ์ค๊ณ , rhs(rvalue)๋ ๊ฐ์ ๊ฐ์ ธ์ค๋๋ก ๊ตฌํ
- Call : ํจ์์ฝ์ด ์ผ์ด๋ ๋ Call Stack์ ํ๋ผ๋ฉํฐ, return value๊ฐ ์์ด๋ ์์์ ์ฃผ์ํ์ฌ ๊ตฌํ
- Func, Var, ArrVar : ์ด์ ๋จ๊ณ์์ ํ์ ๊ณผ ์ค์ฝํ๋ ๊ฒ์ฌํ์์ผ๋ฏ๋ก ํ ๋น๋ ๋ฉ๋ชจ๋ฆฌ ํฌ๊ธฐ๋ง ๊ณ์ฐํ๋ค. c-minus์์๋ ๋ชจ๋ ๋ณ์ํ์ ์ด 1์ ํฌ๊ธฐ๋ฅผ ๊ฐ์ง๋๋ก ์ค์ ํ์๋ค. Array์ ๊ฒฝ์ฐ Array์ ํฌ๊ธฐ๋งํผ ํ ๋น
syntaxTree๋ฅผ ๋์ code๋ฅผ ์์ฑํ ํ, main๋ฅผ ํธ์ถํ๋ ์ฝ๋๋ฅผ ์์ฑ
/* A Program to perform Euclid`s
Algorithm to computer gcd */
int gcd (int u, int v)
{
if (v == 0) return u;
else return gcd(v,u-u/v*v);
/* u-u/v*v == u mod v */
}
void main(void)
{
int x; int y;
x = input(); y = input();
output(gcd(x,y));
}
* TINY Compilation to TM Code
* File: test.tm
* Standard prelude:
0: LD 5,0(0) load gp with maxaddress
1: LDA 6,0(5) copy gp to mp
2: ST 0,0(0) clear location 0
* End of standard prelude.
* -> Function (gcd)
4: ST 1,-2(5) func: store the location of func. entry
* func: unconditional jump to next declaration belongs here
* func: function body starts here
3: LDC 1,6(0) func: load function location
6: ST 0,-1(6) func: store return address
* -> param
* u
* <- param
* -> param
* v
* <- param
* -> compound
* -> if
* -> Op
* -> Id (v)
7: LDC 0,-3(0) id: load varOffset
8: ADD 0,6,0 id: calculate the address
9: LD 0,0(0) load id value
* <- Id
10: ST 0,-4(6) op: push left
* -> Const
11: LDC 0,0(0) load const
* <- Const
12: LD 1,-4(6) op: load left
13: SUB 0,1,0 op ==
14: JEQ 0,2(7) br if true
15: LDC 0,0(0) false case
16: LDA 7,1(7) unconditional jmp
17: LDC 0,1(0) true case
...
ํจ์๋ค๊ณผ ํ๋ผ๋ฉํฐ๋ค์ด ์ ์ ์๋์ด ํธ์ถ๋๊ณ , ๋ณ์๋ค์ ๋ฉ๋ชจ๋ฆฌ ์ฃผ์๋ ์ ๋๋ก ๊ณ์ฐ ๋จ์ ํ์ธ ํ ์ ์๋ค.
๋๋์ด ์ปดํ์ผ๋ฌ์ ๋ง์ง๋ง ๊ณผ์ ๊ฐ ๋๋ฌ์ต๋๋ค. ๋จธ์ ์ฝ๋๋ LLVM ๋ ๋ฒจ๊น์ง ์ปดํ์ผ์ด ๋์ด์ ์ง์ ์คํ ์ํฌ ์ ์์์ง ์์๋๋ฐ, tiny machine ์ฉ์ผ๋ก๋ง ์ปดํ์ผ์ด ๋์ด ์กฐ๊ธ ์์ฝ์ต๋๋ค๋ง ์ปดํ์ผ๋ ์ธ์ด๊ฐ ์ด์๋ธ๋ฆฌ์ด์ ๊ฐ๊น๊ธฐ์ ์ด์์ผ๋ก์ ์ปดํ์ผ์ ๊ฒฝํํด ๋ณผ ์ ์์์ต๋๋ค. ์ฅ๊ธฐ๊ฐ ์งํ๋ ํ๋ก์ ํธ์์๋ ๋ถ๊ตฌํ๊ณ ์์ฝ๊ฒ๋ ์ค์ฉ์ ์ธ ์ธ์ด๊ฐ ์๋๋ผ์ ์ด ํ๋ก์ ํธ๋ฅผ ๋ค๋ฅธ ๊ณณ์์ ์ธ ์๋ ์๊ฒ ์ง๋ง ํ ํ๊ธฐ๋์ ํ๋ก์ ํธ๋ฅผ ์งํํ๋ฉด์ ์ค์ ๋ก ํ๋ก๊ทธ๋๋ฐ ์ธ์ด๊ฐ ์ด๋ ํ ๊ณผ์ ์ ๊ฑฐ์ณ์ ๋ถ์๋๋์ง๋ฅผ ์ดํดํ ์ ์์๋ค. ํนํ ๋ง์ง๋ง ๊ณผ์ ์์ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด๋ฅผ ๋ ์ง์คํฐ๋ฆฌ ๋ช ๋ น๋จ์๊น์ง ์ปดํ์ผ์ ํด๋ณด๋ฉด์, c์ธ์ด์์ ์์ฑ๋ ์ฝ๋ ํนํ ํจ์ ํธ์ถ์ด ์ค์ ๋ก ์ปดํจํฐ๋ด์์ ์ด๋ ํ ์ฐ์ฐ์ ์ํํ๋์ง ๋ค์ ํ๋ฒ ์ตํ ์ ์์๋ค.
์ํ๊ธฐ๊ฐ์ด๋ผ ์๊ฐ์ ์ซ๊ธฐ๋ฉฐ ๋ง๋ฌด๋ฆฌ ํ๊ฒ ๋์๋๋ฐ, ๊ทธ๋๋ ์ ๋ง๋ฌด๋ฆฌ ๋ ๊ฒ ๊ฐ์์ ๋คํ์ ๋๋ค. ํํ๊ธฐ ๋์ ๊ต์๋๊ณผ ์กฐ๊ต๋ ์๊ณ ํ์ จ์ต๋๋ค.