이번에 프로그래밍 언어론을 듣습니다. 그 첫 번째 과제로 Lex & Yacc를 이용하여 간단한 공학용 계산기를 만드는 것입니다. 사칙연산뿐만 아니라 변수도 저장할 수 있어야 하고 사용자 함수 역시 저장할 수 있어야 합니다.

  사용자 함수의 경우 구현하기가 조금 까다로워서 Flex와 Bison에서 제공하는 Recursive parser를 이용하여 처리하였습니다. 이 부분이 조금 어려웠고 처음 사용하는 것이라 코드가 이상해졌지만 그래도 문제 없이 돌아가는 것을 확인하였습니다.


engcalc.l

  1: %{
  2: #include <stdio.h>
  3: #include <stdlib.h>
  4: #include "engcalc.tab.h"
  5: #include "recursive_parsing.h"
  6: 
  7: // 재귀적인 parser 호출을 위한 코드
  8: /*
  9:  When in the lexer you have to access parm through the extra data.
 10: */
 11: #define PARM	yyget_extra(yyscanner)
 12: 
 13: /*
 14: ** We want to read from a the buffer in parm so we have to redefine the
 15: ** YY_INPUT macro (see section 10 of the flex manual 'The generated scanner')
 16: */
 17: #define YY_INPUT(buffer, res, max_size)				\
 18: do {												\
 19: 	if (PARM->pos >= PARM->length)					\
 20: 		res = YY_NULL;								\
 21: 	else											\
 22: 	{												\
 23: 		res = PARM->length - PARM->pos;				\
 24: 		res > (int)max_size ? res = max_size : 0;	\
 25: 		memcpy(buffer, PARM->buf + PARM->pos, res);	\
 26: 		PARM->pos += res;							\
 27: 	}												\
 28: } while (0)
 29: 
 30: // 재귀적인 parsing 호출을 위한 코드
 31: %}
 32: 
 33: /*
 34: ** We want the scanner to be reentrant, therefore generate no global variables.
 35: ** That what the 'reentrant' option is for.
 36: ** 'bison-bridge' is used to create a bison compatible scanner and share yylval
 37: */
 38: %option reentrant bison-bridge
 39: %option noyywrap
 40: %option nounput
 41: 
 42: LETTER	[A-Za-z]
 43: DIGIT	[0-9]
 44: 
 45: %%
 46: 
 47: [ \t]+							;						/* whitespace */
 48: 
 49: "="               				{ return EQU_T; }
 50: 
 51: "+"								{ return OP1; }			/* token binop '+' */
 52: "-"								{ return OP2; }			/* token binop '-' */
 53: "*"								{ return OP3; }			/* token binop '*' */
 54: "/"								{ return OP4; }			/* token binop '/' */
 55: "^"								{ return OP5; }			/* token binop '^' */
 56: "#"								{ return OP6; }			/* token binop '#' */
 57: "("               				{ return SMALLPL_T; }
 58: ")"               				{ return SMALLPR_T; }
 59: "["								{ return BIGPL_T; }
 60: "]"								{ return BIGPR_T; }
 61: 
 62: "sin"							{ return SIN; }
 63: "cos"							{ return COS; }
 64: "tan"							{ return TAN; }
 65: "log"							{ return LOG; }
 66: "ln"							{ return LN; }
 67: "exp"							{ return EXP; }
 68: "clear"							{ return CLEAR; }
 69: "clearf"						{ return CLEARF; }
 70: "exit"							{ return EXIT; }
 71: "\n"							{ return EOL; }
 72: 
 73: "("({LETTER})({LETTER}|{DIGIT}|_|,|[ ])*")"[ ]*"="[ ]*({LETTER}|{DIGIT}|_|\+|\-|\*|\/|\^|\#|[ ]|\(|\))+	{ yylval->TT_SYMT = strndup(yytext, yyleng); return FUNC_T; } // function parameter and body
 74: "("({LETTER}|{DIGIT}|_|,|[ ])*")"	{ yylval->TT_SYMT = strndup(yytext, yyleng); return FUNC_ARG_T; }	// function argument to use function call
 75: 
 76: ({LETTER})({LETTER}|{DIGIT}|_)*	{ yylval->TT_SYMT = strndup(yytext, yyleng); return SYMT; }	/* token id */
 77: ({DIGIT}+|{DIGIT}+\.{DIGIT}+)([eE][+-]?{DIGIT}+)? { yylval->TT_NUMBER = atof(yytext); return NUMBER; } /* token real number */
 78: 
 79: .                           yyerror();	// All other character is not understood by scanner, so call error function.
 80: %%
 81: 
 82: 
 83: 

engcalc.y

  1: %{
  2: // include whole header file to use this code.
  3: #include <stdio.h>
  4: #include <stdlib.h>
  5: #include <string.h>
  6: #include <math.h>
  7: 
  8: #include "recursive_parsing.h"
  9: #include "symboltable.h"
 10: 
 11: #define PI 3.14159265
 12: 
 13: extern SymbolTable* SymTab;	// SymTab Linked List
 14: static int Error_Flag = 0;	// Error 시 결과를 얘기하기 위한 전역변수
 15: 
 16: // declare function
 17: double my_sin(double x);
 18: double my_cos(double x);
 19: double my_tan(double x);
 20: double user_func_evaluate(char* func_name, char* func_arg);
 21: void user_func_define(char* func_name, char* func_all);
 22: extern void parse(char *buf, double *result);
 23: 
 24: %}
 25: 
 26: %pure_parser
 27: %parse-param {parse_parm *parm}
 28: %parse-param {void *scanner}
 29: %lex-param {yyscan_t *scanner}
 30: 
 31: %union
 32: {
 33: 	double TT_NUMBER;
 34: 	char* TT_SYMT;
 35: 	
 36: 	/* Non Terminal Type */
 37: 	int TT_Statement;
 38: 	double TT_Expression;
 39: 	double TT_Exp_func;
 40: 	double (*TT_BuiltFunc)();
 41: };
 42: 
 43: %token <TT_SYMT>	SYMT	/* id */
 44: %token <TT_SYMT>	FUNC_ARG_T	/* function real argument */
 45: %token <TT_SYMT>	FUNC_T	/* function parameter and body */
 46: %token <TT_NUMBER>	NUMBER	/* integer */
 47: %token OP1					/* '+' */
 48: %token OP2					/* '-' */
 49: %token OP3					/* '*' */
 50: %token OP4					/* '/' */
 51: 
 52: %token SMALLPL_T 			/* ( */
 53: %token SMALLPR_T 			/* ) */
 54: %token EQU_T 				/* = */
 55: %token BIGPL_T 				/* [ */
 56: %token BIGPR_T 				/* ] */
 57: 
 58: 
 59: %token SIN					/* sin() */
 60: %token COS					/* cos() */
 61: %token TAN					/* tan() */
 62: %token LOG					/* log() */
 63: %token LN					/* ln() */
 64: %token EXP					/* exp() */
 65: 
 66: %token CLEAR				/* clear */
 67: %token CLEARF				/* clearf */
 68: 
 69: %token EXIT					/* exit command */
 70: 
 71: %token EOL					/* End of Line */
 72: 
 73: %type <TT_Statement> Statement 
 74: %type <TT_Expression> Expression
 75: %type <TT_BuiltFunc> BuiltFunc
 76: %type <TT_Exp_func> Exp_func
 77: 
 78: /* 우선순위 */
 79: %right	EQU_T					/* = */
 80: %left	OP1 OP2  				/* + - */
 81: %left	OP3 OP4  				/* * / */
 82: %right	OP5 OP6  				/* ^ # */
 83: %nonassoc	UMINUS 				/* unary operation */
 84: %left	SMALLPL_T SMALLPR_T		/* () */
 85: 
 86: 
 87: %start		Goal				// Start symbol is Program
 88: 
 89: %%
 90: Goal:	Statement EOL	{ }	// 변수, 함수 생성 및 삭제
 91: 	|	Expression EOL	{	// 그 외 여러 expression
 92: 							if(!Error_Flag)
 93: 							{
 94: 								printf("Ans : %f\n", $1);
 95: 							}
 96: 							else
 97: 							{
 98: 								Error_Flag = 0;
 99: 							}
100: 						}
101: 	|	EXIT EOL		{ printf("Engineering Calculator Exit! Good Bye~\n"); exit(0); }	// 종료
102: 	|	EQU_T Exp_func	{	// function define시 사용하는 코드
103: 						}
104: 	|	Expression		{	// function call 시 함수 argument parsing
105: 							parm->result = $1;
106: 						}
107: 	;
108: 	
109: Statement:	SYMT EQU_T Expression		{	// 변수 생성.
110: 											SymbolTable* temp;
111: 											if(NULL == (temp = Symbol_Search($1, 1)))
112: 											{
113: 												temp = malloc(sizeof(SymbolTable));
114: 												if(NULL == temp)
115: 												{
116: 													printf("malloc error!\n");
117: 													exit(1);
118: 												}
119: 												temp->name = $1;
120: 												temp->num_value = $3;
121: 												temp->type = 1;	// 변수는 1
122: 												temp->left_symbol = NULL;
123: 												temp->right_symbol = NULL;
124: 												Symbol_Insert(temp);
125: 												printf("make variable %s = %f\n", $1, $3);
126: 											}
127: 											// 변수가 이미 있다면 값 변경.
128: 											else
129: 											{
130: 												temp->num_value = $3;
131: 												printf("Ans : %f\n", $3);
132: 											}
133: 										}		
134: 	|		CLEAR BIGPL_T SYMT BIGPR_T	{	// 변수 삭제.
135: 											if(-1 == Symbol_Delete($3, 1))
136: 												printf("Error!! There is no variable named %s.\n", $3);
137: 											else
138: 												printf("delete %s variable\n", $3);
139: 										}
140: 	|		CLEAR BIGPL_T BIGPR_T		{	// 모든 변수 삭제.
141: 											Symbol_Delete_All(1);
142: 											printf("delete all variable\n");
143: 										}
144: 	|		SYMT FUNC_T					{	// 함수 생성.
145: 											user_func_define($1, $2);
146: 										}
147: 	|		CLEARF BIGPL_T SYMT BIGPR_T	{	// 함수 삭제
148: 											if(-1 == Symbol_Delete($3, 2))
149: 												printf("Error!! There is no function named %s.\n", $3);
150: 											else
151: 												printf("delete %s function\n", $3);
152: 										}
153: 	|		CLEARF BIGPL_T BIGPR_T		{	// 모든 함수 삭제
154: 											Symbol_Delete_All(2);
155: 											printf("delete all functions\n");
156: 										}
157: 	;
158: 
159: Expression:	Expression OP1 Expression	{ $$ = $1 + $3; }		// 덧셈
160: 	|		Expression OP2 Expression	{ $$ = $1 - $3; }		// 뺄셈
161: 	|		Expression OP3 Expression	{ $$ = $1 * $3; }		// 곱셈
162: 	|		Expression OP4 Expression	{ 						// 나눗셈
163: 											if(0.0 == $3)
164: 											{
165: 												printf("Error!! divide by zero\n");
166: 												Error_Flag = 1;
167: 											}
168: 											else
169: 												$$ = $1 / $3;
170: 										}
171: 	|		Expression OP5 Expression	{ $$ = pow($1, $3); }	// 승
172: 	|		Expression OP6 Expression	{ $$ = exp(log($3) / $1); }	// 제곱근, http://www.daniweb.com/forums/thread12733.html
173: 	|		OP2 Expression %prec UMINUS	{ $$ = -$2; }			// 음수
174: 	|		SMALLPL_T Expression SMALLPR_T	{ $$ = $2; }		// 괄호
175: 	|		NUMBER						{ $$ = $1; }			// 숫자
176: 	|		SYMT						{ 						// memory 변수 접근
177: 											SymbolTable* symt = Symbol_Search($1, 1);	// symboltable에 있는지 검색
178: 											
179: 											if(NULL != symt)
180: 											{
181: 												// 있다면 값을 반환
182: 												$$ = symt->num_value;
183: 											}
184: 											else if(NULL != (symt = Symbol_Search($1, 3)))
185: 											{
186: 												// 있다면 값을 반환
187: 												$$ = symt->num_value;
188: 											}
189: 											else
190: 											{
191: 												// 없다면 에러 메시지를 띄움.
192: 												printf("Error!! There is no variable named %s.\n", $1);
193: 												Error_Flag = 1;
194: 												$$ = 0;	// default로 0을 반환. 출력은 하지 않음.
195: 											}
196: 										}	
197: 	|		BuiltFunc FUNC_ARG_T 		{	// 미리 정의된 함수 사용.
198: 											double parsed_argu;
199: 											char temp_exp[MAX_CHAR];
200: 											strncpy(temp_exp, &$2[1], (strlen($2)-2));	// 괄호 제거
201: 											parse(temp_exp, &parsed_argu);				// 괄호 안의 것 parsing
202: 											$$ = ($1)(parsed_argu);
203: 										}
204: 	|		SYMT FUNC_ARG_T { $$ = user_func_evaluate($1, $2); }			// 사용자가 정의한 함수 사용
205: 	;
206: 
207: BuiltFunc:	SIN	{ $$ = my_sin; }
208: 	|		COS	{ $$ = my_cos; }
209: 	|		TAN	{ $$ = my_tan; }
210: 	|		LOG	{ $$ = log10; }
211: 	|		LN	{ $$ = log; }
212: 	|		EXP	{ $$ = exp; }
213: 
214: Exp_func :	Exp_func OP1 Exp_func		{}
215: 	|		Exp_func OP2 Exp_func		{}
216: 	|		Exp_func OP3 Exp_func		{}
217: 	|		Exp_func OP4 Exp_func		{}
218: 	|		Exp_func OP5 Exp_func		{}
219: 	|		Exp_func OP6 Exp_func		{}
220: 	|		OP2 Exp_func %prec UMINUS	{}
221: 	|		SMALLPL_T Exp_func SMALLPR_T{}
222: 	|		NUMBER						{}
223: 	|		SYMT						{	// 함수 정의 시 body 안에 심볼로 파라메터만 있는지 확인
224: 											SymbolTable* temp = Symbol_Search($1, 4);
225: 											if(NULL == temp)
226: 											{
227: 												printf("There is no %s named parameter.\n", $1);
228: 												Symbol_Delete_All(1);
229: 												Symbol_Delete_All(2);
230: 												Symbol_Delete_All(3);
231: 												Symbol_Delete_All(4);
232: 												exit(1);
233: 											}
234: 										}
235: 	|		BuiltFunc FUNC_ARG_T		{}
236: %%
237: 
238: // degree 계산을 위해 만든 함수
239: double my_sin(double x)
240: {
241: 	return sin(x*PI/180);
242: }
243: 
244: // degree 계산을 위해 만든 함수
245: double my_cos(double x)
246: {
247: 	return cos(x*PI/180);
248: }
249: 
250: // degree 계산을 위해 만든 함수
251: double my_tan(double x)
252: {
253: 	return tan(x*PI/180);
254: }
255: 
256: // 유저가 만든 함수를 사용할 때 호출. 너무 길어서 따로 떼어냄.
257: double user_func_evaluate(char* func_name, char* func_arg)
258: {
259: 	char temp_str[MAX_CHAR] = { 0 };
260: 	double temp_func_arg[MAX_ARG_NUM] = { 0 };
261: 	char* pch1;
262: 	char* pch2;
263: 	SymbolTable* temp_symt;							// 변수 추가시 필요
264: 	SymbolTable* symt = Symbol_Search(func_name, 2);// 이름으로 symboltable에서 함수 검색.
265: 	double result;								// 함수 실행 후 결과
266: 	int i, j;
267: 	
268: 	if(NULL != symt)
269: 	{
270: 		// 함수가 있다면...
271: 		// 들어온 func_arg를 parsing
272: 		// func_arg를 배열에 저장
273: 		i = 0;
274: 		pch1 = strtok(&func_arg[1], ",");
275: 		
276: 		while(NULL != pch1)
277: 		{
278: 			if(NULL == (pch2 = strchr(pch1, ')')))
279: 			{
280: 				// 마지막 값이 아니라면
281: 				parse(pch1, &temp_func_arg[i]);
282: 				i++;
283: 				pch1 = strtok(NULL, ",");
284: 			}
285: 			else
286: 			{
287: 				// 마지막이라면...
288: 				pch2[0] = '\0';
289: 				parse(pch1, &temp_func_arg[i]);
290: 				pch2[0] = ')';
291: 				break;
292: 			}
293: 		}
294: 		
295: 		// 함수의 parameter를 symboltable에 등록 type : 3
296: 		i = 0;
297: 		strcpy(temp_str, symt->str_func_value);
298: 		pch1 = strtok(&temp_str[1], ",");
299: 		while(NULL != pch1)
300: 		{
301: 			temp_symt = malloc(sizeof(SymbolTable));
302: 			if(NULL == temp_symt)
303: 			{
304: 				printf("malloc error!\n");
305: 				exit(1);
306: 			}
307: 			
308: 			if(NULL == (pch2 = strchr(pch1, ')')))
309: 			{
310: 				// 마지막 값이 아니라면
311: 				temp_symt->name = strndup(pch1, strlen(pch1));
312: 			}
313: 			else
314: 			{
315: 				// 마지막이라면...
316: 				pch2[0] = '\0';
317: 				temp_symt->name = strndup(pch1, strlen(pch1));
318: 				pch2[0] = ')';
319: 			}
320: 			temp_symt->num_value = temp_func_arg[i];
321: 			temp_symt->type = 3;	// 함수 파라메터는 3
322: 			temp_symt->left_symbol = NULL;
323: 			temp_symt->right_symbol = NULL;
324: 			Symbol_Insert(temp_symt);
325: 			
326: 			i++;
327: 			pch1 = strtok(NULL, ",");
328: 		}
329: 		
330: 		// 함수 본문 parsing
331: 		strcpy(temp_str, symt->str_func_value);
332: 		pch1 = strchr(temp_str, '=');	// 함수 body 찾기
333: 		parse(&pch1[1], &result);
334: 		
335: 		// symboltable에 함수 parameter 삭제
336: 		Symbol_Delete_All(3);
337: 		
338: 		// 반환
339: 		return result;
340: 	}
341: 	else
342: 	{
343: 		// 함수가 없다면 에러 메시지를 띄우고 반환
344: 		printf("Error!! There is no function named %s.\n", func_name);
345: 		Error_Flag = 1;
346: 		return 0;
347: 	}
348: }
349: 
350: 
351: void user_func_define(char* func_name, char* func_all)
352: {
353: 	SymbolTable* temp;
354: 	char temp_str[MAX_CHAR] = { 0 };
355: 	char* pch1;
356: 	char* pch2;
357: 	double result;
358: 	int i;
359: 	SymbolTable* temp_symt;	
360: 	
361: 	// 함수 정의 여부 체크
362: 	// 함수의 parameter를 symboltable에 등록 type : 4
363: 	i = 0;
364: 	strcpy(temp_str, func_all);
365: 	pch1 = strtok(&temp_str[1], ",");
366: 	while(NULL != pch1)
367: 	{
368: 		temp_symt = malloc(sizeof(SymbolTable));
369: 		if(NULL == temp_symt)
370: 		{
371: 			printf("malloc error!\n");
372: 			exit(1);
373: 		}
374: 		
375: 		if(NULL == (pch2 = strchr(pch1, ')')))
376: 		{
377: 			// 마지막 값이 아니라면
378: 			temp_symt->name = strndup(pch1, strlen(pch1));
379: 		}
380: 		else
381: 		{
382: 			// 마지막이라면...
383: 			pch2[0] = '\0';
384: 			temp_symt->name = strndup(pch1, strlen(pch1));
385: 			pch2[0] = ')';
386: 		}
387: 		temp_symt->type = 4;	// define시 함수 파라메터는 4
388: 		temp_symt->left_symbol = NULL;
389: 		temp_symt->right_symbol = NULL;
390: 		Symbol_Insert(temp_symt);
391: 		
392: 		i++;
393: 		pch1 = strtok(NULL, ",");
394: 	}
395: 		
396: 	// 함수 본문 parsing
397: 	strcpy(temp_str, func_all);
398: 	pch1 = strchr(temp_str, '=');	// 함수 body 찾기
399: 	parse(pch1, &result);
400: 	
401: 	// symboltable에 함수 parameter 삭제
402: 	Symbol_Delete_All(4);
403: 	
404: 	// 제대로 함수 등록
405: 	// 함수가 이미 있는지 확인.
406: 	if(NULL == (temp = Symbol_Search(func_name, 2)))
407: 	{
408: 		temp = malloc(sizeof(SymbolTable));
409: 		if(NULL == temp)
410: 		{
411: 			printf("malloc error!\n");
412: 			exit(1);
413: 		}
414: 		temp->name = func_name;
415: 		temp->str_func_value = strndup(func_all, strlen(func_all));
416: 		temp->type = 2;	// 함수는 2
417: 		temp->left_symbol = NULL;
418: 		temp->right_symbol = NULL;
419: 		Symbol_Insert(temp);
420: 		printf("make function %s%s\n", func_name, func_all);
421: 	}
422: 	// 함수가 이미 있다면...
423: 	else
424: 	{
425: 		free(temp->str_func_value);
426: 		temp->str_func_value = strndup(func_all, strlen(func_all));
427: 		printf("Ans : %s%s\n", func_name, func_all);
428: 	}
429: }

makefile

  1: OBJS = engcalc.tab.o lex.yy.o main.o
  2: 
  3: all: ${OBJS}
  4: 	gcc -o engcalc $? -lm -lfl -ly
  5: 
  6: engcalc.tab.c: engcalc.y
  7: 	bison -d $?
  8: 
  9: lex.yy.c: engcalc.l
 10: 	flex $?
 11: 
 12: clean:
 13: 	rm -f engcalc engcalc.exe engcalc.tab.{c,h} lex.yy.c ${OBJS}
 14: 
 15: .SUFFIXES: .c .o
 16: 
 17: .c.o:
 18: 	gcc -c $< -o $*.o

recursive_parsing.h

  1. /*
  2. ** recursive_parsing.h
  3. */
  4.  
  5. #ifndef    __RECURSIVE_PARSING_H__
  6. #define __RECURSIVE_PARSING_H__
  7.  
  8. typedef struct        parse_parm_s
  9. {
  10.     void            *yyscanner; /* state of the lexer */
  11.    
  12.     char            *buf;         /* buffer we read from */
  13.     int                pos;         /* current position in buf */
  14.     int                length;        /* length of buf */
  15.  
  16.     double            result;
  17. }                     parse_parm;
  18.  
  19. typedef union
  20. {
  21.     double TT_NUMBER;
  22.     char* TT_SYMT;
  23.    
  24.     /* Non Terminal Type */
  25.     int TT_Statement;
  26.     double TT_Expression;
  27.     double TT_Exp_func;
  28.     double (*TT_BuiltFunc)();
  29.    
  30. } parm_union;
  31. void    parse(char *buf, double *result);
  32.  
  33. #define YYSTYPE            parm_union
  34. #define YY_EXTRA_TYPE    parse_parm *
  35.  
  36. /*
  37. ** forward declaration of lexer/parser functions
  38. ** so the compiler shuts up about warnings
  39. */
  40. int        yylex(YYSTYPE *, void *);
  41. int        yylex_init(void **);
  42. int        yylex_destroy(void *);
  43. void    yyset_extra(YY_EXTRA_TYPE, void *);
  44. int        yyparse(parse_parm *, void *);
  45. void    yyerror();
  46.  
  47. #endif /* !__RECURSIVE_PARSING_H__ */

symboltable.h

  1. /*
  2.     symboltable.h
  3. */
  4.  
  5. #ifndef    __SYMBOLTABLE_H__
  6. #define __SYMBOLTABLE_H__
  7.  
  8. // SymboleTable Structure
  9. typedef struct SymbolTable
  10. {
  11.     char* name;
  12.     char* str_func_value;
  13.     double num_value;
  14.     int type;                            // º¯¼ö: 1, ÇÔ¼ö: 2
  15.     struct SymbolTable* left_symbol;
  16.     struct SymbolTable* right_symbol;
  17. } SymbolTable;
  18.  
  19. #define MAX_CHAR 100
  20. #define MAX_ARG_NUM 10
  21.  
  22. // ÇÔ¼ö¼±¾ð
  23. void Symbol_Insert(SymbolTable* symbol);
  24. SymbolTable* Symbol_Search(const char* name, const int type);
  25. int Symbol_Delete(const char* name, const int type);
  26. void Symbol_Delete_All(int type);
  27. void Symbol_Print_All(void);
  28.  
  29. #endif /* !__SYMBOLTABLE_H__ */

main.c

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4.  
  5. #include "recursive_parsing.h"
  6. #include "symboltable.h"
  7.  
  8. void parse(char *buf, double *result);
  9.  
  10. SymbolTable* SymTab;    // SymTab Linked List
  11.  
  12. // main ÇÔ¼ö
  13. int main(int argc, char* argv[])
  14. {
  15.     char strinput[MAX_CHAR];
  16.     double temp = 0;
  17.    
  18.     SymTab = NULL;
  19.    
  20.     printf("Engineering Calculator Start!\n");
  21.    
  22.     //yyparse();                            // do parsing
  23.     // »ç¿ëÀڷκÎÅÍÀÔ·ÂÀ»¹Þ½À´Ï´Ù.
  24.     while(1)
  25.     {
  26.         printf("> ");
  27.         fgets(strinput, 100, stdin);
  28.         parse(strinput, &temp);                // do parsing
  29.     }
  30.    
  31.     return 0;                                // return to the OS
  32. }
  33.  
  34.  
  35. // SymbolTable¿¡»ðÀÔÇÏ´ÂÇÔ¼ö
  36. void Symbol_Insert(SymbolTable* symbol)
  37. {
  38.     if(NULL != SymTab)
  39.     {
  40.         symbol->left_symbol = SymTab;
  41.         symbol->right_symbol = SymTab->right_symbol;
  42.         if(NULL != SymTab->right_symbol)
  43.         {
  44.             SymTab->right_symbol->left_symbol = symbol;
  45.         }
  46.         SymTab->right_symbol = symbol;
  47.     }
  48.     else
  49.     {
  50.         symbol->left_symbol = NULL;
  51.         symbol->right_symbol = NULL;
  52.         SymTab = symbol;
  53.     }
  54. }
  55.  
  56. // SymbolTable¿¡¼­°Ë»öÇÏ´ÂÇÔ¼ö
  57. SymbolTable* Symbol_Search(const char* name, const int type)
  58. {
  59.     SymbolTable* temp = SymTab;    // ã±âÀ§Çغ¯¼ö¼³Á¤.
  60.    
  61.     // ³¡±îÁö°Ë»ö
  62.     while(NULL != temp)
  63.     {
  64.         // ã´ÂÀ̸§ÀÌÁ¸ÀçÇÑ´Ù¸é
  65.         if(temp->name && !strcmp(temp->name, name) && (type == temp->type))
  66.         {
  67.             return temp;    // ÇØ´çsymbol ¹Ýȯ
  68.         }
  69.        
  70.         temp = temp->right_symbol;    // ã´ÂÀ̸§À̾ø±â¿¡´ÙÀ½°ÍÀ»¼³Á¤
  71.     }
  72.    
  73.     return NULL;
  74. }
  75.  
  76. // SymbolTable¿¡¼­»èÁ¦ÇÏ´ÂÇÔ¼ö
  77. int Symbol_Delete(const char* name, const int type)
  78. {
  79.     SymbolTable* target = Symbol_Search(name, type);
  80.    
  81.     // targetÀ̰¡ÀåóÀ½°ÍÀ̾ƴ϶ó¸é
  82.     if(target != SymTab)
  83.     {
  84.         target->left_symbol->right_symbol = target->right_symbol;    // left_symbolÀÌnullÀ̾ƴϹǷεû·Î°Ë»çÇÏÁö¾ÊÀ½.
  85.         // °¡À峡¿¡ÀÖ´ÂsymbolÀϰæ¿ì
  86.         if(NULL != target->right_symbol)
  87.             target->right_symbol->left_symbol = target->left_symbol;
  88.     }
  89.     // targetÀ»Ã£¾ÒÀ¸³ª°¡ÀåóÀ½°Í
  90.     else if(NULL != target)
  91.     {
  92.         SymTab = target->right_symbol;
  93.         if(SymTab != NULL)
  94.             SymTab->left_symbol = NULL;
  95.     }
  96.     // targetÀ»¸øÃ£Àº°æ¿ì
  97.     else
  98.     {
  99.         return -1;
  100.     }
  101.    
  102.     // Free
  103.     free(target->name);
  104.     // Áö¿ï´ë»óÀÌÇÔ¼ö¶ó¸évalue¸¦free
  105.     if(2 == target->type)
  106.         free(target->str_func_value);
  107.        
  108.     free(target);
  109.    
  110.     return 0;
  111. }
  112.  
  113. // SymbolTable¸¦typeº°·Îºñ¿ì´ÂÇÔ¼ö.
  114. void Symbol_Delete_All(int type)
  115. {
  116.     SymbolTable* target = SymTab;    // Çϳª¾¿»èÁ¦¸¦À§Çغ¯¼ö¼³Á¤.
  117.     SymbolTable* temp;
  118.    
  119.     // ³¡±îÁö°Ë»ö
  120.     while(NULL != target)
  121.     {
  122.         // typeÀ̸´°¡?
  123.         if(type == target->type)
  124.         {
  125.             // targetÀ̰¡ÀåóÀ½°ÍÀ̾ƴ϶ó¸é
  126.             if(target != SymTab)
  127.             {
  128.                 target->left_symbol->right_symbol = target->right_symbol;    // left_symbolÀÌnullÀ̾ƴϹǷεû·Î°Ë»çÇÏÁö¾ÊÀ½.
  129.                 // °¡À峡¿¡ÀÖ´ÂsymbolÀϰæ¿ì
  130.                 if(NULL != target->right_symbol)
  131.                     target->right_symbol->left_symbol = target->left_symbol;
  132.             }
  133.             // targetÀ»Ã£¾ÒÀ¸³ª°¡ÀåóÀ½°Í
  134.             else
  135.             {
  136.                 SymTab = target->right_symbol;
  137.                 if(SymTab != NULL)
  138.                     SymTab->left_symbol = NULL;
  139.             }
  140.            
  141.             temp = target->right_symbol;    // ÀÓ½ÃÀúÀå
  142.            
  143.             // Free
  144.             free(target->name);
  145.             // Áö¿ï´ë»óÀÌÇÔ¼ö¶ó¸évalue¸¦free
  146.             if(2 == type)
  147.                 free(target->str_func_value);
  148.                
  149.             free(target);
  150.            
  151.             target = temp;    // ´ÙÀ½°ÍÀ»¼³Á¤
  152.         }
  153.         // typeÀ̸ÂÁö¾Ê´Ù¸é´ÙÀ½°ÍÀ»º»´Ù.
  154.         else
  155.         {
  156.             target = target->right_symbol;    // ´ÙÀ½°ÍÀ»¼³Á¤
  157.         }
  158.     }
  159. }
  160.  
  161. // µð¹ö±×¸¦À§ÇØsymbol table Ãâ·ÂÇÏ´ÂÇÔ¼ö.
  162. void Symbol_Print_All(void)
  163. {
  164.     SymbolTable* target = SymTab;    // Çϳª¾¿»èÁ¦¸¦À§Çغ¯¼ö¼³Á¤.
  165.    
  166.     // ³¡±îÁö°Ë»ö
  167.     while(NULL != target)
  168.     {
  169.         printf("name : %s\ttype : %d\n", target->name, target->type);
  170.        
  171.         target = target->right_symbol;    // ´ÙÀ½°ÍÀ»¼³Á¤
  172.     }
  173. }
  174.  
  175. // Parsing function
  176. /*
  177. ** main parsing function
  178. */
  179. void parse(char *buf, double *result)
  180. {
  181.     parse_parm    pp;
  182.  
  183.     pp.buf = buf;
  184.     pp.length = strlen(buf);
  185.     pp.pos = 0;
  186.     *result = 0;
  187.     yylex_init(&pp.yyscanner);
  188.     yyset_extra(&pp, pp.yyscanner);
  189.     yyparse(&pp, pp.yyscanner);
  190.     *result = pp.result;
  191.     yylex_destroy(pp.yyscanner);
  192. }

크리에이티브 커먼즈 라이선스
Creative Commons License

글에 잘못된 점, 다른 점, 부족한 점이 있다면 지적해주세요.
댓글, 트랙백, 메일 모두 고맙습니다.

트랙백 주소 :: http://nosyu.pe.kr/trackback/2164

댓글을 달아 주세요

[로그인][오픈아이디란?]