TinyCIn Lex Yacc
| 
  TinyC language parser 
 
±Û¾´ÀÌ : ÀÌ Çüä <hclee80 atat gmail dotdot com>
 
ÃÖÃÊ ¼öÁ¤ÀÏ : 2008³â 06¿ù 19ÀÏ ( È帲 )
 
ÃÖÁ¾ ¼öÁ¤ÀÏ : 2008³â 06¿ù 20ÀÏ ( ¸¼À½ )
 
1. TinyC ? ¶tinyC ( ŸÀÌ´Ï ¾¾(0) ) - compiler construction, principles and practice -> kenneth C, rouden ( ÄÄÆÄÀÏ·¯ Á¦ÀÛ, ¿ø¸®¿Í ½ÇÁ¦ -> ±èÀçÈÆ|µµ°æ±¸|¿ì±Õ|Á¤´ö±æ|Á¤¹Î¼ö)
 
Ã¥¿¡¼ ÄÄÆÄÀÏ·¯ÀÇ ½ºÄ³³Ê & ÆÄ¼ ( front-end ) ¼³¸íÀ» À§Çؼ ¾²¿©Áø °£´ÜÇÑ ¾ð¾îÀÔ´Ï´Ù. ¿µ¾î¸¦ ±×´ë·Î ÇØ¼®Çصµ ÁÁÀ» µí ½Í½À´Ï´Ù. º°´Ù¸¥ ¼³¸íÀÌ ÇÊ¿ä¾øÀ» Á¤µµ·Î ÀûÀº ¿¹¾à¾î¿Í ¹®¹ýÀÔ´Ï´Ù. lex¿Í yaccÀÇ »ç¿ë¹ýÀ» ÀÍÈ÷±â À§ÇÑ ¾ð¾î¶ó°í »ý°¢ÇÏ½Ã¸é µË´Ï´Ù. ¹°·Ð Tiny C Compiler µµ Á¸ÀçÇÕ´Ï´Ù.
 
Tiny C -> C-Minus -> C-- -> ANSI C ¼ø¼´ë·Î È®ÀåµÇ´Â °³³äÀ̶ó°í »ý°¢ÇÏ½Ã¸é µË´Ï´Ù. ¹°·Ð ANSI CºÎÅʹ ǥÁØÀ̰í, ±× ÀÌÇϴ ǥÁØÀÌ ¾ø½À´Ï´Ù. ÀÌ ¸»Àº °ð Á¤ÀÇ ¹× ±¸ÇöÇÏ´Â ¹æ¹ý¿¡ µû¶ó¼ ´Þ¶óÁú¼ö ÀÖ½À´Ï´Ù. ¿¹¾à¾îÁß ÇϳªÀÎ int ¸¦ integer ¶ó°í Á¤ÀÇÇÒ¼öµµ ÀÖÀ»Å×°í, INTEGER ¶ó°í Á¤ÀÇÇÒ ¼öµµ ÀÖ´Â °ÍÀÔ´Ï´Ù.
 
lex & yacc À» ¼³¸íÇϴ å, ¹®¼, »çÀÌÆ® µî¿¡¼ ½±°Ô º¼¼ö ÀÖ´Â ¿¹Á¦°¡ expr ( expression ) ¿¹Á¦ÀÏ °Ì´Ï´Ù.ÀÌ ³»¿ëÀº °á±¹ ¿ì¼±¼øÀ§°¡ ÀÖ´Â calc °è»ê±â ¸¸µé±â¿Í µ¿ÀÏÇÕ´Ï´Ù. ¶ÇÇÑ, "shift/reduce Ãæµ¹" ¹®Á¦¿¡ ´ëÇÑ ³»¿ë¿¡¼µµ ¾ð±ÞµÇ´Â ºÎºÐÀÔ´Ï´Ù. ±×·¯³ª, ÀÌ ¿¹Á¦¸¸À¸·Î lex & yaccÀÇ »ç¿ë¹ýÀº ÀÍÈú¼ö ÀÖÀ¸³ª, Á¤È®ÇÑ ÀÌÇØ´Â ¸Å¿ì Èûµç °Í°°½À´Ï´Ù.
 
