letter = a|b|c|d|e..|A|B|C|D|E ..
digit = 0|1|2|3|4|5|6|7|8|9|
➡️ID = letter(letter | digit | _ )* // lexer의 "패턴"
a
= letter로 통과된다. lexer는 그 뒤 8, 9, 1, _부터 d까지 하나하나 체크하는데 모두 (letter or digit or __)이므로, ID(a891_jksdbed)가 만들어진다.
lexer가 one by one 체크하는데, 1이 letter에 해당하지 않으므로 lexer는 어떠한 토큰도 만들어내지 않고 "lexical error"을 만들어 낸다.
=> 이와 같이, lexer는 정규 표현식을 사용하여 토큰의 패턴을 명시하고, 토큰의 패턴이 맞는 경우 적절하게 토큰을 만들어주게 된다.
letter = a|b|c|d|e..|A|B|C|D|E ..
digit = 0|1|2|3|4|5|6|7|8|9|
➡️ID = letter(letter | digit | _ )* // lexer의 "패턴"
➡️NUM = digit*
=> NUM("125") 만들어진다!
=> digit* 이므로, NUM("")이 만들어진다. 따라서 NUM 토큰의 패턴을 바꿔야 한다.
➡️NUM = digit+ // one or more을 의미한다.
=> 0은 digit에 있고, 그 뒤 0도 각각 digit에 속하므로 NUM(00000)이 만들어진다. 따라서 NUM 토큰의 패턴을 바꿔야 한다.
letter = a|b|c|d|e..|A|B|C|D|E ..
digit = 0|1|2|3|4|5|6|7|8|9|
positive_digit = 1|2|3|4|5|6|7|8|9|
➡️ID = letter(letter | digit | _ )* // lexer의 "패턴"
➡️NUM = positive_digit(digit)*
현재 상태로는 1.5가 주어지면, lexical error가 발생할 것이다.
letter = a|b|c|d|e..|A|B|C|D|E ..
digit = 0|1|2|3|4|5|6|7|8|9|
positive_digit = 1|2|3|4|5|6|7|8|9|
➡️ID = letter(letter | digit | _ )* // lexer의 "패턴"
➡️NUM = positive_digit(digit)*
➡️DECIMAL = NUM . \. . NUM
(NUM과 dot과 NUM을 concatenate 한 패턴)
=> 1.5 => DECIMAL(1.5) 토큰이 생성된다.
=> 현재 NUM은 positive digit으로 시작하기 때문에 생성되지 않고 'lexical error' 발생
letter = a|b|c|d|e..|A|B|C|D|E ..
digit = 0|1|2|3|4|5|6|7|8|9|
positive_digit = 1|2|3|4|5|6|7|8|9|
➡️ID = letter(letter | digit | _ )* // lexer의 "패턴"
➡️NUM = positive_digit(digit)*
➡️DECIMAL = NUM . \. . digit*
=> 1.05 => DECIMAL(1.05) 생성된다.
=> 1. => DECIMAL(1.)이 생성된다. 따라서 패턴을 바꿔야 한다.
letter = a|b|c|d|e..|A|B|C|D|E ..
digit = 0|1|2|3|4|5|6|7|8|9|
positive_digit = 1|2|3|4|5|6|7|8|9|
➡️ID = letter(letter | digit | _ )* // lexer의 "패턴"
➡️NUM = positive_digit(digit)*
➡️DECIMAL = NUM . \. . digit . digit*
=> 1.은 lexical error가 발생함 !
=> 0은 positive_digit이 아니기 때문에 lexcial error 발생. 업뎃 필요
=> 이런 식으로 패턴을 업뎃 해가면서 원하는 대로 만들면 된다 !
만약 잘못 되면, Lexical Error나 Syntax Error가 발생한다. Lexical Error는 주어진 문자열이 토큰의 패턴에 맞지 않으면 발생한다.
letter = a|b|c|d|e..|A|B|C|D|E ..
digit = 0|1|2|3|4|5|6|7|8|9|
positive_digit = 1|2|3|4|5|6|7|8|9|
ID = letter.(letter|digit|_)*
=> ID(abc)
=> ID(a), ID(b), ID(c)
두 가지 모두 가능하지 않을까? lexer는 어떤 토큰을 만들까?!
digit = 0|1|2|3|4|5|6|7|8|9|
positive_digit = 1|2|3|4|5|6|7|8|9|
DIGIT = digit+
PDIGIT = pdigit+
=> DIGIT(12)
=> PDIGIT(12)
두가지 모두 가능하지 않을까? lexer는 어떤 토큰을 만들까?
(1) Starting from the next input symbol, find the longest string that matches a token.
(2) Break ties by giving preference to token listed first in the list
-> 규칙(1)에 의해 ID(abc)와 ID(a), ID(b), ID(c) 중 ID(abc)가 가장 길기 때문에, ID(abc)가 생성된다.
-> 규칙(2) DIGIT(12), PDIGIT(12)의 경우에는 토큰 리스트 중 가장 먼저 Matching된 토큰을 생성한다. DIGIT 토큰이 먼저 정의되어 있기 때문에 DIGIT 토큰이 생성된다.
letter = a|b|c|d|e..|A|B|C|D|E ..
digit = 0|1|2|3|4|5|6|7|8|9|
positive_digit = 1|2|3|4|5|6|7|8|9|ID = letter.(letter|digit|_)*
DOT = \.
NUM = digit.(digit)* | 0
DECIMAL = NUM.DOT.digit.digit
1.1 = DECIMAL("1.1")
abc1 = ID("abc1")
. = DOT(".")
2 = NUM("2")
Do 15 |= 1,100
// loop statement (i = 1부터 100까지 DO 15)
Do 15 |= 1.1000
// assign statement (DO15| = 1.100 대입)
=> Whitespace는 fortran에서 무시되기 때문에 .을 , 로 잘못 쓰면 위와 같이 완전히 의미가 달라질 수 있다.
python에서는 int(10)는 10이고, int(010)은 8이다. int(0x10)은 16이다.
python 에서는 10 = decimal number system, 010 = octal number system, 0x10 = hexadecimal number system이기 때문이다.
KW_LET : let
INDENT : [a-z] [0-9a-zA-Z'_]*
OP_EQ : =
INT : [1-9][0-9]*
KW_IN : in
KW_WILDCARD : _
LPAREN : \(
RPAREN : \)
let xyz = 3 in
let _ = foo xyz in
()
KW_LET (INDENT "xyz") OP_EQ (INT 3) KW_IN
KW_LET KW_WILDCARD OP_EQ (INDENT "foo") (INDENT "xyz") KW_IN
LPAREN RPAREN