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

Add lexical analyzer

parents
No related branches found
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