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 fileresult 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 fileresult text file
C-Minus Test ProgramParse 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 #include #include -#include #include #ifndef FALSE @@ -22,23 +22,56 @@ #define TRUE 1 #endif +#ifndef YYPARSER +#include "y.tab.h" +#define ENDFILE 0 +#endif /* MAXRESERVED = the number of reserved words */ #define MAXRESERVED 6 -typedef enum - /* book-keeping tokens */ - {ENDFILE,ERROR, - /* reserved words */ - IF,ELSE,WHILE,RETURN,INT,VOID, - /* multicharacter tokens */ - ID,NUM, - /* special symbols */ - ASSIGN,EQ,NE,LT,LE,GT,GE,PLUS,MINUS,TIMES,OVER,LPAREN,RPAREN,LBRACE,RBRACE,LCURLY,RCURLY,SEMI,COMMA - } TokenType; +#if 0 +typedef enum +/* book-keeping tokens */ +{ ENDFILE, + ERROR, + /* reserved words */ + IF, + ELSE, + WHILE, + RETURN, + INT, + VOID, + /* multicharacter tokens */ + ID, + NUM, + /* special symbols */ + ASSIGN, + EQ, + NE, + LT, + LE, + GT, + GE, + PLUS, + MINUS, + TIMES, + OVER, + LPAREN, + RPAREN, + LBRACE, + RBRACE, + LCURLY, + RCURLY, + SEMI, + COMMA +} TokenType; +#endif -extern FILE* source; /* source code text file */ -extern FILE* listing; /* listing output text file */ -extern FILE* code; /* code text file for TM simulator */ +typedef int TokenType; + +extern FILE *source; /* source code text file */ +extern FILE *listing; /* listing output text file */ +extern FILE *code; /* code text file for TM simulator */ extern int lineno; /* source line number for listing */ @@ -46,26 +79,52 @@ extern int lineno; /* source line number for listing */ /*********** Syntax tree for parsing ************/ /**************************************************/ -typedef enum {StmtK,ExpK} NodeKind; -typedef enum {IfK,RepeatK,AssignK,ReadK,WriteK} StmtKind; -typedef enum {OpK,ConstK,IdK} ExpKind; +typedef enum { StmtK, + ExpK, + DeclK, + TypeK } NodeKind; +typedef enum { CompK, + IfK, + IterK, /* WhileK*/ + ReturnK } StmtKind; +typedef enum { AssignK, + OpK, + ConstK, + IdK, + ArrIdK, + CallK } ExpKind; +typedef enum { FuncK, + VarK, + ArrVarK, + ArrParamK, + NonArrParamK } DeclKind; +typedef enum { TypeNameK } TypeKind; /* ExpType is used for type checking */ -typedef enum {Void,Integer,Boolean} ExpType; +typedef enum { Void, + Integer, + IntegerArray } ExpType; #define MAXCHILDREN 3 -typedef struct treeNode - { struct treeNode * child[MAXCHILDREN]; - struct treeNode * sibling; - int lineno; - NodeKind nodekind; - union { StmtKind stmt; ExpKind exp;} kind; - union { TokenType op; - int val; - char * name; } attr; - ExpType type; /* for type checking of exps */ - } TreeNode; +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; /**************************************************/ /*********** Flags for tracing ************/ @@ -100,5 +159,5 @@ extern int TraceAnalyze; extern int TraceCode; /* Error = TRUE prevents further passes if an error occurs */ -extern int Error; +extern int Error; #endif diff --git a/src/main.c b/src/main.c index 83c53f8..f0fbd70 100644 --- a/src/main.c +++ b/src/main.c @@ -8,7 +8,7 @@ #include "globals.h" /* set NO_PARSE to TRUE to get a scanner-only compiler */ -#define NO_PARSE TRUE +#define NO_PARSE FALSE /* set NO_ANALYZE to TRUE to get a parser-only compiler */ #define NO_ANALYZE TRUE @@ -38,8 +38,8 @@ FILE *code; /* allocate and set tracing flags */ int EchoSource = FALSE; -int TraceScan = TRUE; -int TraceParse = FALSE; +int TraceScan = FALSE; +int TraceParse = TRUE; int TraceAnalyze = FALSE; int TraceCode = FALSE; diff --git a/src/result1.txt b/src/result1.txt deleted file mode 100644 index 961c870..0000000 --- a/src/result1.txt +++ /dev/null @@ -1,73 +0,0 @@ - -C-MINUS COMPILATION: ./test.1.txt - 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 diff --git a/src/result2.txt b/src/result2.txt deleted file mode 100644 index 4733083..0000000 --- a/src/result2.txt +++ /dev/null @@ -1,77 +0,0 @@ - -C-MINUS COMPILATION: ./test.2.txt - 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 diff --git a/src/scan_result1.txt b/src/scan_result1.txt deleted file mode 100644 index 91ac571..0000000 --- a/src/scan_result1.txt +++ /dev/null @@ -1,73 +0,0 @@ - -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 diff --git a/src/scan_result2.txt b/src/scan_result2.txt deleted file mode 100644 index 4b1995d..0000000 --- a/src/scan_result2.txt +++ /dev/null @@ -1,77 +0,0 @@ - -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 diff --git a/src/test.cm b/src/test.cm deleted file mode 100644 index 1c31abd..0000000 --- a/src/test.cm +++ /dev/null @@ -1,5 +0,0 @@ -/* - - - -dddd \ No newline at end of file diff --git a/src/test1.cm b/src/test1.cm deleted file mode 100644 index 478c5e4..0000000 --- a/src/test1.cm +++ /dev/null @@ -1,16 +0,0 @@ -/* 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)); -} diff --git a/src/test2.cm b/src/test2.cm deleted file mode 100644 index 80bc4fa..0000000 --- a/src/test2.cm +++ /dev/null @@ -1,21 +0,0 @@ -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]); - } - } -} diff --git a/src/util.c b/src/util.c index 4bc50de..f35cea8 100644 --- a/src/util.c +++ b/src/util.c @@ -137,6 +137,36 @@ TreeNode *newExpNode(ExpKind kind) { return t; } +TreeNode *newDeclNode(DeclKind kind) { + TreeNode *t = (TreeNode *) malloc(sizeof(TreeNode)); + int i; + if (t == NULL) + fprintf(listing, "Out of memory error at line %d\n", lineno); + else { + for (i = 0; i < MAXCHILDREN; i++) t->child[i] = NULL; + t->sibling = NULL; + t->nodekind = DeclK; + t->kind.decl = kind; + t->lineno = lineno; + } + return t; +} + +TreeNode *newTypeNode(TypeKind kind) { + TreeNode *t = (TreeNode *) malloc(sizeof(TreeNode)); + int i; + if (t == NULL) + fprintf(listing, "Out of memory error at line %d\n", lineno); + else { + for (i = 0; i < MAXCHILDREN; i++) t->child[i] = NULL; + t->sibling = NULL; + t->nodekind = TypeK; + t->kind.type = kind; + t->lineno = lineno; + } + return t; +} + /* Function copyString allocates and makes a new * copy of an existing string */ @@ -169,6 +199,22 @@ static void printSpaces(void) { fprintf(listing, " "); } +void printType(TreeNode *tree) { + switch (tree->type) { + case Void: + fprintf(listing, "void"); + break; + case Integer: + fprintf(listing, "int"); + break; + case IntegerArray: + fprintf(listing, "int[]"); + break; + default: + return; + } +} + /* procedure printTree prints a syntax tree to the * listing file using indentation to indicate subtrees */ @@ -179,27 +225,28 @@ void printTree(TreeNode *tree) { printSpaces(); if (tree->nodekind == StmtK) { switch (tree->kind.stmt) { + case CompK: + fprintf(listing, "Compound Statement:\n"); + break; case IfK: - fprintf(listing, "If\n"); + fprintf(listing, "%s:\n", + (tree->child[2] != NULL) ? "If-Else Statement" : "If Statement"); break; - case RepeatK: - fprintf(listing, "Repeat\n"); + case IterK: + fprintf(listing, "While Statement:\n"); break; - case AssignK: - fprintf(listing, "Assign to: %s\n", tree->attr.name); - break; - case ReadK: - fprintf(listing, "Read: %s\n", tree->attr.name); - break; - case WriteK: - fprintf(listing, "Write\n"); + case ReturnK: + fprintf(listing, "Return Statement:\n"); break; default: - fprintf(listing, "Unknown ExpNode kind\n"); + fprintf(listing, "Unknown StmtNode kind\n"); break; } } else if (tree->nodekind == ExpK) { switch (tree->kind.exp) { + case AssignK: + fprintf(listing, "Assign:\n"); + break; case OpK: fprintf(listing, "Op: "); printToken(tree->attr.op, "\0"); @@ -208,12 +255,55 @@ void printTree(TreeNode *tree) { fprintf(listing, "Const: %d\n", tree->attr.val); break; case IdK: - fprintf(listing, "Id: %s\n", tree->attr.name); + fprintf(listing, "Variable: name = %s\n", tree->attr.name); + break; + case ArrIdK: + fprintf(listing, "Variable: name = %s\n", tree->attr.name); + break; + case CallK: + fprintf(listing, "Call: function name = %s\n", tree->attr.name); break; default: fprintf(listing, "Unknown ExpNode kind\n"); break; } + } else if (tree->nodekind == DeclK) { + switch (tree->kind.decl) { + case FuncK: + fprintf(listing, "Function Declaration: name = %s, return type = ", tree->attr.name); + printType(tree); + fprintf(listing, "\n"); + break; + case VarK: + fprintf(listing, "Variable Declaration: name = %s, type = ", tree->attr.name); + printType(tree); + fprintf(listing, "\n"); + break; + case ArrVarK: + fprintf(listing, "Variable Declaration: name = %s, type = ", tree->attr.name); + printType(tree); + fprintf(listing, "\n"); + break; + case NonArrParamK: + if (tree->type == Void) + fprintf(listing, "Void Parameter\n"); + else { + fprintf(listing, "Parameter: name = %s, type = ", tree->attr.name); + printType(tree); + fprintf(listing, "\n"); + } + break; + case ArrParamK: + fprintf(listing, "Parameter: name = %s, type = ", tree->attr.name); + printType(tree); + fprintf(listing, "\n"); + break; + default: + fprintf(listing, "Unknown DeclNode kind\n"); + break; + } + } else if (tree->nodekind == TypeK) { + } else fprintf(listing, "Unknown node kind\n"); for (i = 0; i < MAXCHILDREN; i++) diff --git a/src/util.h b/src/util.h index 36cfb83..3a363a1 100644 --- a/src/util.h +++ b/src/util.h @@ -25,6 +25,10 @@ TreeNode * newStmtNode(StmtKind); */ TreeNode * newExpNode(ExpKind); +TreeNode* newDeclNode(DeclKind); + +TreeNode* newTypeNode(TypeKind); + /* Function copyString allocates and makes a new * copy of an existing string */