diff --git a/.crossnote/style.less b/.crossnote/style.less
index ad45723..69b7860 100644
--- a/.crossnote/style.less
+++ b/.crossnote/style.less
@@ -8,13 +8,14 @@
background-color: white;
font-family: NanumGothic;
}
- font-size: 11pt;
+ font-size: 10pt;
font-family: NanumMyeongjo;
.language-scanres {
font-size: 6pt;
}
ol, ul {
margin-top: 0.0pt;
+ margin-bottom: 0.2rem;
}
p {
margin-bottom: 0.4rem;
diff --git a/notes/4.md b/notes/4.md
index 60be980..fd7d762 100644
--- a/notes/4.md
+++ b/notes/4.md
@@ -68,3 +68,77 @@ Language usually have basic types aka primitive types. Using these types to buil
There are two options:
1. Implement a method `Equals(T1, T2)`.
It must compare type trees of T1 and T2. For OOP languages also need sub-types
+
+
+### Type Checking Methodology
+Type checking means verifying whether expressions are given proper types
+1. Implement using Syntax-Directed Definitions(SDD)
+2. First build the AST, then implement type checking by recursive traversal of the AST nodes
+
+#### SDD
+
+SDD associates semantic rules for the productions in the CFG. It checks types based on the semantic rules associated with the production rules.
+
+#### AST Traversal
+
+Type Checking During AST Traversal.
+
+중간에 새로운 타입이 생길 수 있음.
+
+By Recursive Traversal of the AST nodes, inferencing types of AST nodes.
+
+### Inference
+
+$$\frac{\vdash H_1 \vdash H_2 \vdash H_3}{\vdash \text{conclusion}}[\text{rule name}]$$
+
+#### Soundness
+
+항상 참이 되는 타입
+
+$e : T$ means that $e$ is a sound expression of type $T$, that is $e$ is always the type $T$.
+
+for non expression statements use special unit type (like void or empty type)
+
+$S: \text{void}$
+
+#### Proof Tree
+
+$$\frac{
+ \frac{1 \text{ is a integer literal}}{\vdash 1: \text{int}} [\text{int}] \;
+ \frac{2 \text{ is an integer literal}}{\vdash 2: \text{int}} [\text{int}]
+ }{\vdash 1 + 2 : \text{int}} [\text{int add}]
+ $$
+
+Proof Tree는 AST를 뒤집은 모양.
+
+If-then-else는 가질 수 있는데, If-then은 타입을 가질 수 없음.
+
+
+
+#### Type Environment
+
+어떻게 $x$가 variable이라고 할때 어떤 타입을 가지는지 알 수가 없음.
+
+Type Environment gives types for **free variables**.
+
+$$O \vdash e: T$$
+* $O$ is essentially **symbol table**.
+
+Complex Example of Declaration:
+```c
+for (T1 i = 0;;) {
+ exp
+}
+```
+$$\frac{O[T1/i] \vdash \text{exp}: T2}{O\vdash \texttt{for}(i: T1) \set{\text{exp}: T2}}$$
+
+Complex Example of Class Attrs
+
+$$O_C(x) = T$$
+* forall attrs $x: T$ in class C
+$$O_C$$
+
+Complex Example of Class Methods
+
+### Subtyping
+
diff --git a/out/lex.md b/out/lex.md
new file mode 100644
index 0000000..3a9658d
--- /dev/null
+++ b/out/lex.md
@@ -0,0 +1,379 @@
+# Lexical Analysis(Scanner) Report
+
+* 주하진, 2024062806
+
+## Compilation Environment and Method
+
+주어진 `Makefile`을 이용하여 C파일을 컴파일함.
+C파일은 `gcc`를 이용해서 컴파일한다.
+`Makefile`에서 산출되는 실행파일은 `cminus_cimpl`과 `cminus_lex`가 있으며 각각 `main.c util.c scan.c`, `main.c util.c lex.yy.c`를 컴파일한 오브젝트 파일을 필요로 한다.
+
+`lex.yy.c`는 `flex -o lex.yy.c cminus.l`을 통해 생성된다.
+
+## C-Minus Language
+
+C-Minus에서 필요한 토큰타입변수와 그에 대한 설명은 다음과 같다.
+
+**특수 토큰**
+
+* `ENDFILE`: 파일끝
+* `ERROR`: 에러
+
+**키워드 토큰**
+
+* `IF`: `if`
+* `THEN`: `then`
+* `ELSE`: `else`
+* `WHILE`: `while`
+* `RETURN`: `return`
+* `INT`: `int`
+* `VOID`: `void`
+
+**가변길이 토큰**
+
+* `ID`: 식별자
+* `NUM`: 숫자
+
+**기호 토큰**
+
+* `ASSIGN`: `=`
+* `EQ`: `==`
+* `NE`: `!=`
+* `LT`: `<`
+* `LE`: `<=`
+* `GT`: `>`
+* `GE`: `>=`
+* `PLUS`: `+`
+* `MINUS`: `-`
+* `TIMES`: `*`
+* `OVER`: `/`
+* `LPAREN`: `(`
+* `RPAREN`: `)`
+* `LBRACE`: `[`
+* `RBRACE`: `]`
+* `LCURLY`: `{`
+* `RCURLY`: `}`
+* `SEMI`: `;`
+* `COMMA`: `,`
+
+**토큰에 포함되지 않는 스펙**
+
+* `/*` - `*/`: 주석 (토큰에 포함하지 않음)
+
+위와 같은 토큰 타입을 기반으로 토크나이징하는 것이 목적이다.
+
+### Using `scan.c`
+
+`scan.c`에서는 올바른 `getToken`을 작성해야 한다.
+
+`getToken`을 작성하기에 앞서 전이가능한 `STATE`를 작성한다. 특히 `<`, `>`, `!`, `=`, `/`의 경우에는 단 한 글자만 받는게 아니라 그 다음 문자에 따라 산출할 토큰이 달라질 수 있으므로 그에 따른 `STATE`를 만든다.
+
+결과적으로 필요한 STATE는 다음과 같다.
+
+```
+START, INOVER, INCOMMENT, ASTERCOMMENT, INASSIGN, INLT, INGT, INNE, INNUM, INID, DONE
+```
+
+이를 이용해 `getToken`의 DFA를 작성할 수 있다.
+
+```mermaid
+stateDiagram-v2
+ START
+ state comment {
+ INOVER
+ INCOMMENT
+ ASTERCOMMENT
+ }
+
+
+ INASSIGN
+ INLT
+ INGT
+ INNE
+ state multichar {
+ INNUM
+ INID
+ }
+
+
+ state done {
+ DONE
+ }
+
+
+
+ START --> INNUM: isdigit
+ INNUM --> INNUM: isdigit
+ INNUM --> DONE: else with unget
+
+ START --> INID: isalpha
+ INID --> INID: isalnum
+ INID --> DONE: else with unget
+
+ START --> INASSIGN: =
+ INASSIGN --> DONE: =
+ INASSIGN --> DONE: else with unget
+
+ START --> INLT: \<
+ INLT --> DONE: =
+ INLT --> DONE: else with unget
+
+ START --> INGT: \>
+ INGT --> DONE: =
+ INGT --> DONE: else with unget
+
+ START --> INNE: !
+ INNE --> DONE: =
+ INNE --> DONE: else with unget and return ERROR
+
+
+ START --> INOVER: /
+ INOVER --> INCOMMENT: \*
+ INCOMMENT --> ASTERCOMMENT: \*
+ ASTERCOMMENT --> INCOMMENT: else
+ ASTERCOMMENT --> START: /
+
+```
+
+이를 통해 `scan.c`를 작성하면 된다.
+
+이때 `tokenString`은 항상 넣되 (하지만 NUM, ID 토큰에서만 필요함) comment때만 안 넣으면 된다. `unget`할때도 안넣어야 한다.
+
+### Using Lex (cminus.l)
+
+tiny의 lex파일처럼 간단하게 넣고 컴파일하면 된다.
+
+하나 중요한 점은 comment를 구현할 때, `prev`와 `now`를 각 과정에서 계속 업데이트 해가면서 `now == '/' && prev == '*'` 일때까지 계속 `input()`을 받아주면 된다.
+
+## Examples & Result
+
+
+
+
+| cminus file |
+result text file |
+
+
+|
+
+```c { .line-numbers }
+/* 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));
+}
+
+```
+
+ |
+
+
+```scanres
+
+C-MINUS COMPILATION: ./test1.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: EOF
+```
+
+
+ |
+
+
+
+
+|
+
+```c {.line-numbers}
+void main(void)
+{
+ int i; int x[5];
+
+ i = 0;
+ while( i < 5 )
+ {
+ x[i] = input();
+
+ i = i + 1;
+ }
+
+ i = 0;
+ while( i <= 4 )
+ {
+ if( x[i] != 0 )
+ {
+ output(x[i]);
+ }
+ }
+}
+
+```
+
+ |
+
+
+
+```scanres
+
+C-MINUS COMPILATION: ./test2.cm
+ 1: reserved word: void
+ 1: ID, name= main
+ 1: (
+ 1: reserved word: void
+ 1: )
+ 2: {
+ 3: reserved word: int
+ 3: ID, name= i
+ 3: ;
+ 3: reserved word: int
+ 3: ID, name= x
+ 3: [
+ 3: NUM, val= 5
+ 3: ]
+ 3: ;
+ 5: ID, name= i
+ 5: =
+ 5: NUM, val= 0
+ 5: ;
+ 6: reserved word: while
+ 6: (
+ 6: ID, name= i
+ 6: <
+ 6: NUM, val= 5
+ 6: )
+ 7: {
+ 8: ID, name= x
+ 8: [
+ 8: ID, name= i
+ 8: ]
+ 8: =
+ 8: ID, name= input
+ 8: (
+ 8: )
+ 8: ;
+ 10: ID, name= i
+ 10: =
+ 10: ID, name= i
+ 10: +
+ 10: NUM, val= 1
+ 10: ;
+ 11: }
+ 13: ID, name= i
+ 13: =
+ 13: NUM, val= 0
+ 13: ;
+ 14: reserved word: while
+ 14: (
+ 14: ID, name= i
+ 14: <=
+ 14: NUM, val= 4
+ 14: )
+ 15: {
+ 16: reserved word: if
+ 16: (
+ 16: ID, name= x
+ 16: [
+ 16: ID, name= i
+ 16: ]
+ 16: !=
+ 16: NUM, val= 0
+ 16: )
+ 17: {
+ 18: ID, name= output
+ 18: (
+ 18: ID, name= x
+ 18: [
+ 18: ID, name= i
+ 18: ]
+ 18: )
+ 18: ;
+ 19: }
+ 20: }
+ 21: }
+ 22: EOF
+
+```
+
+ |
+
+
+
\ No newline at end of file
diff --git a/out/lex.pdf b/out/lex.pdf
new file mode 100644
index 0000000..54f31a8
Binary files /dev/null and b/out/lex.pdf differ
diff --git a/src/2024062806.md b/src/2024062806.md
index 3a9658d..198c7ba 100644
--- a/src/2024062806.md
+++ b/src/2024062806.md
@@ -1,269 +1,135 @@
-# Lexical Analysis(Scanner) Report
+# Syntax Analysis (Parser) Report
* 주하진, 2024062806
## Compilation Environment and Method
-주어진 `Makefile`을 이용하여 C파일을 컴파일함.
-C파일은 `gcc`를 이용해서 컴파일한다.
-`Makefile`에서 산출되는 실행파일은 `cminus_cimpl`과 `cminus_lex`가 있으며 각각 `main.c util.c scan.c`, `main.c util.c lex.yy.c`를 컴파일한 오브젝트 파일을 필요로 한다.
+주어진 `Makefile`을 이용해 C파일과 `cminus.l`, `cminus.y`를 변환함.
+C파일은 `gcc`를 이용하고 `*.l`은 `flex`, `*.y`는 `yacc`을 이용함.
-`lex.yy.c`는 `flex -o lex.yy.c cminus.l`을 통해 생성된다.
+`Makefile`의 빌드 결과물 `cminus_parser`를 만들기 위해서 `main.c`, `util.c`, `lex.yy.o`, `y.tab.o`를 필요로 한다.
-## C-Minus Language
+## C-Minus Parser Implementation
-C-Minus에서 필요한 토큰타입변수와 그에 대한 설명은 다음과 같다.
+C-Minus Parser 구현을 위해 다음 세 파일의 큰 수정이 필요했다.
-**특수 토큰**
+* `globals.h`
+* `util.c`, `util.h`
+* `cminus.y` (Important)
-* `ENDFILE`: 파일끝
-* `ERROR`: 에러
+### `globals.h`
-**키워드 토큰**
+여러개의 Kind Enum을 추가하였다.
+* NodeKind(큰 분류)
+* StmtKind(Statement의 종류)
+* ExpKind(Expression의 종류)
+* DeclKind(Declaration의 종류)
+* TypeKind(Declaration에서 Type을 구분하기 위해 사용, 실제로 파스트리에 들어가진 않음, var_declaration에서 참조하기 위한 목적.)
-* `IF`: `if`
-* `THEN`: `then`
-* `ELSE`: `else`
-* `WHILE`: `while`
-* `RETURN`: `return`
-* `INT`: `int`
-* `VOID`: `void`
+**StmtKind**
+* IfK: if문
+* IterK: while문
+* ReturnK: return문
+* CompK: 여러개 있는 중괄호(복합) 문
-**가변길이 토큰**
+**ExpKind**
+* AssignK: 할당문
+* OpK: 연산자가 포함된 표현식
+* ConstK: 상수
+* IdK: 식별자
+* ArrIdK: 배열 식별자
+* CallK: 함수 호출
-* `ID`: 식별자
-* `NUM`: 숫자
+**DeclKind**
+* FuncK: 함수 선언
+* VarK: 변수 선언
+* ArrVarK: 배열 변수 선언
+* ArrParamK: 배열 매개변수
+* NonArrParamK: 매개변수
-**기호 토큰**
+**TypeKind**
+* TypeNameK: 선언의 타입
-* `ASSIGN`: `=`
-* `EQ`: `==`
-* `NE`: `!=`
-* `LT`: `<`
-* `LE`: `<=`
-* `GT`: `>`
-* `GE`: `>=`
-* `PLUS`: `+`
-* `MINUS`: `-`
-* `TIMES`: `*`
-* `OVER`: `/`
-* `LPAREN`: `(`
-* `RPAREN`: `)`
-* `LBRACE`: `[`
-* `RBRACE`: `]`
-* `LCURLY`: `{`
-* `RCURLY`: `}`
-* `SEMI`: `;`
-* `COMMA`: `,`
+-----
+`TreeNode`를 추가하였다.
-**토큰에 포함되지 않는 스펙**
-
-* `/*` - `*/`: 주석 (토큰에 포함하지 않음)
-
-위와 같은 토큰 타입을 기반으로 토크나이징하는 것이 목적이다.
-
-### Using `scan.c`
-
-`scan.c`에서는 올바른 `getToken`을 작성해야 한다.
-
-`getToken`을 작성하기에 앞서 전이가능한 `STATE`를 작성한다. 특히 `<`, `>`, `!`, `=`, `/`의 경우에는 단 한 글자만 받는게 아니라 그 다음 문자에 따라 산출할 토큰이 달라질 수 있으므로 그에 따른 `STATE`를 만든다.
-
-결과적으로 필요한 STATE는 다음과 같다.
-
-```
-START, INOVER, INCOMMENT, ASTERCOMMENT, INASSIGN, INLT, INGT, INNE, INNUM, INID, DONE
+```c
+typedef struct treeNode {
+ struct treeNode *child[MAXCHILDREN];
+ struct treeNode *sibling;
+ int lineno;
+ NodeKind nodekind;
+ union {
+ StmtKind stmt;
+ ExpKind exp;
+ DeclKind decl;
+ TypeKind type;
+ } kind;
+ union {
+ TokenType op;
+ int val;
+ char *name;
+ } attr;
+ ExpType type; /* for type checking of exps */
+} TreeNode;
```
-이를 이용해 `getToken`의 DFA를 작성할 수 있다.
+TreeNode 타입은 ParseTree의 노드를 나타내며, 자식 노드와 형제 노드를 가리키는 포인터 그리고 노드의 kind와 attr, type을 가진다.
-```mermaid
-stateDiagram-v2
- START
- state comment {
- INOVER
- INCOMMENT
- ASTERCOMMENT
- }
-
-
- INASSIGN
- INLT
- INGT
- INNE
- state multichar {
- INNUM
- INID
- }
-
+### `util.c`, `util.h`
- state done {
- DONE
- }
-
-
+`newStmtNode`, `newExpNode`, `newDeclNode`, `newTypeNode` 함수를 추가 및 수정했다. 각각 Statement, Expression, Declaration, Type 노드를 생성하는 함수이다.
- START --> INNUM: isdigit
- INNUM --> INNUM: isdigit
- INNUM --> DONE: else with unget
+Type을 출력하기 위해 `printType` 함수를 추가하였다.
- START --> INID: isalpha
- INID --> INID: isalnum
- INID --> DONE: else with unget
+printTree는 TreeNode를 출력하는 함수이다. nodeKind에 따라 구분하여 출력한다. 이때 type이 필요한 node이면 type도 같이 출력한다.
- START --> INASSIGN: =
- INASSIGN --> DONE: =
- INASSIGN --> DONE: else with unget
+### `cminus.y`(Important)
- START --> INLT: \<
- INLT --> DONE: =
- INLT --> DONE: else with unget
+cminus.y에서 토큰의 선언은 다음과 같이 했다.
- START --> INGT: \>
- INGT --> DONE: =
- INGT --> DONE: else with unget
-
- START --> INNE: !
- INNE --> DONE: =
- INNE --> DONE: else with unget and return ERROR
+```yacc
+%token IF ELSE WHILE RETURN INT VOID
+%token EQ NE LT LE GT GE LPAREN RPAREN LBRACE LCURLY RBRACE RCURLY SEMI
+%token ID NUM
- START --> INOVER: /
- INOVER --> INCOMMENT: \*
- INCOMMENT --> ASTERCOMMENT: \*
- ASTERCOMMENT --> INCOMMENT: else
- ASTERCOMMENT --> START: /
+%left PLUS MINUS
+%left TIMES OVER
+%right ASSIGN
+%nonassoc THEN
+%nonassoc ELSE
+
+%token ERROR
```
-이를 통해 `scan.c`를 작성하면 된다.
+나머지 부분은 제공된 grammar와 tiny.y의 많은 부분을 참고하여 작성했다.
-이때 `tokenString`은 항상 넣되 (하지만 NUM, ID 토큰에서만 필요함) comment때만 안 넣으면 된다. `unget`할때도 안넣어야 한다.
+이때 중요한 부분은 **dangling-else** 부분이다.
-### Using Lex (cminus.l)
+```yacc
+selection_stmt : IF LPAREN expression RPAREN statement %prec THEN {
+ ...
+} | IF LPAREN expression RPAREN statement ELSE statement {
+ ...
+};
+```
-tiny의 lex파일처럼 간단하게 넣고 컴파일하면 된다.
+`single-if`문의 우선순위를 `ELSE`보다 낮은 `THEN`으로 지정하여 Shift/Reduce Conflict를 해결했다.
-하나 중요한 점은 comment를 구현할 때, `prev`와 `now`를 각 과정에서 계속 업데이트 해가면서 `now == '/' && prev == '*'` 일때까지 계속 `input()`을 받아주면 된다.
-
-## Examples & Result
+## Results
+다음은 테스트 C-Minus 프로그램과 그에 대한 파스트리 출력 결과이다.
-| cminus file |
-result text file |
-
-
+| C-Minus Test Program |
+Parse Tree Output |
+
|
-```c { .line-numbers }
-/* 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));
-}
-
-```
-
- |
-
-
-```scanres
-
-C-MINUS COMPILATION: ./test1.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: EOF
-```
-
-
- |
-
-
-
-
-|
-
-```c {.line-numbers}
+```c
void main(void)
{
int i; int x[5];
@@ -285,95 +151,117 @@ void main(void)
}
}
}
+```
+ |
+```txt
+
+C-MINUS COMPILATION: test.2.txt
+
+Syntax tree:
+ Function Declaration: name = main, return type = void
+ Void Parameter
+ Compound Statement:
+ Variable Declaration: name = i, type = int
+ Variable Declaration: name = x, type = int[]
+ Const: 5
+ Assign:
+ Variable: name = i
+ Const: 0
+ While Statement:
+ Op: <
+ Variable: name = i
+ Const: 5
+ Compound Statement:
+ Assign:
+ Variable: name = x
+ Variable: name = i
+ Call: function name = input
+ Assign:
+ Variable: name = i
+ Op: +
+ Variable: name = i
+ Const: 1
+ Assign:
+ Variable: name = i
+ Const: 0
+ While Statement:
+ Op: <=
+ Variable: name = i
+ Const: 4
+ Compound Statement:
+ If Statement:
+ Op: !=
+ Variable: name = x
+ Variable: name = i
+ Const: 0
+ Compound Statement:
+ Call: function name = output
+ Variable: name = x
+ Variable: name = i
```
- |
-
+
+ |
|
-```scanres
-
-C-MINUS COMPILATION: ./test2.cm
- 1: reserved word: void
- 1: ID, name= main
- 1: (
- 1: reserved word: void
- 1: )
- 2: {
- 3: reserved word: int
- 3: ID, name= i
- 3: ;
- 3: reserved word: int
- 3: ID, name= x
- 3: [
- 3: NUM, val= 5
- 3: ]
- 3: ;
- 5: ID, name= i
- 5: =
- 5: NUM, val= 0
- 5: ;
- 6: reserved word: while
- 6: (
- 6: ID, name= i
- 6: <
- 6: NUM, val= 5
- 6: )
- 7: {
- 8: ID, name= x
- 8: [
- 8: ID, name= i
- 8: ]
- 8: =
- 8: ID, name= input
- 8: (
- 8: )
- 8: ;
- 10: ID, name= i
- 10: =
- 10: ID, name= i
- 10: +
- 10: NUM, val= 1
- 10: ;
- 11: }
- 13: ID, name= i
- 13: =
- 13: NUM, val= 0
- 13: ;
- 14: reserved word: while
- 14: (
- 14: ID, name= i
- 14: <=
- 14: NUM, val= 4
- 14: )
- 15: {
- 16: reserved word: if
- 16: (
- 16: ID, name= x
- 16: [
- 16: ID, name= i
- 16: ]
- 16: !=
- 16: NUM, val= 0
- 16: )
- 17: {
- 18: ID, name= output
- 18: (
- 18: ID, name= x
- 18: [
- 18: ID, name= i
- 18: ]
- 18: )
- 18: ;
- 19: }
- 20: }
- 21: }
- 22: EOF
-
+```c
+int main(void){
+ int a;
+ int b;
+ a = (b = 4) + 3;
+ if(a==b+(c*b+d))
+ while(1)
+ if(1)
+ a=2;
+ else a=3;
+}
```
+ |
+
+```txt
+
+C-MINUS COMPILATION: test.cm
+
+Syntax tree:
+ Function Declaration: name = main, return type = int
+ Void Parameter
+ Compound Statement:
+ Variable Declaration: name = a, type = int
+ Variable Declaration: name = b, type = int
+ Assign:
+ Variable: name = a
+ Op: +
+ Assign:
+ Variable: name = b
+ Const: 4
+ Const: 3
+ If Statement:
+ Op: ==
+ Variable: name = a
+ Op: +
+ Variable: name = b
+ Op: +
+ Op: *
+ Variable: name = c
+ Variable: name = b
+ Variable: name = d
+ While Statement:
+ Const: 1
+ If-Else Statement:
+ Const: 1
+ Assign:
+ Variable: name = a
+ Const: 2
+ Assign:
+ Variable: name = a
+ Const: 3
+```
+
+
|
+
\ No newline at end of file
diff --git a/src/2024062806.pdf b/src/2024062806.pdf
index 54f31a8..ddeb117 100644
Binary files a/src/2024062806.pdf and b/src/2024062806.pdf differ
diff --git a/src/Makefile b/src/Makefile
index 22a8a79..86a7bc0 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,37 +1,43 @@
-# Makefile for C-Minus Scanner
-# ./lex/tiny.l --> ./cminus.l
+# Makefile for C-Minus
+#
+# ./lex/tiny.l --> ./cminus.l (from Project 1)
+# ./yacc/tiny.y --> ./cminus.y
+# ./yacc/globals.h --> ./globals.h
-CC = gcc
+CC = gcc
CFLAGS = -W -Wall
-OBJS = main.o util.o scan.o
-OBJS_LEX = main.o util.o lex.yy.o
+OBJS = main.o util.o lex.yy.o y.tab.o
.PHONY: all clean
-all: cminus_cimpl cminus_lex
+all: cminus_parser
clean:
- -rm -vf cminus_cimpl cminus_lex *.o lex.yy.c
+ rm -vf cminus_parser *.o lex.yy.c y.tab.c y.tab.h y.output
-cminus_cimpl: $(OBJS)
- $(CC) $(CFLAGS) -o $@ $(OBJS)
+cminus_parser: $(OBJS)
+ $(CC) $(CFLAGS) $(OBJS) -o $@ -lfl
-cminus_lex: $(OBJS_LEX)
- $(CC) $(CFLAGS) -o $@ $(OBJS_LEX) -lfl
+main.o: main.c globals.h util.h scan.h parse.h y.tab.h
+ $(CC) $(CFLAGS) -c main.c
-main.o: main.c globals.h util.h scan.h
- $(CC) $(CFLAGS) -c -o $@ $<
+util.o: util.c util.h globals.h y.tab.h
+ $(CC) $(CFLAGS) -c util.c
-scan.o: scan.c globals.h util.h scan.h
- $(CC) $(CFLAGS) -c -o $@ $<
+scan.o: scan.c scan.h util.h globals.h y.tab.h
+ $(CC) $(CFLAGS) -c scan.c
-util.o: util.c globals.h util.h
- $(CC) $(CFLAGS) -c -o $@ $<
-
-lex.yy.o: lex.yy.c globals.h util.h scan.h
- $(CC) $(CFLAGS) -c -o $@ $<
+lex.yy.o: lex.yy.c scan.h util.h globals.h y.tab.h
+ $(CC) $(CFLAGS) -c lex.yy.c
lex.yy.c: cminus.l
- flex -o $@ $<
+ flex cminus.l
+y.tab.h: y.tab.c
+
+y.tab.o: y.tab.c parse.h
+ $(CC) $(CFLAGS) -c y.tab.c
+
+y.tab.c: cminus.y
+ yacc -d -Wcounterexamples -v cminus.y
diff --git a/src/cminus.y b/src/cminus.y
new file mode 100644
index 0000000..4ab1bdc
--- /dev/null
+++ b/src/cminus.y
@@ -0,0 +1,328 @@
+/****************************************************/
+/* File: tiny.y */
+/* The TINY Yacc/Bison specification file */
+/* Compiler Construction: Principles and Practice */
+/* Kenneth C. Louden */
+/****************************************************/
+%{
+#define YYPARSER /* distinguishes Yacc output from other code files */
+
+#include "globals.h"
+#include "util.h"
+#include "scan.h"
+#include "parse.h"
+
+#define YYSTYPE TreeNode *
+static char * savedName; /* for use in assignments */
+static int savedNumber;
+static int savedLineNo; /* ditto */
+static TreeNode * savedTree; /* stores syntax tree for later return */
+static int yylex(void); // added 11/2/11 to ensure no conflict with lex
+
+%}
+
+%token IF ELSE WHILE RETURN INT VOID
+%token EQ NE LT LE GT GE LPAREN RPAREN LBRACE LCURLY RBRACE RCURLY SEMI COMMA
+%token ID NUM
+
+%left PLUS MINUS
+%left TIMES OVER
+%right ASSIGN
+
+%nonassoc THEN
+%nonassoc ELSE
+
+%token ERROR
+
+%% /* Grammar for C-MINUS */
+
+program : declaration_list
+ {savedTree = $1;};
+
+declaration_list : declaration_list declaration {
+ YYSTYPE t = $1;
+ if (t != NULL) {
+ while (t->sibling != NULL) {
+ t = t->sibling;
+ }
+ t->sibling = $2;
+ $$ = $1;
+ } else { $$ = $2; };
+ }
+ | declaration { $$ = $1; }
+ ;
+
+declaration : var_declaration {$$ = $1; } | func_declaration { $$ = $1; };
+
+name_specifier : ID {
+ savedName = copyString(tokenString);
+ savedLineNo = lineno;
+};
+
+number_specifier : NUM {
+ savedNumber = atoi(tokenString);
+ savedLineNo = lineno;
+};
+
+var_declaration : type_specifier name_specifier SEMI {
+ $$ = newDeclNode(VarK);
+ $$->lineno = savedLineNo;
+ $$->attr.name = savedName;
+ $$->type = $1->type;
+ free($1);
+} | type_specifier name_specifier LBRACE number_specifier RBRACE SEMI {
+ $$ = newDeclNode(ArrVarK);
+ $$->lineno = savedLineNo;
+ $$->type = IntegerArray;
+ $$->attr.name = savedName;
+ free($1);
+ $$->child[0] = newExpNode(ConstK);
+ $$->child[0]->type = Integer;
+ $$->child[0]->attr.val = savedNumber;
+};
+
+type_specifier : INT {
+ $$ = newTypeNode(TypeNameK);
+ $$->type = Integer;
+}
+| VOID {
+ $$ = newTypeNode(TypeNameK);
+ $$->type = Void;
+};
+
+func_declaration : type_specifier name_specifier {
+ $$ = newDeclNode(FuncK);
+ $$->lineno = savedLineNo;
+ $$->attr.name = savedName;
+ $$->type = $1->type; /* 타입 바로 복사 */
+} LPAREN params RPAREN compound_stmt {
+ $$ = $3;
+ $$->child[0] = $5; /* params */
+ $$->child[1] = $7; /* compound_stmt */
+};
+
+params : param_list { $$ = $1; } | VOID {
+ $$ = newDeclNode(NonArrParamK);
+ $$->type = Void;
+ };
+
+param_list : param_list COMMA param {
+ YYSTYPE t = $1;
+ if (t != NULL) {
+ while (t->sibling != NULL) {
+ t = t->sibling;
+ }
+ t->sibling = $3;
+ $$ = $1;
+ } else {
+ $$ = $3;
+ };
+} | param {$$ = $1; };
+
+param : type_specifier name_specifier {
+ $$ = newDeclNode(NonArrParamK );
+ $$->attr.name = savedName;
+ $$->type = $1->type;
+} | type_specifier name_specifier LBRACE RBRACE {
+ $$ = newDeclNode(ArrParamK);
+ $$->type = $1->type;
+ $$->attr.name = savedName;
+};
+
+compound_stmt : LCURLY local_declarations statement_list RCURLY {
+ $$ = newStmtNode(CompK);
+ $$->lineno = lineno;
+ $$->child[0] = $2;
+ $$->child[1] = $3;
+};
+
+local_declarations : local_declarations var_declaration {
+ YYSTYPE t = $1;
+ if (t != NULL) {
+ while (t->sibling != NULL)
+ t = t->sibling;
+ t->sibling = $2;
+ $$ = $1;
+ } else $$ = $2;
+} | { $$ = NULL; };
+
+statement_list : statement_list statement {
+ YYSTYPE t = $1;
+ if (t != NULL) {
+ while (t->sibling != NULL)
+ t = t->sibling;
+ t->sibling = $2;
+ $$ = $1;
+ } else $$ = $2;
+} | { $$ = NULL; };
+
+statement : expression_stmt { $$ = $1; }
+ | compound_stmt { $$ = $1; }
+ | selection_stmt { $$ = $1; }
+ | iteration_stmt { $$ = $1; }
+ | return_stmt { $$ = $1; }
+ ;
+
+expression_stmt : expression SEMI { $$ = $1; }
+ | SEMI { $$ = NULL; }
+ ;
+selection_stmt : IF LPAREN expression RPAREN statement %prec THEN {
+ $$ = newStmtNode(IfK);
+ $$->lineno = lineno;
+ $$->child[0] = $3;
+ $$->child[1] = $5;
+} | IF LPAREN expression RPAREN statement ELSE statement {
+ $$ = newStmtNode(IfK);
+ $$->lineno = lineno;
+ $$->child[0] = $3;
+ $$->child[1] = $5;
+ $$->child[2] = $7;
+};
+
+iteration_stmt : WHILE LPAREN expression RPAREN statement {
+ $$ = newStmtNode(IterK);
+ $$->lineno = lineno;
+ $$->child[0] = $3;
+ $$->child[1] = $5;
+};
+
+return_stmt : RETURN SEMI {
+ $$ = newStmtNode(ReturnK);
+ $$->lineno = lineno;
+} | RETURN expression SEMI {
+ $$ = newStmtNode(ReturnK);
+ $$->lineno = lineno;
+ $$->child[0] = $2;
+};
+
+expression : var ASSIGN expression {
+ $$ = newExpNode(AssignK);
+ $$->lineno = lineno;
+ $$->type = $3->type;
+ $$->child[0] = $1;
+ $$->child[1] = $3;
+} | simple_expression { $$ = $1; };
+
+var : name_specifier {
+ $$ = newExpNode(IdK);
+ $$->attr.name = savedName;
+} | name_specifier {
+ $$ = newExpNode(ArrIdK);
+ $$->attr.name = savedName;
+} LBRACE expression RBRACE {
+ $$ = $2;
+ $$->child[0] = $4;
+};
+
+simple_expression : additive_expression relop additive_expression {
+ $$ = $2;
+ $$->lineno = lineno;
+ $$->child[0] = $1;
+ $$->child[1] = $3;
+ $$->type = Integer;
+} | additive_expression { $$ = $1; };
+
+relop : LE {
+ $$ = newExpNode(OpK);
+ $$->attr.op = LE;
+} | LT {
+ $$ = newExpNode(OpK);
+ $$->attr.op = LT;
+} | GT {
+ $$ = newExpNode(OpK);
+ $$->attr.op = GT;
+} | GE {
+ $$ = newExpNode(OpK);
+ $$->attr.op = GE;
+} | EQ {
+ $$ = newExpNode(OpK);
+ $$->attr.op = EQ;
+} | NE {
+ $$ = newExpNode(OpK);
+ $$->attr.op = NE;
+};
+
+additive_expression : additive_expression addop term {
+ $$ = $2;
+ $$->lineno = lineno;
+ $$->child[0] = $1;
+ $$->child[1] = $3;
+} | term { $$ = $1; };
+
+addop : PLUS {
+ $$ = newExpNode(OpK);
+ $$->attr.op = PLUS;
+} | MINUS {
+ $$ = newExpNode(OpK);
+ $$->attr.op = MINUS;
+};
+
+term : term mulop factor {
+ $$ = $2;
+ $$->lineno = lineno;
+ $$->child[0] = $1;
+ $$->child[1] = $3;
+} | factor { $$ = $1; };
+
+mulop : TIMES {
+ $$ = newExpNode(OpK);
+ $$->attr.op = TIMES;
+} | OVER {
+ $$ = newExpNode(OpK);
+ $$->attr.op = OVER;
+};
+
+factor : LPAREN expression RPAREN { $$ = $2; }
+ | var { $$ = $1; }
+ | call { $$ = $1; }
+ | NUM {
+ $$ = newExpNode(ConstK);
+ $$->lineno = lineno;
+ $$->type = Integer;
+ $$->attr.val = atoi(tokenString);
+ }
+ ;
+
+call : name_specifier {
+ $$ = newExpNode(CallK);
+ $$->lineno = lineno;
+ $$->attr.name = savedName;
+ } LPAREN args RPAREN {
+ $$ = $2;
+ $$->child[0] = $4;
+ };
+
+args : arg_list { $$ = $1; } | { $$ = NULL; } ;
+
+arg_list : arg_list COMMA expression {
+ YYSTYPE t = $1;
+ if (t != NULL) {
+ while (t->sibling != NULL)
+ t = t->sibling;
+ t->sibling = $3;
+ $$ = $1;
+ } else $$ = $3;
+} | expression { $$ = $1; } ;
+
+
+%%
+
+int yyerror(char * message)
+{ fprintf(listing,"Syntax error at line %d: %s\n",lineno,message);
+ fprintf(listing,"Current token: ");
+ printToken(yychar,tokenString);
+ Error = TRUE;
+ return 0;
+}
+
+/* yylex calls getToken to make Yacc/Bison output
+ * compatible with ealier versions of the TINY scanner
+ */
+static int yylex(void)
+{ return getToken(); }
+
+TreeNode * parse(void)
+{ yyparse();
+ return savedTree;
+}
+
diff --git a/src/globals.h b/src/globals.h
index 5d09545..37446ee 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -9,9 +9,9 @@
#ifndef _GLOBALS_H_
#define _GLOBALS_H_
+#include