제 8 장  파서 생성기 YACC 사용하기.

Slides:



Advertisements
Similar presentations
스택 스택 추상자료형 스택 스택의 구현 스택의 응용 한빛미디어(주).
Advertisements

자료구조: CHAP 7 트리(1) 순천향대학교 컴퓨터공학과 하 상 호.
YACC 응용 예 Desktop Calculator.
쉽게 풀어쓴 C언어 Express 제5장 수식과 연산자 C Express Slide 1 (of 34)
제3장 C 프로그래밍 환경.
Internet Computing KUT Youn-Hee Han
C 프로그래밍 소개 숙명여대 창병모 2011 가을.
C로 쉽게 풀어쓴 자료구조 © Copyright 생능출판사 2011
5장. 리스트 리스트 학습목표 목록이나 도표처럼 여러 데이터를 관리할 수 있는 자료형을 추상화
Internet Computing KUT Youn-Hee Han
쉽게 풀어쓴 C언어 Express 제18장 입출력과 라이브러리 함수 C Express.
C 11장. 포인터의 활용 #include <stdio.h> int main(void) { int num;
쉽게 풀어쓴 C언어 Express 제17장 동적 메모리와 연결 리스트 C Express.
제9장 C 프로그래밍 환경 창병모
4장 스택.
처음으로 배우는 C 프로그래밍 제2부 기초 제5장 반복문.
CHAP 7:트리.
강의 #7 트리(Tree).
누구나 즐기는 C언어 콘서트 제4장 수식과 연산자.
배열, 포인터, 참조 배열은 같은 형을 가지는 변수들의 묶음이다..
제  3 장  Lex 사용하기.
head data link data link data link NULL a b c
HW#2 #1과 동일한 방법으로 argc와 argv를 사용함
Chapter 9 – 구조형과 리스트 처리 Outline 9.1 자신 참조 구조형 9.2 선형 연결 리스트 9.3 리스트 연산
10장 메모리 관리.
쉽게 풀어쓴 C언어 Express 제17장 동적 메모리와 연결 리스트 C Express.
쉽게 풀어쓴 C언어 Express 제17장 동적메모리와 연결리스트 C Express.
25장. 메모리 관리와 동적 할당.
동적메모리와 연결리스트 컴퓨터시뮬레이션학과 2016년 봄학기 담당교수 : 이형원 E304호,
윤성우의 열혈 C 프로그래밍 윤성우 저 열혈강의 C 프로그래밍 개정판 Chapter 02. 프로그램의 기본구성.
C 7장. 배열과 문자열 #include <stdio.h> int main(void) { int num;
쉽게 풀어쓴 C언어 Express 제14장 포인터 활용 C Express.
Term Project Team Member
14주차.
제 3 장 상수와 변수
10장 C 표준 파일 입출력 子曰 學而時習(실습?)之 不亦悅乎.
CHAP 8:우선순위큐 C로 쉽게 풀어쓴 자료구조 생능출판사 2011.
4장 제어문 선택문: if 문, if – else 문, switch 문
CHAP 7:트리 C로 쉽게 풀어쓴 자료구조 생능출판사 2005.
C 4장. 연산자 #include <stdio.h> int main(void) { int num;
Chapter 3 클래스. 최호성.
13. 포인터와 배열! 함께 이해하기.
Chapter 2 Lexical Elements, Operators, and the C System
4. 어휘 분석(Lexical analysis)
배열과 연결리스트 연결리스트 배열 메모리 할당이 연속적이어서 인덱스 사용시 검색이 빠르다.
CHAP 7:트리 C로 쉽게 풀어쓴 자료구조 생능출판사 2005.
컴퓨터의 기초 제 2강 - 변수와 자료형 , 연산자 2006년 3월 27일.
자전거를 배우려면 안장에 올라가 페달을 밟아라.
컴퓨터 프로그래밍 기초 - 4th : 수식과 연산자 -
제어문 & 반복문 C스터디 2주차.
3장. 변수와 연산자. 3장. 변수와 연산자 3-1 연산자, 덧셈 연산자 연산자란 무엇인가? 연산을 요구할 때 사용되는 기호 ex : +, -, *, / 3-1 연산자, 덧셈 연산자 연산자란 무엇인가? 연산을 요구할 때 사용되는 기호 ex : +, -, *, /
실습과제 1(조건문, ) 표준입력으로 수축기 혈압을 입력 받아 그에 따른 적당한 표현을 화면에 출력하는 프로그램을 if-else 문을 이용하여 작성.
제 3장 데이터형과 연산자 Hello!! C 언어 강성호 김학배 최우영.
CHAP 8:우선순위큐.
4. 어휘 분석(Lexical analysis)
C89(C++03) 프로그래밍 (Part 2) 7 배열 8 변수 범위 9 포인터 10 유도 자료형.
GDB - GNU Debugger 김진용.
컴퓨터 프로그래밍 기초 - 11th : 파일 입출력 및 구조체 -
Chapter 07 트리.
실습과제 1번 생성된 파일 basic.txt를 프로젝트 폴더에서 메모장으로 열고 내용을 확인
9장. C 언어의 핵심! 함수. 9장. C 언어의 핵심! 함수 9-1 함수의 정의와 선언 main 함수 다시 보기 : 함수의 기본 형태 { } 그림 9-1.
3주차: Control Flow and Others
argc, argv 의 사용방법 #include <stdio.h>
C 13장. 입출력 라이브러리 #include <stdio.h> int main(void) { int num;
C 4장. 연산자 #include <stdio.h> int main(void) { int num;
C.
printf("Global Korea\n");
3b장 구조체와 열거형 구조체의 정의 구조체 변수의 선언 구조체 초기화 및 사용 구조체 재정의 포인터를 이용해서 구조체 사용
배열.
Presentation transcript:

