본문 바로가기
컴퓨터 지식

[컴파일러설계] Yacc를 이용한 C 어휘분석기 구현

by LiveData 2018. 12. 9.
반응형

컴파일러 설계


 

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]+)?)를 사용하여 인식

정수는 소수든 NUMreturn

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문을 실행한다.

반응형