±×·¡¼, Tiny C °¡ lex & yacc ÀÌ¿ëÇÑ ÇÁ·Î±×·¡¹Ö¾ð¾î ÆÄ¼¸¦ ¸¸µå´Âµ¥ °¡Àå ÁÁÀº ¿¹Á¦ÀÎ°Í °°½À´Ï´Ù. ¹°·Ð lex & yacc°¡ ²À ÇÁ·Î±×·¡¹Ö¾ð¾î¸¸À» À§ÇÑ °ÍÀº ¾Æ´Õ´Ï´Ù. ÀÀ¿ë¹æ¹ýÀº ¹«±Ã¹«ÁøÇÕ´Ï´Ù. ÀÌ¿¡ ´ëÇØ¼´Â ÃßÈÄ¿¡ ´Ù¸¥ ±ÛÀ» Âü°íÇÏ½Ã¸é µË´Ï´Ù.
 
À¯¸íÇÑ awk, Perl °°Àº ¹®Àڿ󸮰¡ ÆíÇÑ Åø ¹× ¾ð¾îµéó·³ c, c++ ¿¡¼µµ À¯¿¬ÇÏ°Ô °³¹ßÇϽǼö ÀÖ½À´Ï´Ù. awk ´Â °á±¹ lex & yacc ÀÇ ºÒÆíÇÔ(?)¶§¹®¿¡ ³ª¿Â °ÍÀ̰í, PerlÀº awkÀÇ ºÎÁ·ÇÔÀ» ä¿ì±â À§Çؼ ¸¸µé¾îÁ³´Ù. awk ÁÖ¸ñÀû °³¹ß¸ñÀûÀº ºü¸¥ Å×½ºÆÃ(¹®Àڿó¸®)°ú °£ÆíÇÔÀ» À§ÇÔÀ̾ú´Ù.
 
2. TinyC lexical ¶
 2.1. TinyC.l ¶
