ANSI C Grammar and Lex Specification
- ANSI에 의해 표준화되어 있는 C언어의 문법을 Lex로 표기한 것이다.
ANSI C Grammar (Lex)
- 모든 경우의 문자 입력에 대한 Lexical Analyzer의 처리 방식을 기술한 것이다.
Notation 처리부
D [0-9] ⇔ 0부터 9까지의 문자(숫자)중 하나를 D로 Reduce한다.(D를 지칭한다.)
L [a-zA-Z_] ⇔ 영문 대소문자와 언더바가 붙은 형태를 L로 Reduce한다.
H [a-fA-F0-9] ⇔ 16진수를 H로 Reduce한다.
E [Ee][+-]?{D}+ ⇔ Scientific Notation를 숫자의 일부로 간주한다. (?는 or의 의미이다.)
FS (f|F|l|L) ⇔ Floating-Point Number를 의미하는 기호들이 FS로 Reduce된다.
IS (u|U|l|L)* ⇔ Unsigned 수를 의미하는 기호들이 IS로 Reduce된다.
%{
#include <stdio.h>
#include "y.tab.h"
void count();
%}
%%
"/*" { comment(); }
Predefined Identifier 처리부
- 아래 키워드들에 해당하는 Lexical Token들이 미리 정의되어 있어, 그 기정의된 어휘 토큰을 리턴하라 명령하는 문장들이다.
"auto" { count(); return(AUTO); } ⇔ "auto"라는 키워드가 입력되면, Lexical Analyzer는 AUTO라는 Lexical Token을 리턴한다. (이 Lexical Token은 어딘가에 숫자로 저장되어 있거나, 프로그래머가 만들 수 있다.)
"break" { count(); return(BREAK); }
"case" { count(); return(CASE); }
"char" { count(); return(CHAR); }
"const" { count(); return(CONST); }
"continue" { count(); return(CONTINUE); }
"default" { count(); return(DEFAULT); }
"do" { count(); return(DO); }
"double" { count(); return(DOUBLE); }
"else" { count(); return(ELSE); }
"enum" { count(); return(ENUM); }
"extern" { count(); return(EXTERN); }
"float" { count(); return(FLOAT); }
"for" { count(); return(FOR); }
"goto" { count(); return(GOTO); }
"if" { count(); return(IF); }
"int" { count(); return(INT); }
"long" { count(); return(LONG); }
"register" { count(); return(REGISTER); }
"return" { count(); return(RETURN); }
"short" { count(); return(SHORT); }
"signed" { count(); return(SIGNED); }
"sizeof" { count(); return(SIZEOF); }
"static" { count(); return(STATIC); }
"struct" { count(); return(STRUCT); }
"switch" { count(); return(SWITCH); }
"typedef" { count(); return(TYPEDEF); }
"union" { count(); return(UNION); }
"unsigned" { count(); return(UNSIGNED); }
"void" { count(); return(VOID); }
"volatile" { count(); return(VOLATILE); }
"while" { count(); return(WHILE); }
사용자 정의 Identifier 처리부
{L}({L}|{D})* { count(); return(check_type()); } ⇔ 영문자 한 글자 뒤에 영문자 혹은 숫자가 0개 이상 붙는 형태는 check_type()을 리턴한다. 즉, Lexical Analyzer가 이러한 형태의 Identifier를 발견하면 User-Defined Type 여부를 분석하게 된다.
Constant 처리부
0[xX]{H}+{IS}? { count(); return(CONSTANT); } ⇔ 0x(X) 16진수와 IS(상수 접미어)가 붙으면 CONSTANT를 리턴(상수로 간주)한다.
0{D}+{IS}? { count(); return(CONSTANT); } ⇔ 8진수 상수
{D}+{IS}? { count(); return(CONSTANT); } ⇔ 10진수 상수
L?'(\\.|[^\\'])+' { count(); return(CONSTANT); } ⇔ Literal 상수
{D}+{E}{FS}? { count(); return(CONSTANT); } ⇔ 과학적 표기 상수
{D}*"."{D}+({E})?{FS}? { count(); return(CONSTANT); } ⇔ 과학적 표기 상수 (소수점 앞에 숫자가 없어도 과학적 표기로 인정)
{D}+"."{D}*({E})?{FS}? { count(); return(CONSTANT); } ⇔ 과학적 표기 상수
String 처리부
L?\"(\\.|[^\\"])*\" { count(); return(STRING_LITERAL); } ⇔ 큰 따옴표로 둘러싼 내용을 String으로 간주
두 글자 이상 키워드 처리부
"..." { count(); return(ELLIPSIS); } (Ellipsis 기호 처리)
">>=" { count(); return(RIGHT_ASSIGN); }
"<<=" { count(); return(LEFT_ASSIGN); }
"+=" { count(); return(ADD_ASSIGN); }
"-=" { count(); return(SUB_ASSIGN); }
"*=" { count(); return(MUL_ASSIGN); }
"/=" { count(); return(DIV_ASSIGN); }
"%=" { count(); return(MOD_ASSIGN); }
"&=" { count(); return(AND_ASSIGN); }
"^=" { count(); return(XOR_ASSIGN); }
"|=" { count(); return(OR_ASSIGN); }
">>" { count(); return(RIGHT_OP); }
"<<" { count(); return(LEFT_OP); }
"++" { count(); return(INC_OP); }
"--" { count(); return(DEC_OP); }
"->" { count(); return(PTR_OP); }
"&&" { count(); return(AND_OP); }
"||" { count(); return(OR_OP); }
"<=" { count(); return(LE_OP); }
">=" { count(); return(GE_OP); }
"==" { count(); return(EQ_OP); }
"!=" { count(); return(NE_OP); }
한 글자 키워드 처리부
- 한 글자이니, 토큰을 생성할 필요 없이 바로 전달하면 된다.
";" { count(); return(';'); }
("{"|"<%") { count(); return('{'); }
("}"|"%>") { count(); return('}'); }
"," { count(); return(','); }
":" { count(); return(':'); }
"=" { count(); return('='); }
"(" { count(); return('('); }
")" { count(); return(')'); }
("["|"<:") { count(); return('['); }
("]"|":>") { count(); return(']'); }
"." { count(); return('.'); }
"&" { count(); return('&'); }
"!" { count(); return('!'); }
"~" { count(); return('~'); }
"-" { count(); return('-'); }
"+" { count(); return('+'); }
"*" { count(); return('*'); }
"/" { count(); return('/'); }
"%" { count(); return('%'); }
"<" { count(); return('<'); }
">" { count(); return('>'); }
"^" { count(); return('^'); }
"|" { count(); return('|'); }
"?" { count(); return('?'); }
[ \t\v\n\f] { count(); }
. { /* ignore bad characters */ }
%%
yywrap()
{
return(1);
}
comment()
{
char c, c1;
loop:
while ((c = input()) != '*' && c != 0)
putchar(c);
if ((c1 = input()) != '/' && c != 0)
{
unput(c1);
goto loop;
}
if (c != 0)
putchar(c1);
}
int column = 0;
void count()
{
int i;
for (i = 0; yytext[i] != '\0'; i++)
if (yytext[i] == '\n')
column = 0;
else if (yytext[i] == '\t')
column += 8 - (column % 8);
else
column++;
ECHO;
}
int check_type()
{
/*
* pseudo code --- this is what it should check
*
* if (yytext == type_name)
* return(TYPE_NAME);
*
* return(IDENTIFIER);
*/
/*
* it actually will only return IDENTIFIER
*/
return(IDENTIFIER);
}