제 8 장  파서 생성기 YACC 사용하기

제 8 장  파서 생성기 YACC 사용하기 컴파일러를 프로그래밍 언어마다 각각 따로 만드는 것이 아니라, 문법만 있으면 LR 파싱 테이블을 자동으로 생성하는 도구인 YACC(Yet Another Compiler-Compiler)의 구조와 사용 방법을 살펴본다.

8.1 YACC 개요 그림 8.1 지금까지 살펴본 LR 파서 개념

문법에 따라 파싱 테이블 자동 생성 그림 8.2 파싱 테이블 자동 생성 개념이 포함된 LR 파서

YACC와 LEX의 연관 구동 그림 8.3 LEX와 YACC에 의한 프로그램 생성과 컴파일

YACC와 LEX 사이의 제어와 데이터 흐름 그림 8.4 YACC와 LEX 함수 사이의 제어와 데이터 흐름

8.2 YACC 스팩 YACC 스팩은 아래와 같이 선언부, 규칙 기술부, 지원 루틴부의 세부분으로 구성한다. 선언부 %%               선언부               %%               규칙 기술부

8.2.1 선언부 아래는 선언부를 구성하는 예이다. % { ... % } %token ID %left '+'  '-' %left '*' '/'   ....... 위는 토큰으로 받아들이는 것은 식별자 ID이며, 연산자는 *, /, +, -이며 왼쪽부터 차례로 우선순위를 가지는데 *, /를 같은 우선순위로,  +, -를 같은 우선순위로 사용한다.

8.2.2 규칙 기술부 넌터미널  :    α  {액션}               |β  {액션}                 |γ  {액션}                 .                 .                ;