%{
%{
#include "list.h"
#define YYSTYPE		ListPtr
#include "y.tab.h"
extern YYSTYPE yylval;
%}
%%
"=="				return EQ;
"<"				return '<';
">"				return '>';
"="				return '=';
"+"				return '+';
"-"				return '-';
"*"				return '*';
"/"				return '/';
","				return ',';
";"				return ';';
"("				return '(';
")"				return ')';
"{"				return '{';
"}"				return '}';
"["				return '[';
"]"				return ']';
"int"				return INT;
"return"			return RETURN;
"if"				return IF;
"else"				return ELSE;
[0-9]+				{ List* lst = NullList();
				  yylval = AddInteger(lst, atoi(yytext));
				  return Number;
				}
[A-Za-z][A-Za-z0-9]*		{ List* lst = NullList();
				  yylval = AddSymbol(lst, MakeSymbol(yytext));
				  return Identifier;
				}
[ \t\n]				;
.				return BADTOKEN;
%%
3.1. TinyC.y ¶
/*
   tinyc.y	-- a parser of Tiny C
*/
%{
#include <stdio.h>
#include "list.h"
#define YYSTYPE		ListPtr
static List* MakeBinaryExpr(char* op, List* exp1, List* exp2);
static List* MakeTriple(char* op, List* e1, List* e2, List* e3);
%}
/* yacc produces yyparse() from the following grammar. */
%token Identifier
%token Number
%token '=' '+' '-' '*' '/' ',' ';' '(' ')' '{' '}' '[' ']' '<' '>'
%token INT
%token RETURN
%token IF
%token ELSE
%token EQ		/* == */
%token BADTOKEN
%%
program
    : function
      {}
    | program function
      {}
    | error '}'		/* error recovery: ignore tokens until '}' */
      {}		/*		   is encountered.	   */
function
    : typename Identifier '(' formal.arguments ')' function.body
      {
	  List* lst;
	  lst = ConcatLists($1, $2);
	  lst = AddList(lst, $4);
	  lst = ConcatLists(lst, $6);
	  PrintList(lst);
	  $$ = lst;
      }
typename
    : INT
      { $$ = AddSymbol(NullList(), "int"); }
    | INT '*'
      { $$ = AddSymbol(NullList(), "int*"); }
formal.arguments
    : /* empty */
      { $$ = NULL; }
    | formal.argument.list
      { $$ = $1; }
formal.argument.list
    : formal.argument
      { $$ = MakeList($1); }
    | formal.argument.list ',' formal.argument
      { $$ = AddList($1, $3); }
formal.argument
    : typename Identifier
      { $$ = MakeTriple("*var*", $2, $1, NULL); }
function.body
    : '{' '}'				/* empty body */
      { $$ = NULL; }
    | '{' statements '}'
      { $$ = $2; }
statements
    : statement
      { $$ = MakeList($1); }
    | statements statement
      { $$ = AddList($1, $2); }
statement
    : declaration
      { $$ = $1; }
    | RETURN expression ';'		/* return statement */
      { $$ = MakeBinaryExpr("return", $2, NULL); }
    | if.statement
    | term '=' expression ';'		/* assignment */
      { $$ = MakeBinaryExpr("=", $1, $3); }
    | expression ';'
      { $$ = MakeBinaryExpr(";", $1, NULL); }
    | '{' statements '}'
      { $$ = MakeBinaryExpr("{}", $2, NULL); }
    | ';'				/* null statement */
      { $$ = NULL; }
declaration
    : typename Identifier ';'
      { $$ = MakeTriple("*var*", $2, $1, NULL); }
    | typename Identifier '[' Number ']' ';'	/* array */
      { $$ = MakeTriple("*var*", $2, $1, $4); }
if.statement
    : IF '(' expression ')' statement
	/* ??? */
    | IF '(' expression ')' statement ELSE statement
	/* ??? */
expression
    : additive.expression
      { $$ = $1; }
    | expression EQ additive.expression
	/* ??? */
    | expression '>' additive.expression
	/* ??? */
    | expression '<' additive.expression
	/* ??? */
additive.expression
    : term
      { $$ = $1; }
    | additive.expression '+' term
      { $$ = MakeList(MakeBinaryExpr("+", $1, $3)); }
    | additive.expression '-' term
	/* ??? */
term
    : Identifier
      { $$ = $1; }
    | Number
	/* ??? */
    | Identifier '(' opt.actual.arguments ')'	/* function call */
      { $$ = MakeList(ConcatLists($1, $3)); }
    | Identifier '[' expression ']'		/* array access */
      { $$ = MakeList(MakeBinaryExpr("[]", $1, $3)); }
    | '(' expression ')'
      { $$ = $2; }
opt.actual.arguments
    : /* empty */
      { $$ = NullList(); }
    | actual.arguments
      { $$ = $1; }
actual.arguments
    : expression
      { $$ = $1; }
    | actual.arguments ',' expression
      { $$ = ConcatLists($1, $3); }
%%
static List* MakeBinaryExpr(char* op, List* exp1, List* exp2)
{
    List* lst = NullList();
    lst = AddSymbol(lst, op);
    lst = ConcatLists(lst, exp1);
    return ConcatLists(lst, exp2);
}
static List* MakeTriple(char* op, List* e1, List* e2, List* e3)
{
    List* lst = NullList();
    lst = AddSymbol(lst, op);
    lst = ConcatLists(lst, e1);
    lst = ConcatLists(lst, e2);
    return ConcatLists(lst, e3);
}
yyerror(msg)
    char* msg;
{
#if !defined(YYBISON)
    extern int yynerrs;
    ++yynerrs;
#endif
    fprintf(stderr, "Error: %s\n", msg);
}
main()
{
    extern int yynerrs;
#ifdef YYDEBUG
    yydebug = !0;
#endif
    yyparse();
    fprintf(stderr, "%d errors.\n", yynerrs);
}
4. Makefile ¶#YACC = bison -dvy YACC = yacc -dv #LIB = -lfl # Linux LIB = -ll CC = gcc -g OBJ = y.tab.o lex.yy.o list.o codegen.o build : $(OBJ) gcc -g -o tinyc $(OBJ) $(LIB) debug : y.tab.c lex.yy.c gcc -DYYDEBUG -o tinyc y.tab.c lex.yy.c $(LIB) list.o : list.c list.h gcc -g -c list.c y.tab.c : tinyc.y $(YACC) tinyc.y lex.yy.c : tinyc.l lex tinyc.l clean : rm -f y.output y.tab.c y.tab.h lex.yy.c a.out tinyc *.s *.o *~  | 











![[http]](/imgs/http.png)