컴파일러 설계
1. 개요(목적)
Lex를 이용해서 단어들을 인식하게 만든다. C언어의 명령어들을 인식하게 만들어서 C의 명령어나 심볼들을 출력하게 만든다. 그 외 변수나 숫자(정수, 소수 등) 인식하게 만든다. 함수를 이용해서 C 명령문을 실제로 동작하게 만들어본다. 더 나아가가 따로 Yacc의 함수를 만들어서 숫자들을 인식하여 간단한 사측연산을 할 수 있게 만든다.
2. 구현 내용
① LEX를 이용해서 값이 오면 인식하고 그 값을 반환하는 것을 구현
.
▶ Symbol : +, -, *, /, \, \n, if, else, while, for, char, int, double, identity(식별자) return 등을 인식하게 만들고 인식이 되면 출력.
(if) (for) (while) ( ) { }
▶ 숫자 : DECIMAL [0-9]* 까지의 정수를 통해 {DECIMAL}은 정수를 인식하게 만들었고 {DECIMAL}\.{DECIMAL}은 실수를 인식하게 만들었습니다.
(DEC, 3) (DEC,12) (NUM, 2.126)
▶ 연산 : 정수나 실수가 나왔을 시 뒤에 +,-,*,/ 가 나오면 다음 숫자를 연산하여 결과 값 을 출력합니다.
3 + 5 = 8 3.21/1.52=1.69
▶ 문자 : 식별자는 LETTER ([A-Za-z]) 로 단일문자와 IDENTIFIER ({LETTER} ({LETTER} | {DECI})*) 의 문자+숫자의 변수 인식할 수 있다.
(ID , a123) (ID , num123)
② YACC를 이용해서 숫자가 들어오면 전에 나온 숫자 연산 형태와 값을 우선순위 연산을 실행 합니다.
▶ 사측연산 : +,-,*,/ 로 *,/가 먼저 계산 한다. cal을 입력 후 계산식을 입력하면 parser() 함수로 yacc 인식기를 동작하게 하여 판별 후 계산한다.
cal 3+5*4; 4.2/3.3+5.7*2.7;
③ 실행
# yacc –dv y.y ☞ y.tab.h 와 y.tab.c생성
# lex Compile.l ☞ lex.yy.cc 생성
# cc –o a.out y.tab.c lex.yy.c ☞ 실행파일 a.out을 만듬
# ./a.out < input > out ☞ 입력한 input을 분석기로 변환한 out으로 보냄
④ 실행 결과
인식 변수 |
설명 |
DECIMAL |
정수를 인식. 인식한 값을 yylval로 전달 |
NUMBER |
실수를 인식. 인식한 값을 yylval로 전달 |
LOWER, UPPER, LETTER |
각각 소문자 대문자 혼합을 인식한 |
IDENTIFIER |
문자+숫자의 변수를 인식 |
“\”.*“\” |
각 심볼을 인식 |
\(, \), \{, \} |
중괄호 대괄호를 인식 |
; , = |
; , 값이 오면 그대로 전달하여 출력 |
+ - * / |
연산의 심볼이 오면 인식 |
\n |
엔터를 치면 라인의 line_count 값 올림. |
if, else, while, for char, int, void double, return
|
명령어들을 인식하면 출력을 해줌 // 차후 lex함수나 yacc로 구현 예정
|
▶ LEX 코드
⒧ Cal_num(실수 연산)
⑵ Cal_dec(정수 연산)
▶ Lex로 만든 2개의 숫자끼리 연산을 해줍니다. 정수나 실수의 숫자가 오면 다음 연산(+,-,*,/) 를 인식하고 다음 나오는 숫자를 인식하여 둘의 연산을 실행합니다.
But lex의 함수만으로 우선순위를 나누기 힘들어서 후에 YACC를 이용하였습니다.
<b> </b>
결 과
※ 각각의 인자 전달
▶ 각각의 인식한 값들을 인식하였다고 전달 받아 print 출력을 해줍니다. 정수나 숫자가 올 경우 전의 cal_dec, cal_num의 함수로 +,-,*,/ 의 연산 심볼이 오는지 확인하여 연산 심볼이 올 경우 연산을 하고 아닐 경우 숫자 인식값을 출력 합니다.
▶ YACC 코드
./실행
▶ Lex 동작 원리
( 3+2*5 )
⑴ 3을 primary_expr 로 인식하고 term 으로 올라와 *나 / 가 있는지 확인 후 없으면
다시 expr로 바꾸준 후 shift를 해준다.
⑵ 그다음 ‘+’ 가 들어오고 어느 상황에 만족하지 않으므로 다음 shift를 한다.
⑶ +의 연산식이 완성되긴 하나 다음 나올 연산이 *인걸 알기 때문에 shift를 한다.
expr(3) |
‘+’ |
term(2) |
‘*’ |
primary_expr(5) |
⑷ { 이부분이 term MUL priamry_expr과 매칭되어 계산}
⑸ { expr ADD term 과 매칭되므로 계산 }
⑹ 최종적으로 13의 숫자가 남는다.
=> 우선순위 계산을 쉽게 할 수 있었다.