당신은 주제를 찾고 있습니까 “문맥 자유 문법 – Compiler Lecture 04: Grammar (in Korean)“? 다음 카테고리의 웹사이트 you.charoenmotorcycles.com 에서 귀하의 모든 질문에 답변해 드립니다: https://you.charoenmotorcycles.com/blog. 바로 아래에서 답을 찾을 수 있습니다. 작성자 C Studio 이(가) 작성한 기사에는 조회수 442회 및 좋아요 6개 개의 좋아요가 있습니다.
문맥 자유 문법 주제에 대한 동영상 보기
여기에서 이 주제에 대한 비디오를 시청하십시오. 주의 깊게 살펴보고 읽고 있는 내용에 대한 피드백을 제공하세요!
d여기에서 Compiler Lecture 04: Grammar (in Korean) – 문맥 자유 문법 주제에 대한 세부정보를 참조하세요
언어의 구문을 정의하기 위한 BNF, EBFN, CFG(context-free grammar, 문맥무관문법)에 대해 살펴봅니다.
문맥 자유 문법 주제에 대한 자세한 내용은 여기를 참조하세요.
문맥-자유 언어 – AI Study
1. 문맥-자유 문법. 정규 문법에서는 생성규칙이 두 가지 면에서 제약되어 있다. 생성규칙의 좌변은 반드시 하나의 변수이어야 하는데 반하여, 우변 …
Source: www.aistudy.co.kr
Date Published: 2/9/2022
View: 9932
문맥자유언어 (Context Free Grammar) – 코딩스낵
2. 문맥자유 문법 (Context-Free Grammar : CFG) · 단말기호를 제외한 문법기호들의 집합을 의미하며 유한개의 원소를 가짐 · 언어안에서 다른 문자열을 …
Source: gusdnd852.tistory.com
Date Published: 8/7/2021
View: 1445
오토마타 이론 공부 (10) – 문맥 자유 언어 : 네이버 블로그
문맥 자유 문법(Context-free grammar, CFG), 문맥 무관 문법은 형식 문법의 한 종류로, . … 즉, 문맥 자유 문법을 이루는 요소는 4가지가 있다.
Source: blog.naver.com
Date Published: 5/26/2021
View: 9430
문맥 자유 문법 (Context Free Grammar, CFG)
문맥 자유 문법에서 생성규칙의 가장 큰 특징은 생성규칙의 좌변에는 항상 1개의 nonterminal만 올 수 있다는 것이다. 하나의 nonterminal만 고려하여 …
Source: seraup.dev
Date Published: 8/26/2021
View: 8981
문맥자유문법,context-free_grammar,CFG – VeryGoodWiki
하텍 02주 1강 p8: 정의. CFG G는 네 구성요소 V, T, S, P로 이루어진 수학적 구조이며. V : nonterminal이라 부르는 symbol들의 유한 집합
Source: tomoyo.ivyro.net
Date Published: 5/6/2021
View: 4709
[Automata Theory] Context-Free Languages | 문맥-자유 언어
Context-Free Languages 문맥-자유 언어 * Parsing (파싱) – 문장을 문법적 유도를 … Definition 5.1 CFG (Context-Free Grammar; 문맥-자유 문법)
Source: dad-rock.tistory.com
Date Published: 3/8/2022
View: 2822
[Automata] Context-free Language ( 문맥 자유 언어 ) – sweetdev
linear grammar? 문제들은 주로, 주어진 언어가 문맥자유언어인지 보이라는 유형이 많다. 언어에 맞는 문법을 유도해서, 문법이 문맥자유문법에 해당 …
Source: sweetdev.tistory.com
Date Published: 11/25/2022
View: 3665
컴파일러 12강 – 문맥자유 문법 – 국민대학교 OCW
컴파일러 12강 – 문맥자유 문법. 조회수 442. |. 게시일 : 2020-01-15. 공유. 공유. 0. 0. 서석문. 좌단유도와 우단유도, 모호한 문법, 문법의 동등성, 문법의 변환, …
Source: ocw.kookmin.ac.kr
Date Published: 5/5/2022
View: 4223
주제와 관련된 이미지 문맥 자유 문법
주제와 관련된 더 많은 사진을 참조하십시오 Compiler Lecture 04: Grammar (in Korean). 댓글에서 더 많은 관련 이미지를 보거나 필요한 경우 더 많은 관련 기사를 볼 수 있습니다.
주제에 대한 기사 평가 문맥 자유 문법
- Author: C Studio
- Views: 조회수 442회
- Likes: 좋아요 6개
- Date Published: 2019. 9. 28.
- Video Url link: https://www.youtube.com/watch?v=wZCzlc4uYsk
문맥-자유 언어
문맥-자유 언어
형식 언어와 오토마타 : Peter Linz 저서, 장직현. 김응모. 엄영익. 한광록 공역, 사이텍미디어 , 2001 (원서 : An Introduction to Formal Languages and Automata. 3rd ed, Jones and Bartlett. 2001), Page 133~158
1. 문맥-자유 문법
(1) 문맥-자유 문법의 예
(2) 좌측우선 유도와 우측우선 유도
(3) 유도 트리
(4) 문장 형태와 유도 트리와의 관계
연습문제
2. 파싱과 모호성
(1) 파싱과 소속성
(2) 문법과 언어에서의 모호성
연습문제
3. 문맥-자유 문법과 프로그래밍 언어
연습문제
앞장에서 우리는 모든 언어들이 정규 언어가 될 수 없음을 알아보았다. 이는 정규 언어가 단순한 패턴들을 표현하는데 효과적인데 반하여, 정규 언어가 아닌 언어들의 예들을 쉽게 찾을 수 있다. 몇몇 예제들을 다시 해석해 보면, 이러한 제한성 (limitation) 의 프로그래밍 언어들과의 연관성은 분명해진다. 만일 언어 에서 a 를 왼쪽 괄호, b 를 오른쪽 괄호로 치환하면, (( )) 나 ((( ))) 와 같은 괄호 문자열들은 L 에 속하는 반면 (( ) 문자열은 속하지 않는다. 이 언어는 프로그래밍 언어에서 접할 수 있는 일종의 중첩 구조 (nested structure) 를 나타내는 것으로서, 프로그램의 몇몇 성질들은 정규 언어 이상의 어떤 것을 필요로 함을 시사한다. 따라서 중첩 구조와 그 외의 다른 좀더 복잡한 특성들을 표현하려면, 언어군을 확대하여야 한다. 이를 위하여 문맥-자유 언어 (context-free language) 와 문법을 살펴보기로 하자.
우선 문맥-자유 문법과 언어를 정의한다. 이 정의들을 몇 개의 간단한 예를 가지고 설명해 본다. 그리고, 중요한 소속성 문제를 고려해 본다. 특히, 임의의 문자열이 주어진 문법에 의하여 유도될 수 있는지를 묻는 문제를 고려해 본다. 문장을 문법적인 유도를 통하여 설명하는 것은 자연 언어를 공부한 우리들에게 익숙하고, 이 과정을 파싱 (parsing) 이라 부른다. 파싱은 문장의 구조를 표현하는 한 방법이다. 예를 들어, 한 언어를 다른 언어로 번역하는 데에서와 같이 문장의 의미를 이해하는 것을 필요로 할 때에 항상 파싱은 중요한 역할을 한다. 컴퓨터 과학에서는, 번역기 (interpreter), 컴파일러 (compiler), 그리고 또 다른 프로그램 번역 등이 이와 연관된다.
문맥-자유 언어는 프로그래밍 언어에 적용이 되기 때문에, 이에 관한 연구는 아마도 형식 언어 이론의 가장 중요한 부분일 것이다. 실제의 프로그래밍 언어는 문맥-자유 언어로 잘 표현될 수 있는 여러 특성들을 가지고 있다. 형식 언어 이론에서 밝혀진 문맥-자유 언어에 대한 결과들은 프로그래밍 언어의 설계에서 뿐만 아니라 효율적인 컴파일러 작성에 중요하게 사용된다. 이에 대하여 3 절에서 간단하게 다루어 본다.
정규 문법에서는 생성규칙이 두 가지 면에서 제약되어 있다. 생성규칙의 좌변은 반드시 하나의 변수이어야 하는데 반하여, 우변은 반드시 특별한 형태이어야 한다. 따라서 좀더 강력한 문법을 만들기 위해서는 이러한 제약 중 일부를 완화하여야 한다. 생성규칙의 좌변의 제약은 그대로 두고, 우변에는 어떤 문자열이든 허용함으로써, 문맥-자유 문법을 정의할 수 있다.
위의 정의에 의하면 모든 정규 문법은 문맥-자유 문법이 되며, 따라서 정규 언어는 문맥-자유 언어임을 알 수 있다. 그러나, L = {anbn : n ≥ 0} 와 같은 예로부터 알고 있듯이, 정규 언어가 아닌 언어가 존재한다. 따라서 정규 언어군은 문맥-자유 언어군의 진부분 집합임을 알 수 있다.
문맥-자유 문법이란 이름은 문장 형태에 있는 임의의 변수는 그 변수를 좌변으로 갖는 생성규칙에 의하여 치환될 수 있다는 사실로부터 유래된다. 이러한 치환은 문장 형태(문장)에 있는 나머지 심볼들과는 상관없이 이루어진다. 이런 특징은 생성규칙의 좌변에 변수 하나만이 허용되기 때문에 얻어지는 결과이다.
위의 두 예제에서 논의된 문법들은 모두 문맥-자유 문법일 뿐만 아니라, 선형 문법이다. 정규 문법과 선형 문법은 당연히 문맥-자유 문법이지만, 문맥-자유 문법은 반드시 선형 문법인 것은 아니다.
선형 문법이 아닌 문맥-자유 문법에 대한 유도에서, 두 개 이상의 변수를 포함하고 있는 문장 형태가 나타날 수 있다. 이러한 경우에, 여러 변수들을 어느 순서로 대체할 것인가 하는 선택이 우리에게 주어진다. 예를 들어, 다음의 생성규칙을 갖는 문법 G = ({A, B, S}, {a, b}, S, P) 를 고려해 보자.
문법 G 가 생성하는 언어가 인 것을 쉽게 확인할 수 있다.
여기서 문자열 aab 가 유도되는 과정을 다음과 같은 두 가지 방식으로 살펴보기로 하자.
어떤 생성규칙들이 적용되었는지를 보이기 위하여, 생성규칙들에 번호를 매겨서 심볼 ⇒ 위에 적절한 번호를 적어 놓았다. 이로부터 위의 두 유도가 문장을 유도할 뿐 아니라 정확히 같은 생성규칙들을 사용한다는 것을 알 수 있다. 차이점은 단지 생성규칙들이 적용된 순서이다. 이러한 관계없는 요소를 제거하기 위하여, 변수들이 특정 순서로 대체되도록 하는 것이 필요하다.
유도 과정을 보이는 또 다른 방법으로 유도 트리 (derivation tree) 가 있다. 이 표현 방법은 사용된 생성규칙들의 순서와는 무관하다. 유도 트리는 순서 트리 (ordered tree) 로서 부모 노드는 생성규칙의 좌변에 있는 변수 (혹은 비단말) 로 라벨이 주어지고, 이 노드의 자식 노드들은 대응되는 우변에 있는 심볼들을 표현한다. 예를 들면, 그림 1 은 다음의 생성규칙에 대한 유도 트리의 한 부분을 보여주고 있다.
즉, 유도 트리에서는, 생성규칙의 좌변에 있는 변수를 라벨로 갖는 노드는 이 규칙의 우변에 있는 심볼들을 자식 노드들로 갖게 된다. 유도 트리는 유도 과정에서 각 변수들이 어떻게 대체되는가를 보여준다. 이 개념을 자세하게 정의하면 다음과 같다.
그림 1
그림 2
그림 3
유도 트리는 유도를 명확하고 쉽게 이해되는 표현하는 방법이다. 앞에서 소개한 유한 오토마타의 전이 그래프와 같이, 이 명확성은 논증을 하는 데 있어 큰 도움이 된다. 우선, 유도와 유도 트리와의 관계를 알아보기로 하자.
유도 트리는 문장을 얻기 위해 어떠한 규칙들이 사용되었는가는 보여주지만, 그들이 어떤 순서로 적용되었는가는 보여주지 못한다. 즉 유도 트리는 어떠한 유도든지 나타낼 수 있으며, 생성규칙이 적용되는 순서는 관계가 없음을 반영한다. 여기서 유도 과정과 유도 트리와의 관계를 살펴보면 다음과 같다. 정의에 의하여, 모든 문자열 w ∈ L(G) 에 대하여 유도가 존재하지만, 우리는 좌측우선 혹은 우측우선 유도가 존재한다고 하지는 않았다. 하지만, 유도 트리가 존재할 경우, 트리에서 항상 가장 왼쪽 변수를 확장하는 방식으로 이 트리가 완성되는 것으로 생각하면, 우리는 항상 좌측우선 유도를 얻을 수 있다. 약간의 세부 사항을 채우면, 모든 w ∈ L(G) 에 대하여, 좌측우선 유도와 우측우선 유도가 존재한다는 당연한 결과를 얻게 된다 (자세한 사항은 이 절의 연습문제 24 를 참조하라).
1. 예제 2 에서 보여진 언어가 주어진 문법에 의해 생성됨을 보여라.
2. 예제 1 의 유도에 대응하는 유도 트리를 그려라.
3. 예제 2 에서 주어진 문법에 대하여, w = abbbaabbaba 에 대한 유도 트리를 보여라. 유도 트리를 이용하여 좌측우선 유도를 구하라.
4. 예제 4 의 문법이 식 (1) 에 의해 정의되는 언어를 생성한다는 것을 보여라.
5. 예제 2 의 언어가 정규 언어인가?
6. 로트 노드 S 를 갖는 모든 부분 유도 트리의 생성물이 문법 G 의 문장 형태임을 보여 정리 1 에 대한 증명을 완성하라.
7. 다음의 각 언어에 대한 문맥-자유 문법을 만들어라. 단, 여기서 n ≥ 0, m ≥ 0 이다.
(a)
(b)
(c)
(d)
(e)
(f)
(g)
8. 다음의 각 언어에 대한 문맥-자유 문법을 만들어라. 단, 여기서 n ≥ 0, m ≥ 0, k ≥ 0 이다.
(a)
(b)
(c)
(d)
(e)
(f)
(g)
(h)
9. 위의 연습문제 7(a) 의 언어를 L 이라 하자. head(L) 에 대한 문맥-자유 문법을 만들어라. head(L) 에 대한 정의는 4.1 절의 연습문제 18 을 참조하라.
10. 언어 에 대한 문맥-자유 문법을 만들어라.
11. L 에 대하여 주어진 문법 G 로부터 을 만족하는 문법 를 어떻게 구성하는지를 보여라.
12. 이라 하자.
(a) 이 문맥-자유 언어임을 보여라.
(b) 가 문맥-자유 언어임을 보여라 (단, k ≥ 1).
(c) 와 이 모두 문맥-자유 언어임을 보여라.
13. 연습문제 8(a) 의 언어를 , 그리고 연습문제 8(d) 의 언어를 라 하자. 가 문맥-자유 언어임을 보여라.
14. 다음의 언어가 문맥-자유 언어임을 보여라.
15. 예제 1 의 언어의 여집합이 문맥-자유 언어임을 보여라.
16. 연습문제 8(b) 의 언어의 여집합이 문맥-자유 언어임을 보여라.
17. 언어 이 문맥-자유 언어임을 보여라. 여기서 Σ = {a, b, c} 이다.
18. 다음의 생성규칙을 갖는 문법에 대해 문자열 aabbbb 의 유도 트리를 그려라.
또한 이 문법에 의해 생성되는 언어를 말로 설명하라.
19. 다음의 생성규칙을 갖는 문법을 고려해 보자.
문자열 aabbabba 가 이 문법에 의해 유도되지 않음을 보여라.
20. 아래에 주어진 유도 트리를 고려해 보자.
이 트리가 문자열 aab 의 유도 트리가 되도록 하는 간단한 문법 G 를 찾아보아라. L(G) 에 속한 다른 문장 두 개를 찾아라.
21. 두 가지의 괄호, ( ) 와 [ ] 로 이루어진 올바르게 중첩된 괄호 구조에 대하여 정의하라. 직관적으로, 이 경우에서 ([ ]), ([[ ]]), [( )] 등은 올바르게 중첩된 괄호이나, ([) 나 ((]] 는 아니다. 제시한 정의를 사용하여, 모든 올바르게 중첩된 괄호를 생성하는 문맥-자유 문법을 제시하라.
22. 알파벳 {a, b} 에 대한 모든 정규 표현들이 집합에 대한 문맥-자유 문법을 만들어라.
23. 단말들의 집합 T = {a, b} 와 변수들의 집합 V = {A, B, C} 에 대한 문맥-자유 언어들에 대한 모든 생성규칙들을 생성할 수 있는 문맥-자유 문법을 만들어라.
24. 만일 G 가 문맥-자유 문법이라면, 모든 w ∈ L(G) 에 대한 좌측우선 유도와 우측우선 유도가 존재함을 증명하라. 유도 트리로부터 좌측우선 (우측우선) 유도를 구하는 알고리즘을 만들어라.
25. 예제 3 의 언어에 대한 선형 문법을 만들어라.
26. G = (V, T, S, P) 가 모든 생성규칙이 A → v 형태인 (단, |v| = k > 1) 문맥-자유 언어라 하자. 임의의 문자열 w ∈ L(G) 의 유도 트리의 높이 h 가 다음의 부등식을 만족함을 보여라.
지금까지 주로 문법의 생성적인 측면을 살펴보았다. 즉 문법 G 가 주어졌을 때 G 로부터 유도될 수 있는 문자열들의 집합, 즉 G 가 생성하는 언어가 무엇인가에 대해 살펴보았다. 실제 응용에 있어서는, 주어진 단말들의 문자열 w 가 L(G) 에 속하는지의 여부를 알고자 하는 문법의 분석적인 측면 또한 중요하다. 만약 w 가 L(G) 에 속하는 경우, 우리는 w 에 대한 유도를 찾을 필요가 있을 것이다. w 가 L(G) 에 속하는지 혹은 아닌지를 판별하는 알고리즘을 소속성 알고리즘이라 한다. 파싱 (parsing) 의 의미는 L(G) 에 속하는 w 가 유도되는 데 사용된 일련의 생성규칙들을 찾는 것이라 할 수 있다.
L(G) 에 속하는 주어진 문자열 w 에 대한 단순한 파싱 방법 가운데 하나는 체계적으로 가능한 모든 (예를 들어, 좌측우선) 유도들을 구성해 가면서 그 중에 w 와 일치하는 것이 있는지를 알아보는 것이다. 구체적으로, 첫 번째 라운드에서 우선 다음과 같은 형태의 시작 심볼을 좌변으로 갖는 모든 생성규칙들을 살펴보아서,
시작 심볼 S 로부터 한 단계에 유도될 수 있는 모든 문장 형태 x 를 찾는다. 만약 어느 x 도 w 와 일치하지 않으면, 다음 라운드에서, 각 x 의 가장 왼쪽 변수에 적용될 수 있는 모든 생성규칙들을 적용한다. 새로운 문장 형태들의 집합이 생성되고, 그 가운데 일부는 w 로 유도될 수 있을 것이다. 계속되는 각 라운드에서, 가장 왼쪽 변수를 취해서 가능한 모든 생성규칙들을 적용한다. 새롭게 생성된 문장 형태들 가운데 w 로 유도될 수 없는 문장 형태는 제외된다. 그러나, 일반적으로, 매라운드마다 문장 형태들의 집합이 남게 된다. 첫번째 라운드가 끝나면, 단 하나의 생성규칙을 적용하여 유도될 수 있는 문장 형태들의 집합이 남게 되고, 두번째 라운드가 끝나면, 두 단계에 유도될 수 있는 문장 형태들의 집합이 남게 되고, 이런 방식으로 계속된다. 만약 w 가 L(G) 에 속하면, 반드시 이에 대한 유한한 길이의 좌측우선 유도가 존재하게 된다. 이 방법은 결국 w 의 좌측우선 유도를 만들어 낸다.
이러한 방법은 w 의 유도를 찾기 위해 시작 심볼 S 로부터 모든 가능한 유도들을 생성하기 때문에 이를 철저한 탐색 파싱 (exhaustive search parsing) 이라 부른다. 이 파싱 방법은 유도 트리를 루트에서부터 시작하여 아래로 내려오면서 구성하는 것으로 볼 수 있기 때문에, 하향식 파싱 (top-down parsing) 의 한 형태이다.
위에서 언급한 철저한 탐색 파싱은 몇 가지 문제점들이 있다. 가장 당연한 문제점은 이 방법이 너무 지루하다는 것이다. 모든 가능한 유도 과정들을 다 고려하기 때문에 효율적인 파싱을 요구하는 경우에는 사용되기 어렵다. 효율성이 가장 중요한 문제가 아니더라도, 더 확실한 단점이 있다. 이 방법은 L(G) 에 속한 문자열은 항상 파싱을 하지만, w 가 L(G) 에 속하지 않은 경우에는, 종료되지 않을 수도 있다. 이에 대한 자세한 설명을 위해, 예제 7 의 문법 G 에서 w = abb 인 경우를 고려해 보자. 이 경우에는 분명히 w 가 L(G) 에 속하지 않음을 알 수 있다. 우리가 철저한 탐색방법에 종료하는 방법을 추가하지 않으면, 철저한 탐색방법은 w 와 일치하는 문장을 찾기 위해 모든 가능한 문장 형태들을 계속 무한히 생성할 것이다.
여기서 만약 문법이 가질 수 있는 형태에 어느 제한을 두면, 철저한 탐색 파싱에서 발생하는 비종료 (nontermination) 문제가 제법 쉽게 해결될 수 있다. 예제 7 을 다시 살펴보면, 문법 G 가 S → λ 형태의 생성규칙을 갖고 있기 때문에 이러한 문제가 발생할 수 있다는 것을 알 수 있다. 이 생성규칙은 유도 과정 중에서 다음에 나타나는 문장 형태들의 길이를 줄이는데 사용될 수 있기 때문에, 언제 수행을 종료할 것인지를 쉽게 알 수가 없게 된다. 만일 이러한 생성규칙들을 갖고 있지 않다면, 문제점들이 많이 줄어든다. 실제로, 두 가지의 바람직하지 않은 형태의 생성규칙들이 알려져 있다. 이들은 A → λ 형태의 생성규칙들 뿐 아니라 A → B 형태의 생성규칙들이며, 이들을 배제시키는 것이 바람직하다. 다음 장에서 확인되는 바와 같이, 이러한 제한이 결과로 주어지는 문법의 능력에 심각한 영향은 주지 않는다.
이 예제에서의 아이디어는 일반화될 수 있고 일반적인 문맥-자유 문법에 대한 정리로 만들어질 수 있다.
철저한 탐색방법은 파싱이 항상 이루어질 수 있다는 이론적인 보증은 제공하지만, 실질적인 유용성은 제한되어 있다. 그 이유는 이 방법에 의하여 생성되는 문장 형태들의 수가 지나치게 많을 수가 있기 때문이다. 문장 형태들이 정확하게 얼마나 많이 생성되는지는 경우에 따라 다르다. 정확한 일반적인 결과는 수립될 수는 없지만 대략적인 상한은 구할 수 있다. 만일 우리가 좌측우선 유도로 제한한다면, 첫 단계 후에 우리는 최대 |P| 개의 문장 형태를 가질 수 있고, 두 번째 단계 후에는 최대 개의 문장 형태를 가질 수 있으며, 계속해서 각 단계 후의 생성될 수 있는 문장 형태들의 최대 개수를 계산할 수 있다. 정리 2 의 증명에서, 우리는 파싱이 2|w| 단계를 넘을 수 없다는 것을 관찰하였다. 따라서 문장 형태의 총 수는 아래의 식으로 주어진 수를 초과할 수 없다.
이는 철저한 탐색 파싱의 작업량이 문자열의 길이에 대하여 지수적으로 증가할 수 있음을 나타내고 있어 이 방법의 비용을 감당할 수 없게 만든다. 물론 식 (2) 는 단지 한계값이고 때로는 생성되는 문장 형태의 수가 아주 작을 수도 있다. 그럼에도 불구하고, 실제로 철저한 탐색 파싱이 대부분의 경우 아주 비효율적임이 밝혀졌다.
문맥-자유 언어에 대한 더 효율적인 파싱을 구성하는 것은 컴파일러 과목에 속하는 복잡한 내용이다. 우리는 이 구성에 대해서 몇 개의 개별적인 결과를 제외하고는 여기서 추구하지는 않을 것이다.
이 결과를 성취할 수 있는 여러 알려진 방법들이 있다. 그러나 이 방법들 모두는 우리가 추가적인 결과들을 만들어 내지 않고서는 설명할 수 없을 정도로 아주 복잡하다. 6.3 절에서 이 문제를 간략하게 다시 다루어 볼 것이다. 더 자세한 내용들은 Harrison 1978 과 Hopcroft and Ullman 1979 를 참고하기 바란다. 이 문제를 자세하게 추구하지 않는 이유는 이 알고리즘들조차도 만족스럽지 못하기 때문이다. 한 방법은 그 작업량이 문자열의 길이에 3 차 식에 비례하여 지수함수적인 알고리즘보다는 좋지만 여전히 상당히 비효율적이다. 이 알고리즘을 기반으로 하는 컴파일러는 적당히 긴 프로그램조차도 파싱하는 데 지나치게 긴 시간을 필요로 할 것이다. 우리가 갖고자 하는 것은 문자열의 길이에 비례하는 시간이 걸리는 파싱 방법이다. 그런 방법을 선형 시간 (linear time) 파싱 알고리즘이라 부른다. 우리는 일반적인 문맥-자유 언어들에 대한 어떤 선형 시간 파싱 알고리즘도 알고 있지 못한다. 그러나 그러한 알고리즘들은 제한적이지만 중요한 특정 경우에 대해서는 찾아질 수 있다.
S → aS | bSS | aSS | c
S → aS | bSS | c
s-문법들은 상당히 제한적이지만, 그들에게 약간의 흥미는 있다. 우리가 다음 절에서 알아보게 되겠지만, 일반적인 프로그래밍 언어들의 많은 기능들이 s-문법으로 기술될 수 있다.
만일 G 가 s-문법이면, L(G) 에 속한 모든 문자열 w 가 |w| 에 비례하는 노력으로 파싱될 수 있다. 이를 알아보기 위하여, 문자열 에 대한 철저한 탐색방법을 살펴보자. 좌변에 S 가 있고 우변이 으로 시작하는 생성규칙이 많아야 하나 있을 수 있기 때문에, 유도는 다음과 같이 시작되어야 한다.
그 다음에 변수 을 치환한다. 역시 많아야 하나의 선택밖에 없기 때문에, 우리는 다음과 같은 유도를 가져야만 한다.
S
우리는 이로부터 각 단계마다 하나의 단말 심볼이 생성되고 따라서 전체 과정이 |w| 단계 내에 완료되어야 한다는 것을 알 수 있다.
논의를 근거로 하여, 우리는 주어진 모든 w ∈ L(G) 에 대하여 철저한 탐색 파싱이 w 에 대한 하나의 유도 트리를 만들어 낼 것이라는 주장을 할 수 있다. 우리가 “하나의 유도 트리” 라 함은 한 문자열에 대하여 여러 개의 다른 유도 트리들이 존재할 가능성이 있기 때문이다. 이러한 상황을 모호성 (ambiguity) 이라 부른다.
그림 4
모호성은 자연 언어의 일반적인 특징이다. 자연 언어에서는 모호성이 허용되며 여러 가지 방식으로 처리되고 있다. 프로그래밍 언어에서는 각 문장이 정확히 하나의 의미로 해석되어야 하므로 가능한 한 모호성을 제거해야만 한다. 때로는 주어진 문법을 동치이면서 모호하지 않은 (unambiguous) 다른 문법으로 다시 구성함으로써 모호성을 제거할 수 있다.
예제 11
문법 G = ({E, I}, {a, b, c, +, *, (, )}, E, P) 의 생성규칙이 다음과 같다고 하자.
E → I E → E + E E → E * E E → (E) I → a|b|c
(a + b) * c 와 a * b + c 와 같은 문자열들이 L(G) 에 속한다. 문법 G 가 C 나 Pascal 과 같은 프로그래밍 언어에 대한 산술식들의 제한된 부분집합을 생성하는 것을 쉽게 알 수 있다. 문법 G 는 모호하다. 이는 문자열 a + b * c 가 그림 5 에서와 같이 상이한 유도 트리들을 갖고 있기 때문이다.
오토마타 이론 공부 (10) – 문맥 자유 언어
위는 회문의 언어를 표현하는 문맥 자유 문법이다. 먼저 문맥 자유 문법의 4가지 구성 요소를 가지고 있는지 확인해보자.
모든 화살표 왼쪽에 있는 A는 변수(Variable)이다. 보통 변수는 알파벳 대문자로 적는데, 위 문맥 자유 언어의 변수 V는 A만 있는 것을 알 수 있다.
V = {A}
화살표는 왼쪽에 있는 변수가 오른쪽에 있는 것을 생성(production)함을 의미한다.
참고로, 화살표를 기준으로 왼쪽을 Head, 오른쪽을 Body라고 한다.
4가지 구성 요소에서 P가 위의 다섯가지 생성 규칙을 포함하고 있다.
P : A → ε | A → 0 | A → 1 | A → 0A0 | A → 1A1
그리고 화살표 오른쪽에 있는 것은 변수에 의해 생성된 것인데, 단말(terminal)과 변수가 모두 있을 수 있다.
단말(terminal)은, 쉽게 생각하면 앱실론을 포함한 알파벳의 집합이다.
위의 언어는 0과 1로 이루어진 언어이기 때문에, 단말의 집합 T는 {ε, 0, 1} 3개의 원소로 이루어져 있다.
T = {ε, 0, 1}
(앱실론은 생략 가능하다.)
시작 변수는 보통 S로 나타내지만, 위의 문법은 시작 변수가 A이다.
S = A
종합해보면, 위의 문법 G는 다음과 같다.
G = ({A}, {0, 1}, P, A}
P : A → ε | A → 0 | A → 1 | A → 0A0 | A → 1A1
4가지 구성 요소는 잘 만족한다. 그리고 생성(production) 규칙이 A → a의 구조를 만족시키는 것을 확인할 수 있다.
생성 규칙은 아주 직관적이다. 왼쪽의 변수가 오른쪽에 있는 변수와 단말을 생성해낸다고 생각하자.
또한 1. 위의 문법으로 생성가능한 모든 문자열은 회문이며, 2. 모든 회문은 위의 문법으로 생성가능하기 때문에, 회문의 언어를 표현하는 문맥 자유 문법이라고 확실하게 말할 수 있다.
먼저 위 문법으로 문자열을 생성하는 것을 보이겠다.
시작 변수 A에서 시작한다.
문맥 자유 문법 (Context Free Grammar, CFG)
반응형
개요
브라우저의 동작 과정 중 렌더링 엔진은 사용자에게 요청받은 문서를 파싱해서 화면에 보여주는 역할을 한다. HTML 문서를 파싱할 때 사용되는 파서의 종류는 문법에 따라 크게 두가지로 나뉘는데 이는 HTML을 파싱하는 파서와 CSS 또는 JavaScript를 파싱하는 파서이다. 왜냐하면 HTML은 언어 자체의 너그러운 속성과 사용자의 변경에 의한 재파싱 등 신경써줘야할 부분이 많기 때문에 문맥 자유 문법에 의해 쉽게 정의할 수가 없다. 그렇다면 문맥 자유 문법이란 무엇일까?
문맥 자유 문법
우리가 영어 문장에서 문장의 의미를 이해하기 위해서 영어 문법을 이해하고 있어야 하는 것이 당연하듯이 파서 또한 프로그래밍 언어를 이해하기 위해서는 프로그래밍 언어 정의에 사용된 문법을 이해하고 있어야한다. 대부분의 프로그래밍 언어는 문맥 자유 문법을 기반으로 정의되어 있다. 문맥 자유 문법은 촘스키 위계의 type-2에 해당하는 문법이다.
촘스키 언어 계층은 정규 언어, 문맥 자유 언어, 문맥 의존 언어, 귀납적 가산 언어 4계층으로 형식 언어(특정한 법칙들에 따라 적절하게 구성된 유한한 길이의 문자열의 집합)를 규정한다.
촘스키 위계
문맥 자유 문법 G는 G=(V, T, P, S) 의 순서쌍으로 정의되며, 각 원소의 의미는 아래와 같다.
V : nonterminal의 유한집합. nonterminal은 언어에 대한 계층적 구조를 부여하는 역할을 한다.
T : terminal의 유한집합. terminal은 더 이상 다른 terminal이나 nonterminal로 유도가 불가능하다. V와 T는 서로소이다.
P : production(생성규칙)의 유한집합. 문법의 생성규칙은 nonterminal과 terminal들이 조합되어 문자열을 생성할 수 있는 방법을 명시한다.
S : 문법에서는 한 개의 nonterminal을 시작 기호(start symbol)로 갖는다. S는 해당 문법의 시작 기호를 나타내며, 문법은 항상 시작 기호로부터 시작된다.
문맥 자유 문법의 정의에서 생성 규칙은 다음과 같이 정의된다. 아래의 생성규칙을 이해하기 위해서는 언어 도메인에서의 연산에 대한 이해가 필요하다.
문맥 자유 문법에서 생성규칙의 가장 큰 특징은 생성규칙의 좌변에는 항상 1개의 nonterminal만 올 수 있다는 것이다. 하나의 nonterminal만 고려하여 문자열을 생성하기 때문에 문맥에 자유롭다는 의미에서 문맥 자유 문법이라고 한다.
참고:
https://ko.wikipedia.org/wiki/%EB%AC%B8%EB%A7%A5_%EC%9E%90%EC%9C%A0_%EB%AC%B8%EB%B2%95
https://untitledtblog.tistory.com/93
반응형
[Automata Theory] Context-Free Languages
Context-Free Languages
문맥-자유 언어
* Parsing (파싱)
– 문장을 문법적 유도를 통하여 설명하는 과정이다.
– 문장의 구조를 표현하는 방법 중 하나이다.
– \(L(G)\)에 속하는 \(w\)가 유도되는데 사용된 일련의 생성규칙들을 찾는 과정이다.
Context-Free Grammars (문맥-자유 문법)
Definition 5.1 CFG (Context-Free Grammar; 문맥-자유 문법)
문법 \(G = (V, T, S, P)\) 에서 모든 생성 규칙이
\(A \to x\)
\((A \in V, x \in (V \cup T)^*)\)
의 형태를 가지면,
\(G\)를 문맥-자유 문법(CFG)이라 한다.
※ CFG의 생성규칙에서 왼쪽항엔 하나의 변수,
오른쪽 항에는 Symbol들과 Variable들로 구성된 String이 위치하면,
CFG이다.
Language \(L\)에 대해,
\(L = L(G) \iff\) 문맥-자유 문법 \(G\)가 존재하면,
\(L\)을 문맥-자유 언어(CFL: Context-Free Language)라 한다.
※ 모든 Regular Grammar는 항상 CFG이다.
– 단, 역은 성립하지 않는다.
※ 모든 Linear Grammar는 항상 CFG이다.
– 단, 역은 성립하지 않는다.
Example 5.1
아래 생성규칙을 갖는 Grammar \(G = (\{S\}, \{a, b\}, S, P)\) 는 CFG이다.
\(S \to aSa\)
\(S \to bSb\)
\(S \to \lambda\)
String “\(aabbaa\)”의 \(G\)에 의한 Derivations는 아래와 같다.
\(S \Rightarrow aSa \Rightarrow aaSaa \Rightarrow aabSbaa \Rightarrow aabbaa\)
\(G\)에 의해 정의되는 Language \(L\)은 아래와 같다.
\(L(G) = \{ww^R : w \in \{a, b\}^*\}\)
(\(L(G)\)는 CFL이지만, Regular Language는 아니다.)
Example 5.2
아래 생성규칙을 갖는 Grammar \(G = (\{S, A, B\}, \{a, b\}, S, P)\) 는 CFG이다.
\(S \to abB\)
\(A \to aaBb\)
\(B \to bbAa\)
\(A \to \lambda\)
\(G\)에 의해 정의되는 Language \(L\)은 아래와 같다.
\(L(G) = \{ab(bbaa)^nbba(ba)^n : n \geq 0\}\)
Example 5.3
\(L = \{a^nb^m : n
eq m\}\) 은 CFL이다.
pf)
\(S \to AE \; | \; EB\)
\(E \to aEb \; | \; \lambda\)
\(A \to aA \; | \; a\)
\(B \to bB \; | \; b\)
\(\therefore\) 위 문법은 CFG이므로, \(L\)은 CFL이다.
– 단 위 문법은 Linear Grammar는 아니다.
Example 5.4
CFG \(G\)는 아래와 같다.
\(S \to aSb \; | \; SS \; | \; \lambda\)
\(G\)가 생성하는 Language \(L(G)\)는
\(L(G) = \{w \in \{a, b\}^* : n_a(w) = n_b(w)\) 그리고 \(n_a(v) \geq n_b(v),\) 단, \(v\)는 \(w\)의 Prefix이다.\(\}\)
이 문에서 ‘\(a\)’를 ‘{‘ 에, ‘\(b\)’를 ‘}’ 로 대치하면,
프로그래밍 언어에서 Nested Structure(중첩 구조)를 표현하는 문법이 된다.
Leftmost and Rightmost Derivations (좌측우선 유도와 우측우선 유도)
– Linear Grammar가 아닌 CFG에서는 두 개 이상의 변수가 포함된 문장이 존재할 수 있다.
– 이 경우, 여러 변수들을 어떠한 순서로 대체할 것인가에 대한 기준이 필요하다.
\(L(G) = \{a^{2n}b^m : n \geq 0, m \geq 0\}\)인 \(L(G)\)의 생성 규칙은 아래와 같다.
\(1: S \to AB\)
\(2: A \to aaA\)
\(3: A \to \lambda\)
\(4: B \to Bb\)
\(5: B \to \lambda\)
String ‘\(aab\)’에 대한 Sentential Form은 아래와 같다.
i. Leftmost Derivaion
\(S \Rightarrow^1 AB \Rightarrow^2 aaAB \Rightarrow^3 aaB \Rightarrow^4 aaBb \Rightarrow^5 aab\)
ii. Rightmost Derivation
\(S \Rightarrow^1 AB \Rightarrow^4 ABb \Rightarrow^5 Ab \Rightarrow^2 aaAb \Rightarrow^3 aab\)
Definition 5.2 Leftmost Derivation(좌측우선 유도), Rightmost Derivation(우측우선 유도)
Leftmost Derivation(좌측우선 유도)
– 유도 과정의 각 단계에서 각 Sentential Form의 가장 좌측 변수부터 대체되는 Derivation이다.
Rightmost Derivation(우측우선 유도)
– 유도 과정의 각 단계에서 각 Sentential Form의 가장 좌측 변수부터 대체되는 Derivation이다.
Example 5.5
아래와 같은 생성규칙을 갖는 CFG가 있다 하자.
\(S \to aAB\)
\(A \to bBb\)
\(B \to A \; | \; \lambda\)
이 CFG에 대한 Leftmost Derivation은
\(S \Rightarrow aAB \Rightarrow abBbB \Rightarrow abAbB \Rightarrow abbBbbB \Rightarrow abbbbB \Rightarrow abbbb\)
이 CFG에 대한 Rightmost Derivation은
\(S \Rightarrow aAB \Rightarrow aA \Rightarrow aaBb \Rightarrow abAb \Rightarrow abbBbb \Rightarrow abbbb\)
Derivation Tree (유도 트리)
– Derivation 과정(Sentential Form)을 Ordered Tree로 표현하는 방법이다.
– Parent Node는 생성규칙의 좌변에 해당되고, Child Node는 생성규칙의 우변에 해당된다.
– 유도 트리에서는 생성규칙의 순서를 표현할 수 없다.
Definition 5.3 Ordered Tree가 Derivation Tree가 되기 위한 Necessary and Sufficient Condition(필요충분조건)
1. 루트노드의 Label은 시작 변수 \(S\)이다.
2. 각 리프노드의 Label은 \(T \cup \{\lambda\}\)의 Symbol이다.
3. 각 내부노드의 Label은 \(V\)에 속한 변수이다.
4. 만약, Label이 \(A \in V\)인 노드가 Label이 \(a_1, a_2, \cdots, a_n\)인 자식노드를 가졌다면,
\(P\)는 아래 형태의 생성 규칙을 갖고 있어야 한다.
\(A \to a_1a_2 \cdots a_n\)
5. Label이 \(\lambda\) 인 자식노드는 형제노드가 없다.
(즉, Label이 \(\lambda\)인 자식노드를 갖는 노드는 다른 자식들을 가질 수 없다.)
* Partial Derivation Tree (부분 유도 트리)
– 위 조건 3, 4, 5를 항상 만족하며, 1은 선택적으로 만족시키며, 조건 2 대신 2.(a)를 만족시키는 유도 트리이다.
2.(a) 모든 리프노드의 Label은 \(V \cup T \cup \{\lambda\}\)의 Symbol이다.
(즉, 부분 유도 트리에서는 리프노드에 변수도 존재할 수 있다.)
* Yield (생성물)
– Derivation Tree의 리프노드들을 왼쪽으로 오른쪽으로 차례로 읽어들인 Symbol들로 구성된(\(\lambda\)는 생략한)
String을 이 트리의 Yield라 한다.
– Yield는 탐색이 이루어지지 않은 가장 왼쪽 Branch부터 DFS로 Traversal할 경우 만나는 Symbol들을 순서대로 열거한 String이다.
Example 5.6
CFG \(G\)가 아래와 같은 생성규칙을 갖는다 하자.
\(S \to aAB\)
\(A \to bBb\)
\(B \to A \; | \; \lambda\)
\(G\)에 대한 Derivation Tree는 아래와 같다.
Yield = \(abbbb\)
또한, Partial Derivation Tree 중 하나는 아래와 같이 나타낼 수 있다.
Yield = \(abBbB\)
Relation Between Sentential Forms and Derivation Trees (문장형태와 유도 트리와의 관계)
Theorem 5.1
\(G = (V, T, S, P)\) 가 CFG라 하자.
모든 \(w \in L(G)\)에 대해, Yield가 \(w\)인 \(G\)의 Derivation Tree가 존재한다.
역으로, 모든 Derivation Tree의 Yield은 \(L(G)\)에 속한다.
만약, \(t_G\)가 루트노드가 \(S\)인 \(G\)의 Partial Derivation Tree이면,
\(t_G\)의 Yield은 \(G\)의 Sentential Form이다.
pf)
\(L(G)\)의 모든 Sentential Form에 대한 Partial Derivation Tree가 존재함을 귀납적으로 보인다.
(Basis)
한 단계의 유도 과정으로 얻어진 모든 Sentential Form에 대한 Partial Derivation Tree가 존재한다.
예를 들어. \(S \Rightarrow u\) 이면, 이에 대한 생성규칙 \(S \to u\)가 존재하며, 이에 대응되는 Partial Derivation Tree가 존재한다.
(Inductive Step)
\(n\)단계의 유도 과정으로 유도되는 모든 Sentential Form에 대해, 이에 대응되는 Partial Derivation Tree가 존재한다 가정하자.
\(n+1\)단계를 거친 후 유도되는 문장 \(w\)는 아래와 같이 유도된다.
\(S \Rightarrow^* xAy \qquad (x, y \in (V \cup T)^*, A \in V)\)
가정에 의해, Yield가 \(xAy\)인 Partial Derivation Tree가 존재한다.
또한, 유도의 마지막 과정으로
\(xAy \Rightarrow xa_1a_2 \cdots a_m y = w \qquad (a_i \in V \cup T)\)
가 이루어진다.
마지막 유도 과정에서 적용된 생성규칙 \(A \to a_1a_2 \cdot a_m\) 또한 \(G\)에 존재하는 생성규칙이다.
따라서, Partial Derivation Tree의 리프노드 \(A\)를 확장함으로써 Yield가 \(xa_1a_2 \cdots a_my = w\)인 Partial Derivation Tree를 얻게 된다.
즉, 모든 Sentential Form에 대해 성립된다.
Parsing and Ambiguity (파싱과 모호성)
Parsing and Membership (파싱과 소속성)
* Exhaustive Search Parsing (철저한 탐색 파싱) (= Back-Tracking)
– String \(w\)의 Derivation을 찾기 위해, 시작 Symbol \(S\)로부터 모든 가능한 Derivation을 생성한다.
– Derivation Tree의 루트에서부터 내려오며 구성하기 때문에 Top-Down Parsing의 한 형태이다.
– 효율적인 방법은 아니며, \(L(G)\)에 속하지 않는 String에 대한 Parsing을 시도할 경우, 종료되지 않을 수 있다.
– Unit Production(\(A \to B\) 형태)과 Lambda Production(\(A \to \lambda\) 형태)은 유도과정 중 Sentential Form의 길이를 줄여서,
유도가 언제 종료될 지 예측을 힘들게 하기 때문에 권장되지 않는다.
(유도과정은 본질적으로, Sentential Form의 길이를 늘리는 과정이다.)
ex) Unit Production, Lambda Production으로 인해 \(S \to SS \to S \to SS\) 와 같은 비효율적인 유도가 생성될 수 있다.
– Exhaustive Search Parsing 방법에서는 각 유도 단계에서 Sentential Form에 적어도 하나의 Symbol이 추가되기 때문에
\(|w|\) 단계 이내에 모든 Parsing 과정이 종료되며,
\(|w|\) 단계 후에는, Parsing을 완료시키거나, \(w\)가 \(L(G)\)에 속하지 않는다는 판정을 내리게 된다.
생성 규칙의 개수를 \(|P|\), \(w\)를 구성하는 Symbol들의 개수를 \(|w|\)라 할 때,
Exhaustive Search Parsing에서 생성되는 Sentential Form의 개수의 상한선(\(M\))은 아래와 같다.
\(M = |P| + |P|^2 + \cdots + |P|^{2|w|}\)
\(= O(|P|^{2|w|+1})\)
즉, Exhaustive Search Parsing 방법의 실행 시간은 최악의 경우, Exponential Time에 비례한다.
Example 5.7
아래 생성규칙을 갖는 Grammar \(G\)에서
String \(w = aabb\)가 유도되는지를 보여라.
\(S \to SS \; | \; aSb \; | \; bSa \; | \; \lambda\)
pf)
(1st Round)
\(1: S \Rightarrow SS \\
2: S \Rightarrow aSb \\
3: S \Rightarrow bSa \\
4: S \Rightarrow \lambda\)
– 3, 4번 생성규칙은 \(aabb\)를 절대 유도할 수 없으므로 제외한다.
– 즉, 2nd Round부터는 1, 2번 생성규칙만 고려한다.
(2nd Round)
\(1: S \Rightarrow SS \Rightarrow SSS \\
2: S \Rightarrow SS \Rightarrow aSbS \\
3: S \Rightarrow SS \Rightarrow bSaS \\
4: S \Rightarrow SS \Rightarrow S \)
\(5: S \Rightarrow aSb \Rightarrow aSSb \\
6: S \Rightarrow aSb \Rightarrow aaSbb \\
7: S \Rightarrow aSb \Rightarrow abSab \\
8: S \Rightarrow aSb \Rightarrow ab \)
– 최종적으로, 6번 Derivation에서 \(aabb\)를 아래와 같이 유도해낼 수 있다.
\(S \Rightarrow aSb \Rightarrow aaSbb \Rightarrow aabb\)
Theorem 5.2
CFG \(G = (V, T, S, P) 가\)
Unit Production(\(A \to B\) 형태)과 Lambda Production(\(A \to \lambda\) 형태)
을 갖지 않는다고 하자.
이 경우, Exhaustive Search Parsing은
어떤 \(w \in \Sigma^*\) 의 Parsing을 산출하거나,
Parsing이 불가능하다 판별하는 알고리즘이 된다.
Theorem 5.3
모든 CFG에 대하여 임의의 \(w \in L(G)\)를 \(|w|^3\) 에 비례하는 수의 단계 내에 Parsing하는 알고리즘이 존재한다.
Definition 5.4 Simple Grammar (S-Grammar)
CFG \(G = (V, T, S, P)\)의 모든 생성규칙들이
\(A \to ax\)
(\(A \in V, a \in T, x \in V^*\) 이고, (여기까지는 Greibach Normal Form*과 동일하다.)
임의의 Pair \((A, a)\)는 \(P\)에서 1회 이하로 나타난다. = Production이 Unique하게 결정된다.)
형태와 같으면,
해당 문법을 Simple Grammar(단순 문법) 혹은 S-Grammar(S-문법)이라 부른다.
(생성 규칙의 오른쪽 항에, 하나의 Symbol과 0개 이상의 Variable로 구성되고, 각 Symbol은 한 번만 나타나는 문법 형태)
\(G\)가 S-Grammar이면, \(L(G)\)에 속하는 String \(w\)가 \(|w|\) 에 비례하는 시간에 Parsing될 수 있다.
※ S-Grammar는 Ideal한 개념으로, 실제 세계에 응용되기는 어렵다.
– 두 번째 조건, “임의의 Pair \((A, a)\)가 \(P\)에서 1회 이하로 나타난다.”이 매우 Strict하기 때문에
실제에서 S-Grammar는 구현되기가 어렵다.
* Greibach Normal Form (GNF; 그레이바흐 정규형)
– A \to ax 형태의 Grammar를 의미한다.
\((A \in V, a \in T, x \in V^*)\)
– 모든 CFG는 Greibach Normal Form으로 변환 가능하다.
Example 5.9
\(S \to aS \; | \; bSS \; | \; c\)
는 S-Grammar이다.
\(S \to aS \; | \; bSS \; | \; aSS \; | \; c\)
는 S-Grammar가 아니다.
(\(\because\) Pair \((S, a)\)가 \(S \to aS\)에도 나타나고, \(S \to aSS\)에도 나타나기 때문이다.)
Ambiguity in Grammars and Language (문법과 언어에서의 모호성)
* Ambiguity (모호성)
– 한 String에 대해, 여러 개의 다른 Derivation Tree가 파생되는 상황을 의미한다.
– Natural Language(자연어)의 일반적인 특징이다.
– Programming Language의 경우, 한 문장이 정확히 하나의 의미로 해석되어야 하므로 모호성을 필히 제거해야 한다.
(모호성을 제거하는 방법으로, 주어진 Grammar를 Equivalent이면서 Unambiguous한 다른 Grammar로 대치하는 방법이 있다.)
Definition 5.5 Ambiguous (모호)
CFG \(G\)에서 두 개 이상의 서로 다른 Derivation Tree를 갖는 String \(w\)가 존재하면,
“문법 \(G\)는 Ambiguous하다.”라 표현한다.
즉, 모호성은 어떤 String \(w\)에 대해 두 개 이상의 Leftmost Derivation 또는 Rightmost Derivation이 존재하는 것을 의미한다.
Example. \(\texttt{if}\) Statement
\(\texttt{if}\) 구문의 생성규칙이 아래와 같다 하자.
\(S \to \texttt{if} \; \mathrm{c} \; \texttt{then} \; S \; \texttt{else} \; S\)
\(S \to \texttt{if} \; \mathrm{c} \; \texttt{then} \; S\)
\(S \to a\)
\(w = \texttt{if} \; c_1 \; \texttt{then if} \; c_2 \; \texttt{then} \; A \; \texttt{else} \; B\)
– 즉, 위 생성규칙에서 \(w\)와 같은 구문을 Parsing하고자 하는 경우, Dangling else Problem*를 야기할 수 있다.
* Dangling else Problem
– \(\texttt{else}\) 구문이 \(c_1\)의 \(\texttt{if}\) 구문에 연계된 것인지, \(c_2\)의 \(\texttt{if}\) 구문에 연계된 것인지 모호한 상황을 의미한다.
Example 5.10
생성규칙
\(S \to aSb \; | \; SS \; | \; \lambda\)
를 갖는 Grammar \(G\)는 Ambiguous하다.
String \(aabb\)에 대해,
\(G\)는 아래와 같은 두 개의 Derivation Tree를 갖게 하기 때문이다.
Example 5.11
Grammar \(G = (\{E, I\}, \{a, b, c, +, *, (, )\}, E, P)\)의 생성규칙은 아래와 같다.
\(P\)는 아래와 같다.
\(E \to I\)
\(E \to E+E\)
\(E \to E*E\)
\(E \to (E)\)
\(I \to a \; | \; b \; | \; c\)
이러한 경우,
\((a+b)*c\),
\(a*b+c\)
와 같은 String들이 \(L(G)\)에 속한다.
그러나, Grammar \(G\)는 Ambiguous하다.
\(a+b*c\) 에 대해 아래와 같은 두 Derivation Tree를 갖게 하기 때문이다.
이와 같은 Ambiguous를 제거하기 위한 문법 외적인 방법 중 하나로
연산자 간 우선순위(Precedence Rule)를 정의해놓는 방법이 있다.
그러나, 단일한 Parsing만이 가능하도록 문법을 재작성하는 것이 바람직하다.
Example 5.12
Example 5.11의 Grammar \(G\)에 Precedence Rule을 적용하여 재작성한 Grammar \(G’\)은 아래와 같다.
Grammar \(G’ = (\{E, I\}, \{a, b, c, +, *, (, )\}, E, P’)\)
\(P’\)은 아래와 같다.
\(E \to T\)
\(T \to F\)
\(F \to I\)
\(E \to E+T\)
\(T \to T*F\)
\(F \to (E)\)
\(I \to a \; | \; b \; | \; c\)
문장 \(a+b*c\) 에 대한 Derivation Tree는 아래와 같다.
이 String에 대한 다른 Derivation Tree는 존재하지 않으므로,
수정된 Grammar \(G’\)은 Unambiguous하며,
\(G\)와 \(G’\)은 Equivalent하다.
※ Regular Grammar와 달리,
CFG이 Ambiguous한지, 두 CFG가 Equivalent한 지를 판별하는 Algorithm은 존재하지 않는다.
Definition 5.6 Inherently Ambiguous (고유적 모호)
CFL \(L\)이 Unambiguous한 Grammar를 가지면,
“\(L\)은 Unambiguous하다.”라 표현한다.
\(L\)을 생성하는 모든 Grammar에 대해,
각 Grammar가 Ambiguous하면,
“\(L\)은 Inherently Ambiguous하다. (\(L\)은 고유적으로 모호하다.)”라 표현한다.
Example 5.13
Language \(L = \{a^nb^nc^m : n \geq 0, m \geq 0\} \cup \{a^nb^mc^m : n \geq 0, m \geq 0\}\)
이다.
이 때, \(L\)은 Inherently Ambiguous하다.
pf)
(\(L\)이 CFL임을 보이는 과정)
\(L = L_1 \cup L_2\)
라 하자.
\(L_1\)의 생성 규칙은 아래와 같다.
\(S_1 \to S_1c \; | \; A\)
\(A \to aAb \; | \; \lambda\)
\(L_2\)의 생성 규칙은 아래와 같다.
\(S_2 \to aS_2 \; | \; B\)
\(B \to bBc \; | \; \lambda\)
\(L\)은 위 두 Grammar를 결합하고,
\(S \to S_1 \; | \; S2\) 와 같은 생성규칙을 추가하여
\(L\)만의 Grammar를 생성할 수 있다.
(\(L\)이 Ambiguous함을 보이는 과정)
이 때, 위와 같은 \(L\)을 생성하는 Grammar는 Ambiguous하다.
String \(a^nb^nc^n\)의 경우,
\(S \Rightarrow S_1\)으로 시작할 수 있고,
\(S \Rightarrow S_2\)로 시작할 수도 있기 때문이다.
다시 말해서, 위 Grammar의 경우,
\(L_1\)은 \(a\)와 \(b\)의 개수가 같아야 하고,
\(L_2\)는 \(b\)와 \(c\)의 개수가 같아야 한다.
즉, \(L\)에서 \(n=m\)인 경우의 문장을 단일한 Parsing으로 생성하게 할 수 없다.
단, \(L\)이 Unambiguous한 다른 Grammar로 표현될 수도 있기 때문에,
이러한 하나의 반례만으로 Inherently Ambiguous하다고 할 수는 없다.
Context-Free Grammars and Programming Languages (문맥-자유 문법과 프로그래밍 언어)
– Formal Language Theory의 응용 분야 중 하나로,
Programming Language(이하 PL)에 대한 Compiler 혹은 Interpreter를 설계가 있다.
– Regular Language를 이용하여 PL의 어휘, 단어와 같은 단순한 패턴을 정의하고,
더 복잡한 구성사항들에 대한 모델링은 CFL을 통해 이루어진다.
– PL의 Specification은 Unambiguous해야한다.
* Backus-Naur Form (BNF)
– PL에 대한 Grammar를 작성하는, 전통적인 표기법이다.
– Variable들은 <>괄호내에 표기하고, Terminal Symbol들은 특별한 표시를 하지 않는다.
Example. BNF
::= | + ::= | * – 여기서, \(*\)와 \(+\)는 Terminial Symbol이며, \(|\)는 을 의미하며, \(::=\)는 \(\to\)를 의미한다.
Example. while Statement in C as BNF
::= while – \(\texttt{while}\)은 Terminal Symbol이다.
– 즉, 이 Grammar는 S-Grammar의 생성규칙과 비슷하여, 쉽고 효율적으로 Parse된다.
※ \(\texttt{while}\)과 같은 Keyword는 프로그래머에게 시각적인 구조를 제공할 뿐만 아니라,
컴파일러의 작업을 더욱 쉽게 만들어준다.
* Syntax (구문)
– CFG로 모델링 될 수 있는 PL의 형태를 의미한다.
– 하지만, CFG만으로는 Semantics를 표현할 수 없다.
Reference: An Introduction to Formal Languages and Automata 6E (Peter Linz 저, Jones & Bartlett Learning, 2017)
[Automata] Context-free Language ( 문맥 자유 언어 )
Chapter 5의 내용이다!
이전 포스팅에서 다뤘듯이 정규언어가 좋긴 한데, 프로그래밍 언어를 다루기에는 조금 부족한 요소들이 있었다.
L = {a^n b^n: n>=0} 이면, a=(, b=)일 때 프로그래밍에서 괄호가 중첩인지 확인하기 좋지만 얘 역시 정규언어가 아니였다.
(정규언어가 아님은 펌핑lemma를 통해서 보였다.)
따라서 우리는 정규언어보다 더 큰 개념인 ‘문맥 자유 언어’를 다룬다.
정규언어의 큰 단점은, 좌변은 한개의 변수이고 우변은 특정한 형태여야 했다. (정의임)
문맥 자유언어는 우변에 특정한 형태 대신 아무거나 올 수 있게 허용해줌으로써 더 강력해진다!!
정규언어 ⊂ 문맥 자유 언어이다.
* linear grammar?
문제들은 주로, 주어진 언어가 문맥자유언어인지 보이라는 유형이 많다.
언어에 맞는 문법을 유도해서, 문법이 문맥자유문법에 해당하면 맞다는 식으로 풀어내면 된다.
최좌단유도와 최우단유도
linear하지 않은 문법에서는 유도하고 나면 한개 이상의 변수가 포함된 문장 형태가 나올 수 있다. 그런 경우를 방지하기 위해서 어떤 변수가 대체될 지 우선순위를 정해준다. 그리고 최좌단 변수부터, 또는 최우단 변수부터 유도하는 식으로 해서 순서를 정해준다. (순서를 안정해도 결과는 같긴 하다!)
parse tree (derivation tree)
partial derivation tree
parse tree에서 1조건이 없고, 2조건이
이면 partial derivation tree이다.
Sentential Form과 Derivation Tree의 관계
뭔가 굉장히 거창하게 서술되어있지만 그냥 tree로 문장 유도할 수 있다는 것..
증명이 나와있다 (Theorem 5.1)
Theorem 5.1
Grammar G는 quadrople G = (V, T, S, P) 로 정의되는데 이 G가 context-free grammar라고 가정하자.
V: variable의 유한집합
T: terminal symbol의 유한집합
S: start하는 variable, T에 항상 포함되어있어야 한다
P: production의 유한 집합
그렇다면 모든 w ⊆ L(G)에 대하여, 항상 yield가 w인 G의 derivation tree가 존재한다.
역으로, 모든 derivation tree의 yield는 L(G)에 있다.
또한, t_G는 root가 S인 어떤 partial derivation tree일 때, t_G의 yield는 G의 sentential form이다.
Parsing과 Ambiguity
ambiguity: 하나의 문자열이 여러개의 tree로 생성될 수 있는 경우
만약 프로그래밍 문법이 ambigious하다면 문제가 될 것이므로 가능한 없애려고 한다.
L이 모호하지 않은 문법이 하나라도 존재하는 문맥자유언어이면, L은 모호하지 않다.
L이 만드는 모든 문법이 모호하다면, 언어는 고유적으로 모호하다고 정의한다. (Definition 5.6)
Exhaustive Search Parsing
: G=(V, T, S, P)인 context free grammar 중에서
A->ƛ, A->B의 form이 하나도 없다면 , (A, B ⊆ V)
exhaustive search parsing 방법은 임의의 w ⊆Σ*에 대해서, 파싱이 불가능한지 아니면 w가 생기는 지 알려줄 수 있는 알고리즘이다.
Complexity가 O(|P|^(2|w| + 1))인데, |P|+ |P|^2 + … + |P|^2|w| 라서 그렇다.
하지만 이 complexity가 너무 높아서 실제로는 CYK라는 알고리즘을 쓴다고 한다. 얘는 |w|^3, linear한 시간복잡도이다.
이 내용은 chapter7에서 추가적으로 다룬다.
Top-down parsing
//WIP
s-grammar(simple grammar)
S->aA도 있고 S->aB도 있으면 단순 문법이 아니다.
꽤 많은 프로그래밍 언어가 s-grammar로 정의될 수 있다고 한다.
실제 프로그래밍 언어에서의 활용
C언어에서의 예시를 하나 보자!
:= while
:= | + := | * BNF이긴 한데 사실상 CFG랑 동일한 문법이다. ->가 := 된것 제외하면!
while문은 s-grammar라서 쉽게 해석이 가능하다.
은 s-grammar아니여서 해석이 좀 더 어렵다. 컴파일러에서는 LL, LR문법을 쓰는데 이는 Chapter6에서 좀 더 다룰거라고 한다.
키워드에 대한 정보 문맥 자유 문법
다음은 Bing에서 문맥 자유 문법 주제에 대한 검색 결과입니다. 필요한 경우 더 읽을 수 있습니다.
이 기사는 인터넷의 다양한 출처에서 편집되었습니다. 이 기사가 유용했기를 바랍니다. 이 기사가 유용하다고 생각되면 공유하십시오. 매우 감사합니다!
사람들이 주제에 대해 자주 검색하는 키워드 Compiler Lecture 04: Grammar (in Korean)
- #Compiler
- #Grammar
- #Context Free Grammar
Compiler #Lecture #04: #Grammar #(in #Korean)
YouTube에서 문맥 자유 문법 주제의 다른 동영상 보기
주제에 대한 기사를 시청해 주셔서 감사합니다 Compiler Lecture 04: Grammar (in Korean) | 문맥 자유 문법, 이 기사가 유용하다고 생각되면 공유하십시오, 매우 감사합니다.