add syntax
This commit is contained in:
@@ -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</br> 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 프로그램과 그에 대한 파스트리 출력 결과이다.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>cminus file</th>
|
||||
<th>result text file</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>C-Minus Test Program</th>
|
||||
<th>Parse Tree Output</th>
|
||||
</tr><tr>
|
||||
<td>
|
||||
|
||||
```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));
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
```c {.line-numbers}
|
||||
```c
|
||||
void main(void)
|
||||
{
|
||||
int i; int x[5];
|
||||
@@ -285,95 +151,117 @@ void main(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
</td><td>
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
</td>
|
||||
|
||||
</td></tr>
|
||||
<td><tr>
|
||||
<td>
|
||||
|
||||
```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;
|
||||
}
|
||||
```
|
||||
</td><td>
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</table>
|
||||
Reference in New Issue
Block a user