Skip to content
Snippets Groups Projects
Commit 466211ac authored by lang0909's avatar lang0909
Browse files

Add lexical analyzer

parents
Branches
No related tags found
No related merge requests found
Pipeline #2131 canceled
%{
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include"parser.h"
/************************************************************************************
* *
* 매크로 선언 *
* *
* TOKEN_LIST_MAX - 배열로 구현되는 토큰 리스트의 사이즈. *
* 샘플로 제공되는 해당 어휘분석기에서 토큰 리스트 배열에 저장되는 아이템은 *
* 최대 100개를 넘지 않는다고 가정한다. *
* *
* TOKEN_VALUE_MAX - 토큰 리스트의 아이템 중 value 문자열 사이즈 *
* 샘플로 제공되는 해당 어휘분석기에서 각 토큰에 해당하는 값은 *
* 최대 10자를 넘지 않는다고 가정한다. *
* *
* SYMBOL_TABLE_MAX - 배열로 구현되는 심볼테이블의 사이즈. *
* 해당 샘플로 제공되는 어휘분석기에서 심볼 테이블 배열에 저장되는 아이템은 *
* 최대 100개를 넘지 않는다고 가정한다. *
* *
* SYMBOL_MAX - 심볼 테이블에 저장되는 심볼 문자열 사이즈 *
* 샘플로 제공되는 해당 어휘분석기에서 심볼은 최대 10자를 넘지 않는다고 가정한다. *
* *
* (주의) 2차 과제에서 주어진 조건과 다릅니다!!. *
* 위에서의 가정은 샘플로 제공되는 어휘 분석기의 구현을 간단하게 하기 *
* 위한 것입니다. *
* *
************************************************************************************/
#define TOKEN_LIST_MAX 100
#define SYMBOL_TABLE_MAX 100
/************************************************************************
* *
* 토큰들을 선언한 enum *
* *
* ID - 변수(Identifier)에 대한 토큰 *
* INT - 정수 상수에 대한 토큰 *
* REAL - 정수 실수에 대한 토큰 *
* PLUS - 덧셈 연산자에 대한 토큰 *
* MINUS - 뺄셈 연산자에 대한 토큰 *
* MUL - 곱셈 연산자에 대한 토큰 *
* DIV - 나눗셈 연산자에 대한 토큰 *
* ASSIGN - Assignment 연산자에 대한 토큰 *
* LP - 왼 괄호 특수 문자에 대한 토큰 *
* RP - 오른 괄호 특수 문자에 대한 토큰 *
* *
* (주의) 반드시 이걸 사용해서 구현 안하셔도 됩니다 !!. *
* (주의) 본인이 편한 방식으로 구현 하셔도 됩니다 !!. *
* *
***********************************************************************/
/************************************************************************
* *
* 토큰 리스트를 위한 구조체 *
* 토큰 리스트는 배열로 구성한다. *
* *
* 토큰 리스트는 다음과 같이 구성된다. *
* token(@TOKEN) - lexical analyzer에서 사용하는 토큰 *
* value(@char[10]) - 토큰에 해당하는 값 (Lexeme이 아닙니다.) *
* (value는 최대 10자를 넘지 않는다고 가정한다.) *
* *
* ex1) > var = 10 *
* *
* TOKEN VALUE *
* *
* ID var *
* ASSIGN *
* NUM 10 *
* *
* ex2) > 10 + 5.23 *
* *
* TOKEN VALUE *
* *
* NUM 10 *
* PLUS *
* NUM 5.23 *
* *
* (주의) 반드시 이걸 사용해서 구현 안하셔도 됩니다 !!. *
* (주의) 본인이 편한 방식으로 구현 하셔도 됩니다 !!. *
* *
***********************************************************************/
/************************************************************************
* *
* 심볼테이블을 위한 구조체 *
* 심볼테이블은 배열로 구성한다. *
* *
* 심볼테이블은 다음과 같이 구성된다. *
* symbol(@char[10]) - 입력한 수식에서 변수(Identifier)가 저장된다. *
* (symbol은 최대 10자를 넘지 않는다고 가정한다.) *
* type(@TOKEN) - 변수에 저장되는 값이 정수인지 실수인지 *
* 구분하기 위한 타입 정보입니다. *
* value(@union) - 변수에 저장되는 값을 나타냅니다. *
* *
* (주의) 반드시 이걸 사용해서 구현 안하셔도 됩니다 !!. *
* (주의) 본인이 편한 방식으로 구현 하셔도 됩니다 !!. *
* *
***********************************************************************/
/* Variables */
TOKEN_LIST token_list[TOKEN_LIST_MAX]; // 사이즈가 100인 토큰 리스트 배열
SYMBOL_TABLE symbol_table[SYMBOL_TABLE_MAX]; // 사이즈가 100인 심볼 테이블 배열
int token_number = 0; // 토큰 리스트에 저장된 토큰의 수
int symbol_number = 0; // 심볼 테이블에 저장된 심볼의 수
int error_detection; // judge lexical error
/* Functions */
void do_lexical_analysis();
void yyerror();
void initialize_symbol_table();
bool is_symbol_duplicated(char* target);
int find_symbol(char* target);
void initialize_token_list();
void print_token_list();
void save_token(TOKEN token, char* value);
void save_symbol(char* symbol);
void addEnd(); //
%}
/*************************************************************************
* *
* 변수(Identifier) 에 대한 정규 표현식 *
* *
*************************************************************************/
id [a-zA-Z_][a-zA-Z0-9_]*
/**************************************************************************
* *
* 정수 상수에 대한 정규 표현식 *
* *
**************************************************************************/
integer 0|[1-9][0-9]*
/**************************************************************************
* *
* 실수 상수에 대한 정규 표현식 *
* *
**************************************************************************/
real (0|[1-9][0-9]*)\.(0*|[0-9]*[1-9])
/***************************************************************************
* *
* 구획 문자(delimiter)에 대한 정규 표현식 *
* *
***************************************************************************/
delim [ \t\r]
ws {delim}+
/******************************************************************************
* *
* 변수(Identifier)가 underscore만 이루어진 예외적인 경우를 처리하기 위한 *
* 정규 표현식 *
* *
******************************************************************************/
under_score [_]+
/**************************************************************************
* *
* 변수(Identifier)의 첫 글자가 숫자로 시작하는 예외적인 경우를 *
* 처리하기 위한 정규 표현식 *
* *
**************************************************************************/
digit_first [0-9]+[a-zA-Z|0-9|_]+
%%
/****************************************************************************
* *
* 탭(Tab, \t)이나 캐리지 리턴(Carriage return, \r)으로 이루어진 *
* 공백을 무시하기 위한 rule. *
* *
****************************************************************************/
{ws} ;
/****************************************************************************
* *
* 2차 과제에서 사용되는 연산자에 대한 rule. *
* *
****************************************************************************/
"+" {save_token(PLUS, "");}
"-" {save_token(MINUS, "");}
"*" {save_token(MUL, "");}
"/" {save_token(DIV, "");}
"=" {save_token(ASSIGN, "");}
/****************************************************************************
* *
* 2차 과제에서 사용되는 기타특수문자에 대한 rule. *
* *
****************************************************************************/
"(" {save_token(LP, "");}
")" {save_token(RP, "");}
/****************************************************************************
* *
* 개행문자(new line)에 대한 rule. *
* 개행 문자가 입력되면 어휘 분석을 종료한다. *
* *
****************************************************************************/
"\n" { /* 어휘 분석기를 종료 시킨다 */ return 0;}
/****************************************************************************
* *
* 상수에 대한 rule. *
* *
****************************************************************************/
{integer} {save_token(INT, yytext);}
{real} {save_token(REAL, yytext);}
/****************************************************************************
* *
* 변수 대한 rule. *
* *
****************************************************************************/
i{digit_first} {yyerror();return 0;}
{under_score} {yyerror();return 0;}
{id} { save_symbol(yytext); save_token(ID, yytext);}
/****************************************************************************
* *
* 위에서 정의한 rule 제외한 나머지는 모두 Lexical Error로 처리하는 rule. *
* *
****************************************************************************/
. {yyerror();return 0;}
%%
int main()
{
initialize_symbol_table(); // 심볼 테이블을 초기화 한다.
/****************************************************************************
* *
* 어휘 분석기를 테스트하기 위한 샘플 프로그램에서 *
* 프롬프트는 무한하게 계속 실행된다고 가정한다. *
* 따라서 프롬프트를 종료 시키는 과정은 따로 구현하지 않는다. *
* *
****************************************************************************/
while(!feof(stdin)) {
initialize_token_list(); // 토큰 리스트를 초기화 한다.
printf(">"); // 프롬프트를 출력한다.
do_lexical_analysis(); // 어휘 분석기를 호출한다.
if(error_detection == 1)
{
error_detection = 0;
continue;
}
addEnd();
if(token_list[0].token==0)
{
continue;
}
// print_token_list(); // 토큰리스트 출력
do_syntax_analysis();
}
fclose(yyin);
return 0;
}
/***********************************************************************
* *
* 함수 이름: initialize_symbol_table *
* 파라미터: 없음 *
* *
* 심볼 테이블을 초기화 한다. *
* *
**********************************************************************/
void initialize_symbol_table()
{
for(int i = 0; i < SYMBOL_TABLE_MAX; i++) {
symbol_table[i].symbol[0] = '\0';
symbol_table[i].value.integer_constant = 0;
}
}
/***********************************************************************
* *
* 함수 이름: initialize_token_list *
* 파라미터: 없음 *
* 리턴 타입: void *
* *
* 토큰 리스트를 초기화 한다. *
* *
**********************************************************************/
void initialize_token_list()
{
for(int i = 0; i < TOKEN_LIST_MAX; i++) {
token_list[i].token = 0;
token_list[i].value[0] = '\0';
token_number =0;
}
}
/***********************************************************************
* *
* 함수 이름: do_lexical_analysis *
* 파라미터: 없음 *
* 리턴 타입: void *
* *
* 입력한 수식에 대해 어휘를 분석한다. *
* *
**********************************************************************/
void do_lexical_analysis()
{
yyin = stdin;
yylex();
yyrestart(yyin);
}
/***********************************************************************
* *
* 함수 이름: yyerror *
* 파라미터: e(@char*) - 출력할 오류 메시지 *
* 리턴 타입: void *
* *
* lexical error에 대한 메시지를 출력한다. *
* *
**********************************************************************/
void yyerror()
{
error_detection = 1;
printf("lexical error\n");
}
/***********************************************************************
* *
* 함수 이름: save_token *
* 파라미터: token(@TOKEN) - 토큰의 종류 *
* value(@char*) - 토큰에 해당하는 값 *
* 리턴 타입: void *
* *
* 토큰 리스트에 토큰의 종류와 토큰에 해당하는 값을 저장한다. *
* *
**********************************************************************/
void save_token(TOKEN token, char* value)
{
token_list[token_number].token = token;
strcpy(token_list[token_number].value, value);
token_number++;
}
/***********************************************************************
* *
* 함수 이름: save_symbol *
* 파라미터: symbol(@char*) - 변수(Identifier) *
* 리턴 타입: void *
* *
* 심볼 테이블에 심볼과 심볼과 매칭되는 값을 저장한다. *
* 중복 되는 심볼은 저장하지 않는다. *
* *
**********************************************************************/
void save_symbol(char* symbol)
{
// 심볼이 중복되지 않는 경우
if(!is_symbol_duplicated(symbol)) {
// 심볼 테이블에 저장
strcpy(symbol_table[symbol_number].symbol, symbol);
symbol_table[symbol_number].set_up = 0;
symbol_number++;
}
}
/***********************************************************************
* *
* 함수 이름: is_symbol_duplicated *
* 파라미터: target(@char*) - 중복 체크할 대상인 심볼 *
* 리턴 타입: bool *
* *
* 심볼 테이블에 중복된 심볼이 있는 지 체크한다. *
* *
**********************************************************************/
bool is_symbol_duplicated(char* target)
{
for(int i = 0; i < symbol_number; i++) {
// 중복되는 경우
if(strcmp(symbol_table[i].symbol, target) == 0)
return true;
}
// 중복 안되는 경우
return false;
}
/****************************************************************************
* *
* 함수 이름: is_token_duplicated *
* 파라미터: target(@char*) - 중복 체크할 대상인 토큰 *
* 리턴 타입: int *
* *
* 심볼 테이블에 일치하는 심볼을 찾아 심볼 테이블 배열의 인덱스를 리턴한다. *
* *
****************************************************************************/
int find_symbol(char* target)
{
for(int i = 0; i < symbol_number; i++) {
// 일치하는 심볼을 찾은 경우
if(strcmp(symbol_table[i].symbol, target) == 0)
return i;
}
return -1;
}
/***********************************************************************
* *
* 함수 이름: print_token_list *
* 파라미터: 없음 *
* 리턴 타입: void *
* *
* 입력된 수식에 대해 토큰 리스트를 출력한다. *
* *
**********************************************************************/
void print_token_list()
{
int symbol_index = 0;
printf("%s%20s\n", "TOKEN", "LEXEME");
for(int i = 0; i < token_number; i++) {
switch(token_list[i].token)
{
case INT: printf("%s%16s\n", "INTEGER", token_list[i].value); break;
case REAL: printf("%s%16s\n", "REAL", token_list[i].value); break;
case ID:
if((symbol_index = find_symbol(token_list[i].value)) != -1)
{
printf("%s,%d%20s\n", "ID", symbol_index+1,
symbol_table[symbol_index].symbol);
}
break;
case PLUS: printf("%s\n", "PLUS"); break;
case MINUS: printf("%s\n", "MINUS"); break;
case MUL: printf("%s\n", "MUL"); break;
case DIV: printf("%s\n", "DIV"); break;
case ASSIGN: printf("%s\n", "ASSIGN"); break;
case LP: printf("%s\n", "LP"); break;
case RP: printf("%s\n", "RP"); break;
default: break;
}
}
}
void addEnd()
{
token_number = token_number+1;
token_list[token_number].token = 0;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment