News
home
๐Ÿ–ฅ๏ธ

The context sensitivity of C and Rust's grammar

Context-free grammar

Context-free grammar(CFG)๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์˜ ์ฝ”๋“œ๋ฅผ parsing ํ•˜๋Š” ๋ฐ์— ์œ ์šฉํ•œ ์ด๋ก ์  ๋„๊ตฌ๋กœ ์“ฐ์ž…๋‹ˆ๋‹ค. ์ผ๋ก€๋กœ, parsing ๋„๊ตฌ ์ค‘ ํ•˜๋‚˜์ธ Yacc๋Š” CFG์šฉ parser๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์‹ค์ œ๋กœ๋Š” ๋‹ค์ˆ˜์˜ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๊ฐ€ context-free ํ•˜์ง€ ์•Š์€ ๋ฌธ๋ฒ•์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค.

C

C๋Š” ๋„๋ฆฌ ์‚ฌ์šฉ๋˜๋Š” ์–ธ์–ด ์ค‘ ํ•˜๋‚˜์ด๋ฉฐ ๊ฑฐ์˜ context-free ํ•œ ๋ฌธ๋ฒ•์„ ๊ฐ€์ ธ ์œ„ ๋‚ด์šฉ์„ ์„ค๋ช…ํ•˜๊ธฐ ์ข‹์€ ์˜ˆ์ž…๋‹ˆ๋‹ค.
CFG๋Š” ํ˜•์‹ ์–ธ์–ด ๋ฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์™€ ๊ด€๋ จํ•˜์—ฌ ๋‹ค์–‘ํ•œ ๋ฐฉ์‹์œผ๋กœ ์ •์˜๋ฉ๋‹ˆ๋‹ค. ๋ณธ ๊ธ€์—์„œ๋Š” ๋ช…๋ช…๋ฒ•์— ๋Œ€ํ•ด ๊นŠ์ด ํŒŒ๊ณ ๋“ค์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค-์ด์— ๊ด€ํ•œ ๋‚ด์šฉ์ด ๊ถ๊ธˆํ•˜๋‹ค๋ฉด ๊ด€๋ จ ํ† ๋ก ์„ ์ฐธ๊ณ ํ•˜์„ธ์š”. ๋ณธ ๊ธ€์—์„œ C์˜ ๋ฌธ๋ฒ•์ด CFG๊ฐ€ ์•„๋‹ˆ๋ผ๊ณ  ํ•˜๋Š” ๊ฒƒ์€, Yacc์— ์ฃผ์–ด์ง„ ๋ฌธ๋ฒ•์ด ๋‹ค๋ฅธ ๊ณณ์—์„œ ์˜ค๋Š” ๋ช‡๋ช‡ context information์„ ์ฐธ์กฐํ•˜์ง€ ์•Š๊ณ ๋Š” C๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ parsing ํ•˜๊ธฐ์— ์ถฉ๋ถ„ํ•˜์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ๋ช‡ ๊ฐ€์ง€ ์˜ˆ๋ฅผ ๋“ค์–ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
{ ย T (x); ... }
Plain Text
๋ณต์‚ฌ
์ƒ์†Œํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ, T๊ฐ€ type์ด๋ฉด ์ƒ๊ธฐ C ์ฝ”๋“œ๋Š” type T์˜ x์— ๋Œ€ํ•œ ์œ ํšจํ•œ ์„ ์–ธ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ T๊ฐ€ ์•Œ๋ ค์ง„ type์ด ์•„๋‹ˆ๋ฉด argument x๋ฅผ ๊ฐ€์ง„ function T์— ๋Œ€ํ•œ ํ˜ธ์ถœ์ด ๋ฉ๋‹ˆ๋‹ค. C parser๋Š” T๊ฐ€ ์ด์ „์— typedef์— ์˜ํ•ด ์ •์˜๋˜์—ˆ๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ์•Œ์ง€ ๋ชปํ•œ ์ฑ„ ์–ด๋–ป๊ฒŒ parsing ํ•  ๋ฐฉ๋ฒ•์„ ์•Œ ์ˆ˜ ์žˆ์„๊นŒ์š”?
ํ˜น์ž๋Š” "ํ•˜์ง€๋งŒ ๋ˆ„๊ฐ€ ์ด๋Ÿฐ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋‚˜์š”?"๋ผ๊ณ  ํ•  ์ˆ˜๋„ ์žˆ์„ ๊ฒ๋‹ˆ๋‹ค. ์ข‹์•„์š”, ๊ทธ๋ ‡๋‹ค๋ฉด ์ข€ ๋” ํ‘œ์ค€์ ์ธ ์ฝ”๋“œ๋ฅผ ๋ณด์ฃ :
{ ย T * x; ... }
Plain Text
๋ณต์‚ฌ
์ด๊ฒƒ์€ T์— ๋Œ€ํ•œ pointer๋กœ x๋ฅผ ์„ ์–ธํ•œ ๊ฒƒ์ผ๊นŒ์š”, ์•„๋‹ˆ๋ฉด variable T์™€ x์˜ ๊ณฑ์…ˆ์ผ๊นŒ์š”? ๋ฉ”๋ชจ๋ฆฌ์— typedef๋กœ ์ •์˜๋œ type์— ๋Œ€ํ•œ table์ด ์—†์œผ๋ฉด ์•Œ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค-์ด๋Š” context-sensitive information์ž…๋‹ˆ๋‹ค.
๋‹ค๋ฅธ ์˜ˆ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค:
func((T) * x);
Plain Text
๋ณต์‚ฌ
T๊ฐ€ type์ด๋ฉด x๋ฅผ ์—ญ์ฐธ์กฐํ•œ ๊ฒฐ๊ณผ๊ฐ€ T๋กœ ํ˜•๋ณ€ํ™˜๋˜์–ด func์— ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค. T๊ฐ€ type์ด ์•„๋‹ˆ๋ฉด T์™€ x์˜ ๊ณฑ์…ˆ์ด func์— ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค.
์œ„ ๋ชจ๋“  ์˜ˆ์—์„œ, ๋ฌธ์ œ๋ฅผ ์œ ๋ฐœํ•  ์ˆ˜ ์žˆ๋Š” ๋ถ€๋ถ„์— ๋„๋‹ฌํ•˜๊ธฐ ์ „์— ์ฝ”๋“œ์—์„œ context-sensitive information์„ ์ˆ˜์ง‘ํ•˜์ง€ ์•Š์œผ๋ฉด parser๋Š” ์ •์ƒ์ ์œผ๋กœ ์ž‘๋™ํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๋Š” compilation/C ์ปค๋ฎค๋‹ˆํ‹ฐ์—์„œ "typedef-name: identifier" ๋ฌธ์ œ๋กœ ๋ถˆ๋ฆฝ๋‹ˆ๋‹ค. K&R2๋„ ๋ถ€๋ก์—์„œ C์˜ ๋ฌธ๋ฒ•์„ ์ œ์‹œํ•  ๋•Œ ์ด๋ฅผ ์–ธ๊ธ‰ํ•ฉ๋‹ˆ๋‹ค:
With one further change, namely deleting the production typedef-name: identifier and making typedef-name a terminal symbol, this grammar is acceptable to the YACC parser-generator.
๋‹คํ–‰ํžˆ๋„ ์ด ๋ฌธ์ œ๋Š” ๊ฐ„๋‹จํžˆ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Parsing์ด ์ง„ํ–‰๋˜๋Š” ๋™์•ˆ typedef๋กœ ์ •์˜๋œ type์˜ symbol table์„ ์œ ์ง€ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. Lexer์—์„œ ์ƒˆ identifier๊ฐ€ ์ธ์‹๋  ๋•Œ๋งˆ๋‹ค ์ด identifier๊ฐ€ ์ •์˜๋œ type์ธ์ง€ ํ™•์ธํ•˜๊ณ  ์˜ฌ๋ฐ”๋ฅธ token์„ parser์— ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. Parser๋Š” identifier์™€ ์ •์˜๋œ type์ด๋ผ๋Š” ๋‘ ๊ฐ€์ง€ terminal์„ ๊ฐ€์ง€๋ฉฐ, ์ด์ œ ๋‚จ์€ ๊ฒƒ์€ typedef ๋ฌธ์˜ parsing์ด ์™„๋ฃŒ๋  ๋•Œ๋งˆ๋‹ค symbol table์„ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ๋” ์ž˜ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด c2c์˜ ์ฝ”๋“œ์—์„œ C parser์™€ lexer ๊ด€๋ จ ๋ถ€๋ถ„์„ ์‚ดํŽด๋ด…์‹œ๋‹ค. ๋‹ค์Œ์€ Lex ํŒŒ์ผ์˜ ์ผ๋ถ€์ž…๋‹ˆ๋‹ค:
identifier ([a-zA-Z_][0-9a-zA-Z_]*) <INITIAL,C>{identifier} { ย  GetCoord(&yylval.tok); ย  yylval.n = MakeIdCoord(UniqueString(yytext), ย  ย  ย  ย  ย  ย  ย  ย  ย  ย  ย  ย  ย  yylval.tok); ย  if (IsAType(yylval.n->u.id.text)) ย  ย  RETURN_TOKEN(TYPEDEFname); ย  else ย  ย  RETURN_TOKEN(IDENTIFIER); }
Plain Text
๋ณต์‚ฌ
์—ฌ๊ธฐ์„œ Lex์˜ syntax๋ฅผ ์ž์„ธํžˆ ์„ค๋ช…ํ•˜์ง€ ์•Š๋”๋ผ๋„, ์ด๊ฒƒ์ด ๊ธฐ๋ณธ์ ์œผ๋กœ ๋งํ•˜๋Š” ๊ฒƒ์€ identifier๊ฐ€ ๋ฐœ๊ฒฌ๋  ๋•Œ๋งˆ๋‹ค ํ•ด๋‹น identifier๊ฐ€ type์ธ์ง€ ํ™•์ธํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. Type์ด๋ฉด TYPEDEFname token์ด ๋ฐ˜ํ™˜๋˜๊ณ , type์ด ์•„๋‹ˆ๋ฉด IDENTIFIER๊ฐ€ ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค. Yacc ๋ฌธ๋ฒ•์—์„œ ์ด ๋‘˜์€ ๋ณ„๋„์˜ terminal์ž…๋‹ˆ๋‹ค.

Rust

Rust์˜ lexical ๋ฌธ๋ฒ•์€ context-free ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. Raw string literal์ด ๊ทธ ์›์ธ์ž…๋‹ˆ๋‹ค. Raw string literal์€ r์— ์ด์€ N๊ฐœ์˜ hash(N์€ 0์ผ ์ˆ˜ ์žˆ์Œ), ๋”ฐ์˜ดํ‘œ, ์ž„์˜์˜ ๋ฌธ์ž๋“ค, ๋”ฐ์˜ดํ‘œ ๊ทธ๋ฆฌ๊ณ  N๊ฐœ์˜ hash๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค. ์ค‘์š”ํ•œ ๊ฒƒ์€ ์ฒซ ๋ฒˆ์งธ ๋”ฐ์˜ดํ‘œ ์Œ ์•ˆ์— ๋‹ค๋ฅธ ๋”ฐ์˜ดํ‘œ๊ฐ€ ๋“ค์–ด์˜ค๋ฉด ๊ทธ ๋’ค์— N๊ฐœ์˜ hash๊ฐ€ ์—ฐ์†์ ์œผ๋กœ ์˜ฌ ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ฐ€๋ น, r###""###"###์€ ์œ ํšจํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
์•„๋ž˜ ๋ฌธ๋ฒ•์„ ๋ด…์‹œ๋‹ค:
R -> 'r' S S -> '"' B '"' S -> '#' S '#' B -> . B B -> ฮต
Plain Text
๋ณต์‚ฌ
์—ฌ๊ธฐ์„œ .๋Š” ์ž„์˜์˜ ๋ฌธ์ž๋ฅผ ๋‚˜ํƒ€๋‚ด๊ณ  ฮต๋Š” ๋นˆ ๋ฌธ์ž์—ด์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ๋ฌธ์ž์—ด r#""#"#์„ ์ƒ๊ฐํ•ด ๋ณด๋ฉด, ์ด ๋ฌธ์ž์—ด์€ ์œ ํšจํ•œ raw string literal์€ ์•„๋‹ˆ์ง€๋งŒ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์œ ๋„ ๊ณผ์ •์„ ํ†ตํ•ด ์ƒ๊ธฐ ๋ฌธ๋ฒ•์—์„œ๋Š” ํ—ˆ์šฉ๋ฉ๋‹ˆ๋‹ค:
R : #""#"# S : ""#" S : "# B : # B : ฮต
Plain Text
๋ณต์‚ฌ
(์—ฌ๊ธฐ์„œ T : U๋Š” ๊ทœ์น™ T๊ฐ€ ์ ์šฉ๋จ์„ ์˜๋ฏธํ•˜๊ณ  U๋Š” ๋ฌธ์ž์—ด์˜ ๋‚˜๋จธ์ง€ ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค.) ๊ทผ๋ณธ์ ์œผ๋กœ raw string literal์ด context-sensitive ํ•˜๋ฏ€๋กœ CFG๋กœ ํ‘œํ˜„ ์‹œ์— ์–ด๋ ค์›€์ด ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์ด๋ฉฐ, ํŠนํžˆ ํ•„์š”ํ•œ context๋Š” hash์˜ ์ˆ˜ ์ž…๋‹ˆ๋‹ค.
Rust์˜ string literal์ด context-free ํ•˜์ง€ ์•Š์Œ์„ ์ฆ๋ช…ํ•˜๊ธฐ ์œ„ํ•ด context-free language๊ฐ€ regular language์™€์˜ ๊ต์ง‘ํ•ฉ์— ๋Œ€ํ•ด ๋‹ซํ˜€ ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค๊ณผ context-free language์— ๋Œ€ํ•œ pumping lemma๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.
Regular language R = r#+""#*"#+๋ฅผ ์ƒ๊ฐํ•ด ๋ด…์‹œ๋‹ค. Rust์˜ raw string literal์ด context-free ํ•˜๋ฉด, raw string literal๊ณผ R์˜ ๊ต์ง‘ํ•ฉ์ธ R' ์—ญ์‹œ context-free ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ raw string literal์ด context-free ํ•˜์ง€ ์•Š์Œ์„ ์ฆ๋ช…ํ•˜๋ ค๋ฉด R'์ด context-free ํ•˜์ง€ ์•Š์Œ์„ ์ฆ๋ช…ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.
R'์€ {r#^n""#^m"#^n | m < n}์ž…๋‹ˆ๋‹ค.
R'์ด context-free ํ•˜๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ์‹œ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด R'์€ pumping lemma๊ฐ€ ์ ์šฉ๋˜๋Š” pumping length p > 0๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค. R'์—์„œ ๋‹ค์Œ ๋ฌธ์ž์—ด s๋ฅผ ์ƒ๊ฐํ•ด ๋ด…์‹œ๋‹ค:
r#^p""#^{p-1}"#^p
e.g. for p = 2: s = r##""#"##
์•„๋ž˜ ์กฐ๊ฑด์„ ๋งŒ์กฑ์‹œํ‚ค๋„๋ก s = uvwxy์™€ ๊ฐ™์ด ๋ถ„ํ• ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
โ€ข
|vx| โ‰ฅ 1
โ€ข
|vwx| โ‰ค p
โ€ข
uv^iwx^iy โˆˆ R' for all i โ‰ฅ 0
โ€ข
R'์˜ ๋ชจ๋“  ๋ฌธ์ž์—ด์—์„œ "์™€ r์˜ ์ˆ˜๋Š” ๊ณ ์ •๋ผ ์žˆ์œผ๋ฏ€๋กœ v์™€ x ๋ชจ๋‘ " ๋˜๋Š” r์„ ํฌํ•จํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ v์™€ x๋Š” hash๋งŒ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ์ ์œผ๋กœ, ์„ธ ๊ฐœ์˜ hash sequence ์ค‘ v์™€ x๋ฅผ ํ•ฉ์นœ ๊ฒƒ์€ ๊ทธ์ค‘ ๋‘ ๊ฐœ๋งŒ pumping ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์ค‘์•™ hash sequence๋ฅผ ์„ ํƒํ•˜๋ฉด pumping ์‹œ ์™ธ๋ถ€ sequence ์ค‘ ํ•˜๋‚˜๊ฐ€ ์ฆ๊ฐ€ํ•˜์ง€ ์•Š์•„ ์™ธ๋ถ€ sequence ๊ฐ„์˜ ๋ถˆ๊ท ํ˜•์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋‘ ์™ธ๋ถ€ hash sequence๋ฅผ ๋ชจ๋‘ pumping ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด ๋‘ hash sequence ์‚ฌ์ด์—๋Š” p + 2๊ฐœ์˜ ๋ฌธ์ž๊ฐ€ ์กด์žฌํ•˜๋ฉฐ, |vwx|๋Š” p๋ณด๋‹ค ์ž‘๊ฑฐ๋‚˜ ๊ฐ™์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ๋ชจ์ˆœ์ด ๋ฐœ์ƒํ•˜์—ฌ R'์ด context-free ํ•˜์ง€ ์•Š์Œ์ด ๋„์ถœ๋ฉ๋‹ˆ๋‹ค.
R'๊ฐ€ context-free ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ Rust์˜ raw string literal ๋˜ํ•œ context-free ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

References