규칙 기술부 구성 예 %% line : expression { printf("%d \n,$1); }; expression :  expression  '+'  expression   { $$ = $1 + $3; }                        |   expression  '-'  expression   { $$ = $1 - $3; }                        |   expression  '*'  expression   { $$ = $1 * $3; }                        |   expression  '/'  expression   { $$ = $1 /  $3; }                        |   '(' expression ')'   { $$ = $2; }                        |   a;

이 규칙 기술은 지금까지 본문에서 많이 사용하던 산술 수식 문법을 YACC에서 읽을 수 있도록 구성한 것이다.      E → E  +  E | E  -  E | E *  E | E /  E | ( E ) | a { 액션 } 부분의 { $$ = $1 - $3; } 파싱 도중에 생성 규칙을 환원할 때 의미 분석을 위해 호출되는 부분

8.2.3 지원 루틴부 지원 루틴부는 규칙 기술 규칙 기술부의 { 액션 }에서 호출하는 함수를 기술한다. 의미 분석을 위한 루틴 { 액션 }에서 지원 루틴부에 있는 해당 함수가 호출되어 구동

정수를 읽어서 사칙 연산을 수행하는 탁상용 계산기에 대한 파서와 의미 분석을 수행하는 YACC 스팩 예 % {      C 코드가 들어가는 부분 % } %token NUMBER %left '+'  '-' %left '*' '/' %% line :  expression  { printf("%d \n,$1); }; expression :  expression  '+'  expression   { $$ = $1 + $3; }                        |   expression  '-'  expression   { $$ = $1 - $3; }                        |   expression  '*'  expression   { $$ = $1 * $3; }                        |   expression  '/'  expression   { $$ = $1 /  $3; }                        |   '(' expression ')'   { $$ = $2; }                        |   NUMBER; main() {        yyparse();  }

입력 스트링 5 + 4 * 3를 파싱한 스택과 실행한 결과 값

8.2.4 YACC 스팩 예 수식에 대한 중간 코드를 생성하는 LEX와 YACC의 전체 스팩 LEX 프로그램 %% [a-zA-Z]       {yylval = alloc(TOKEN); return OPERAND;} [∖t]            ;               return  yytext[0]; ∖n           {lineno++;  return yytext[0];}

YACC 시작 /*  아래는 YACC 프로그램이다. YACC 에는 구문 에러를 수정하는 기능이 있지만 이 예에서는 취급하지 않는다.  */ %{ #include <stdio.h> #include <alloc.h> typedef char  * string; #define YYSTYPE  string;     /* 파싱 스택에 넣을 자료형(타입) 검사  */ #define  TOKEN  1 #define  TEMP 0 int  temp = 0; struct node  {                char  name[3];  /*  "Th" 혹은 a, b, c, ...*/                struct  node  * next;   /* 연결 리스트 */               }; struct node  * tlist = NULL;     /* 리스트 헤드  */ char  * alloc  (int type); %}

연산자와 액션 %token OPERAND %left '+' '-' %left '*' '/' %left UMINUS UPLUS %% list:                               /*  빈 리스트  */            | list  '∖n'            | list  expr  '∖n'    { clear( ); }            ; expr:      '+'  expr  %prec  UPLUS   { $$ = $2; }            | '-' expr  %prec  UMINUS   { $$ = alloc(TEMP); codegen ("umin", $2, $$, 0); }            | expr '+' expr   { $$ = alloc(TEMP); codegen ("add", $1, $3, $$); }            | expr '-' expr    { $$ = alloc(TEMP); codegen ("sub", $1, $3, $$); }            | expr '*' expr   { $$ = alloc(TEMP); codegen ("mul", $1, $3, $$); }            | expr '/' expr    { $$ = alloc(TEMP); codegen ("div", $1, $3, $$); }            | '('  expr  ')'    { $$ = $2; }            | OPERAND     { $$ = $1; }

여러 함수 char *progname; int lineno = 1; #include "lex.yy.c" main (int argc, char  *argv[ ]) {   progname = argv[0];   yyparse( ); } yyerror ( char *s)   fprintf(stderr, "%s[%d]: %s∖n", progname, lineno, s);

여러 함수(계속) char * alloc ( int type) { static struct node * last = NULL;   struct  node  * ptr;   static  char  t[3] = "  "; ptr = (struct  node  *) malloc (sizeof  (struct  node)); ptr->next = NULL; if (last != NULL)  {last->next = ptr; last  = ptr;}     else  tlist  = last  =  ptr; if (type == TEMP)     {       t[0] = 'T';       t[1] = '0'  + temp++;       strcpy (last->name, t);     }    else strcpy (last->name, yytext);    return (char  *)  last; }

여러 함수(계속) clear ( ) /* 할당된 메모리를 해제하고 다음 expr 을 위하여 카운터를 리셋한다 */ { struct node * ptr;   while (tlist)     { ptr = tlist->next;       free (tlist);       tlist = ptr;     }   temp = 0; } codegen (char * operation, * operand1, * operand2, * result) /* 중간코드를 출력하기  */ {   if (result)  /*  umin 가 한 개의 피연산자와 결과만 가지면  */        printf ("∖t %s  %s  %s  %s∖n",  operation, operand1, operand2, result);   else printf("∖t %s  %s  %s∖n",  operation, operand1, operand2);

8.3 YACC 실행하는 방법 YACC 실행을 위해 아래 산술 수식 문법을 인식하는 LEX와 YACC 스팩을 작성하고 실행하여 보자.              G : E → E  +  T                    E → T                    T → T  *  F                    T → F                    F → ( E )                    F → id

단계 1. 어휘 분석을 수행하기 위해 아래와 같은 test.l 이라는 LEX 스팩 파일을 만든다. cs% vi test.lex         %{         #include <stdio.h>         %}         ID [A-Za-z][A-Za-z0-9]*         %%         [\t ];         {ID}         {printf("%s : Identifier\n", yytext);}         "*"|"+"|"("|")"  {printf("%s : Operator \n", yytext);}         void main()         {           yylex();         }         int yywrap()           return 1;

단계 2. 어휘 분석을 수행하기 위해 아래와 같이 LEX를 실행한다.          cs% lex test.l ( lex.yy.c 라는 파일이 생성된다) 단계 3. 단계 2에서 생성한 lex.yy.c 라는 C 파일을 컴파일한다.          cs% cc lex.yy.c –ll ( a.out 이라는 파일이 생성된다) 단계 4. 문장 temp * ((i + j) * yy) 을 예로 하여 입력 파일 input.dat 을 작성한다.          cs% vi input.dat

단계 5. 입력 파일 input.dat 을 이용하여 a.out 를 실행한다. cs% a.out < input.dat 단계 6. 다음에는 구문 분석을 위해서 아래와 같이 test.y 라는 YACC 스팩 파일을 만든다.      cs% vi test.y

단계 7. 구문 분석을 수행한다.          cs% yacc -d  test.y ( y.tab.h, y.tab.c 파일을 생성한다) 단계 8. 위의 LEX 과정과 YACC 과정에서 생성된 C 파일을 컴파일한다.         cs% cc y.tab.c  lex.yy.c -ly -ll 이 결과에서 생성한 실행파일을 input.dat 파일을 입력으로 실행한 결과를 출력한다.

temp* ((i + j) * yy) 를 실행하는 과정 예

실습 8.1 위에서 사용한 문법을 아래와 같이 첨가 문법으로 수정하여 LEX와 YACC를 단계별로 다시 실행하고 결과를 분석하시오. 또 위의 예와 비교하시오.        G : E ' → E                    E → E  +  T                    E → T                    T → T  *  F                    T → F                    F → ( E )                    F → id 실습 8.1의 결과를 스스로 관찰하시오.

실습 8.2 실습 8.1에서 작성한 문법으로 아래 문장을 인식하는 LEX와 YACC 스팩을 작성하여 단계별로 실행하고 결과를 분석하시오.            a + k * ( b *(i + j)) 실습 8.2의 결과를 스스로 관찰하시오.

8.4 YACC 실습하기 실습 8.3 아래 YACC과 LEX를 실행하고 각 입력 스트링에 대한 출력 결과를 보이시오. 또 어느 입력 스트링에 대하여 구문 에러를 탐지하는지 실행하고 결과를 분석하시오. (1)  ㄱㄴ (2)  ㄴㄱㄷㄷ (3)  ㄱㄴㄴㄱㄷㄴㄷㄴ (4)  ㄴㄴㄱㄷㄴc  (5)  ㄴㄴㄱㄷㄴㄴ

실습 8. 4 다음 형식의 언어를 인식하는 파서를 생성하는 LEX 스팩과 YACC 스팩이다 E → E + T | T  T → T * F F → ( E) | id         (1)  a + k * ( b * (i + j)         (2)  a + b + c * knu         (3)  d + (as + j * l)

실습 8.5 정수 연산을 수행하는 탁상용 계산기를 LEX와 YACC 프로그램으로 구현하고 아래 각 수식을 입력하여 수행한 결과를 분석하시오. (1) 2 + 4 (2) 4 + 5 * 4 (3) ( 6 - 5 + 4) - (3 * 5 + 2) * 5 (4) -5 + 4 + (-3 - 2)

실습 8. 6 아래는 유동소수점 연산을 수행하는 탁상용 계산기를 LEX와 YACC 프로그램으로 구현하였다 실습 8.6 아래는 유동소수점 연산을 수행하는 탁상용 계산기를 LEX와 YACC 프로그램으로 구현하였다.아래 각 수식을 입력으로 계산하고 결과를 분석하시오. 그러나 이 프로그램은 여러 곳에 에러가 있어서 올바르게 작동하지 않을 것이다. LEX와 YACC의 구문 에러, C 프로그래밍 언어의 구문 에러, 실행 에러, 에러 메시지를 출력하지 않는 것 등이다. 이 에러를 찾아 수정하고 실행하시오. (1) 6 + 4.2e-2     (2) 4 * 3 - 2 / 0      (3) (4 + 8) * 6 / 3  (4) 6 / (12 * 4 - 7 * 2.3)

실습 8. 7 어떤 수식을 파스 트리로 변환하는 YACC 프로그램을 작성하시오 실습 8.7 어떤 수식을 파스 트리로 변환하는 YACC 프로그램을 작성하시오. 피연산자는 단일 문자나 숫자이고, 연산자는 일반적인 우선순위를 가지는 더하기, 빼기, 곱하기, 나누기이다. yylex( ) 함수는 LEX로 만들거나 C로 직접 작성한다. 입력은 아래 각 줄에 있는 수식이고 stdout 에 파스트리를 전위 표기 형식으로 출력하시오(아래와 같이 출력하여야 한다). 입력(중위 수식)       파스 트리출력 (전위 수식) (1)  (8 + a) * b           * + 8 a b (2)  7 + a * b            + 7 * a b

실습 8.8 아래와 같은 형식의 언어를 인식하는 구문 분석기를 작성하시오.    Exp → Exp Op Exp | ( Exp ) | Number         Op → + | - | * Number →  0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

실습 8.10 일반적으로 많이 사용하는 데이터베이스 명령어의 문법을 검사하는 구문 분석기를 YACC와 LEX를 이용하여 구현하시오. 이 구문 분석기에서는 최소한 아래 명령어는 취급하여야 한다.        RETRIEVE  학생성적파일        DISPLAY  FOR  성적  >=  90        PRINT FOR  이름 = "최하늘"

제 8 장 끝