컴파일러 설계
1. 개요(목적)
전에 만들었던 Lex는 단어들을 인식하게 만들었다. C언어의 명령어들을 인식하게 만들어서 C의 명령어나 심볼들을 인식했다고 출력만 하게 만들었다. 이번에는 yacc를 이용하여 더 체계화된 C 컴파일러를 만들어 볼 생각이다. 처음에 사측연산부터 시작해서 C명령 구문인 if, while, switch case, for, print과 같은 명령문도 만들어 볼 계획이다. 실제로 입력을 하면 인식했다고 출력이 아닌 다음 구문을 분석해 실제로 조건문이나 반복문을 실행하여 출력해주는 프로그램을 만들 것이다.
2. 구현 내용
- 실 행
lex Compiler.l
yacc -d y.y
gcc lex.yy.c y.tab.c
./a.out
① LEX를 이용해서 값이 오면 인식하고 그 값을 반환하는 것을 구현.
▶ Command : if, else, while, for, switch case, int, double, exit, default, end return 등을 인식하게 만들고 인식이 되면 출력.
if for while do ;
▶ 숫자 : PRIME 의 소수 ([0-9]+|([0-9]*\.[0-9]+)([eE][-+]?[0-9]+)?)를 사용하여 인식
정수는 소수든 NUM을 return
▶ Symbol : [-()<>=+*/%:;{}.] 이 나오면 yytext[0] 로 return 합니다
▶ 문자 : 식별자는 LETTER ([A-Za-z][A-Za-z]*) 로 변수 문자를 인식하여 return
(ID , a) (ID , num)
“Compile.l” -> lex파일
인식 변수 |
설명 |
PRIME |
실수,정수를 인식. 인식한 값 숫자를 리턴한다. |
IDENTIFIER |
문자의 변수를 인식후 리턴 |
“\”.*“\” () |
각 심볼을 인식 |
\(, \), \{, \} >=,<= |
중괄호 대괄호를 인식 |
; , =, ! |
; , ! 값이 오면 인식 리턴. |
+ - * / |
연산의 심볼이 오면 인식 |
++,-- |
1증가, 감소 인식후 리턴. |
if, else, while, for int, double, print switch case, end, exit, default, abs
|
명령어들을 인식하면 리턴. |
② YACC은 입력 값과 매치되는 것을 찾아준다. 토큰으로 나누어 입력된 값과 같은 것이 오면 이를 매치시켜 다음 값을 살펴본 후 문법에 맞는지 검사한다. 이 YACC는 자동으로 구문 분석을 생성해준다.
▶ 변수 : identity를 인식하여 설정한 변수에 숫자 값을 넣을 수 있다. int, double의 형식 을 지정하여 만들 수 있다.
ex) a=5; int I=0; double val=5.2+3.4; val=a;
▶ 사측연산 : +,-,*,/ 로 기본 연산과 변수들의 연산을 해준다.
ex) cal c=a+b; print(a+5+b);
▶ for : for( 처음 변수 ; 조건 ; 변수 상태 증가 값을 인식하여 for문의 다음 문장을 여러 번 실행하게 해준다.
ex) for(a=0;a<5;a++) print(a) ->a의 값을 5번 출력합니다.
▶ while : for( 처음 변수 ; 조건 ; 변수 상태 증가값을 인식하여 for문의 다음 문장을 여러 번 실행하게 해준다.
ex) for(a=0;a<5;a++) print(a) ->a의 값을 5번 출력합니다.
▶ if : for( 처음 변수 ; 조건 ; 변수 상태 증가값)을 인식하여 for문의 다음 문장을 여러 번 실행하게 해준다.
ex) for(a=0;a<5;a++) print(a) ->a의 값을 5번 출력합니다.
▶ Switch Case : for( 처음 변수 ; 조건 ; 변수 상태 증가값)을 인식하여 for문의 다음 문장을 여러 번 실행하게 해준다.
ex) for(a=0;a<5;a++) print(a) ->a의 값을 5번 출력합니다.
③ 실행
# lex Compile.l ☞ lex.yy.c 생성
# yacc –d y.y ☞ y.tab.h 와 y.tab.c생성
# gcc lex.yy.c y.tab.c ☞ 실행파일 a.out을 만듬
# ./a.out < input > out ☞ 입력한 input을 분석기로 변환한 out으로 보냄
“Compile.h”
☞ 각 파서들을 기억하기위해 노드를 만들어 매개 변수를 next에 기억하게 하고 나중에 함수를 동작 시켜 명령어를 만든다.
☞ dValue는 값을 기억한다.
“y.y” ->yacc파일
☞ %token 으로 Lex에서 인식하여 리턴한 값의 토큰을 생성한다.
☞ %type 으로 각각의 파서 형태를 정의하여 매치되는 다음 값을 인식하게 해준다.
※ 변수의 인식인 경우 ex) a=1;
ex) 사측 연산 과정
ex) For문 인식 과정
ex) if문 인식 과정
☞ EmptyStatement(비어있는 것을 파싱) ,LabeledStatement(Case 문 파싱)
ExpressionStatement(기초 사즉 연산이나 변수, 숫자를 인식)
IterationStatement(While, Do Whhile, For 같은 반복문을 인식)
Block( { , } 중괄호를 인식하여 범위를 알 수 있다)
☞ 각각 인식하였을 경우 노드를 생성하여 기억하게 만든다.
☞ ForInit ( 처음 for문의 변수를 초기화 한다. )
ForExpr ( for문의 조건문의 식을 만든다. )
ForIncr ( 얼만큼 증가 시킬 것인지 설정한다. )
Block ( { } 같은 중괄호 설정 )
Statement_list ( 괄호의 순서를 결정한다 )
Expression ( Assign_expr의 변수 값 설정이나 Basic_expr 의 기초 사측연산 수행)
☞ execute 의 기억하고 있는 노드들을 통해 va_arg로 각각 리턴된 매개변수 값을 읽어들여 명령들이 들어오면 인식하여 그 case문을 실행한다.