나무모에 미러 (일반/밝은 화면)
최근 수정 시각 : 2026-01-06 21:35:58

파싱

파서에서 넘어옴

파일:다른 뜻 아이콘.svg  
#!if 넘어옴1 != null
'''파서'''{{{#!if 넘어옴2 == null
{{{#!if 넘어옴1[넘어옴1.length - 1] >= 0xAC00 && 넘어옴1[넘어옴1.length - 1] <= 0xD7A3
{{{#!if ((넘어옴1[넘어옴1.length - 1] - 0xAC00) % 28) == 0
는}}}{{{#!if ((넘어옴1[넘어옴1.length - 1] - 0xAC00) % 28) != 0
은}}}}}}{{{#!if 넘어옴1[넘어옴1.length - 1] < 0xAC00 || 넘어옴1[넘어옴1.length - 1] > 0xD7A3
은(는)}}}}}}{{{#!if 넘어옴2 != null
, ''''''{{{#!if 넘어옴3 == null
{{{#!if 넘어옴2[넘어옴2.length - 1] >= 0xAC00 && 넘어옴2[넘어옴2.length - 1] <= 0xD7A3
{{{#!if ((넘어옴2[넘어옴2.length - 1] - 0xAC00) % 28) == 0
는}}}{{{#!if ((넘어옴2[넘어옴2.length - 1] - 0xAC00) % 28) != 0
은}}}}}}{{{#!if 넘어옴2[넘어옴2.length - 1] < 0xAC00 || 넘어옴2[넘어옴2.length - 1] > 0xD7A3
은(는)}}}}}}}}}{{{#!if 넘어옴3 != null
, ''''''{{{#!if 넘어옴4 == null
{{{#!if 넘어옴3[넘어옴3.length - 1] >= 0xAC00 && 넘어옴3[넘어옴3.length - 1] <= 0xD7A3
{{{#!if ((넘어옴3[넘어옴3.length - 1] - 0xAC00) % 28) == 0
는}}}{{{#!if ((넘어옴3[넘어옴3.length - 1] - 0xAC00) % 28) != 0
은}}}}}}{{{#!if 넘어옴3[넘어옴3.length - 1] < 0xAC00 || 넘어옴3[넘어옴3.length - 1] > 0xD7A3
은(는)}}}}}}}}}{{{#!if 넘어옴4 != null
, ''''''{{{#!if 넘어옴5 == null
{{{#!if 넘어옴4[넘어옴4.length - 1] >= 0xAC00 && 넘어옴4[넘어옴4.length - 1] <= 0xD7A3
{{{#!if ((넘어옴4[넘어옴4.length - 1] - 0xAC00) % 28) == 0
는}}}{{{#!if ((넘어옴4[넘어옴4.length - 1] - 0xAC00) % 28) != 0
은}}}}}}{{{#!if 넘어옴4[넘어옴4.length - 1] < 0xAC00 || 넘어옴4[넘어옴4.length - 1] > 0xD7A3
은(는)}}}}}}}}}{{{#!if 넘어옴5 != null
, ''''''{{{#!if 넘어옴6 == null
{{{#!if 넘어옴5[넘어옴5.length - 1] >= 0xAC00 && 넘어옴5[넘어옴5.length - 1] <= 0xD7A3
{{{#!if ((넘어옴5[넘어옴5.length - 1] - 0xAC00) % 28) == 0
는}}}{{{#!if ((넘어옴5[넘어옴5.length - 1] - 0xAC00) % 28) != 0
은}}}}}}{{{#!if 넘어옴5[넘어옴5.length - 1] < 0xAC00 || 넘어옴5[넘어옴5.length - 1] > 0xD7A3
은(는)}}}}}}}}}{{{#!if 넘어옴6 != null
, ''''''{{{#!if 넘어옴7 == null
{{{#!if 넘어옴6[넘어옴6.length - 1] >= 0xAC00 && 넘어옴6[넘어옴6.length - 1] <= 0xD7A3
{{{#!if ((넘어옴6[넘어옴6.length - 1] - 0xAC00) % 28) == 0
는}}}{{{#!if ((넘어옴6[넘어옴6.length - 1] - 0xAC00) % 28) != 0
은}}}}}}{{{#!if 넘어옴6[넘어옴6.length - 1] < 0xAC00 || 넘어옴6[넘어옴6.length - 1] > 0xD7A3
은(는)}}}}}}}}}{{{#!if 넘어옴7 != null
, ''''''{{{#!if 넘어옴8 == null
{{{#!if 넘어옴7[넘어옴7.length - 1] >= 0xAC00 && 넘어옴7[넘어옴7.length - 1] <= 0xD7A3
{{{#!if ((넘어옴7[넘어옴7.length - 1] - 0xAC00) % 28) == 0
는}}}{{{#!if ((넘어옴7[넘어옴7.length - 1] - 0xAC00) % 28) != 0
은}}}}}}{{{#!if 넘어옴7[넘어옴7.length - 1] < 0xAC00 || 넘어옴7[넘어옴7.length - 1] > 0xD7A3
은(는)}}}}}}}}}{{{#!if 넘어옴8 != null
, ''''''{{{#!if 넘어옴9 == null
{{{#!if 넘어옴8[넘어옴8.length - 1] >= 0xAC00 && 넘어옴8[넘어옴8.length - 1] <= 0xD7A3
{{{#!if ((넘어옴8[넘어옴8.length - 1] - 0xAC00) % 28) == 0
는}}}{{{#!if ((넘어옴8[넘어옴8.length - 1] - 0xAC00) % 28) != 0
은}}}}}}{{{#!if 넘어옴8[넘어옴8.length - 1] < 0xAC00 || 넘어옴8[넘어옴8.length - 1] > 0xD7A3
은(는)}}}}}}}}}{{{#!if 넘어옴9 != null
, ''''''{{{#!if 넘어옴10 == null
{{{#!if 넘어옴9[넘어옴9.length - 1] >= 0xAC00 && 넘어옴9[넘어옴9.length - 1] <= 0xD7A3
{{{#!if ((넘어옴9[넘어옴9.length - 1] - 0xAC00) % 28) == 0
는}}}{{{#!if ((넘어옴9[넘어옴9.length - 1] - 0xAC00) % 28) != 0
은}}}}}}{{{#!if 넘어옴9[넘어옴9.length - 1] < 0xAC00 || 넘어옴9[넘어옴9.length - 1] > 0xD7A3
은(는)}}}}}}}}}{{{#!if 넘어옴10 != null
, ''''''{{{#!if 넘어옴10[넘어옴10.length - 1] >= 0xAC00 && 넘어옴10[넘어옴10.length - 1] <= 0xD7A3
{{{#!if ((넘어옴10[넘어옴10.length - 1] - 0xAC00) % 28) == 0
는}}}{{{#!if ((넘어옴10[넘어옴10.length - 1] - 0xAC00) % 28) != 0
은}}}}}}{{{#!if 넘어옴10[넘어옴10.length - 1] < 0xAC00 || 넘어옴10[넘어옴10.length - 1] > 0xD7A3
은(는)}}}}}} 여기로 연결됩니다. 
#!if 설명 == null && 리스트 == null
{{{#!if 설명1 == null
다른 뜻에 대한 내용은 아래 문서를}}}{{{#!if 설명1 != null
{{{#!html 파서(巴西)}}}에 대한 내용은 [[브라질]] 문서{{{#!if (문단1 == null) == (앵커1 == null)
를}}}{{{#!if 문단1 != null & 앵커1 == null
의 [[브라질#s-|]]번 문단을}}}{{{#!if 문단1 == null & 앵커1 != null
의 [[브라질#|]] 부분을}}}}}}{{{#!if 설명2 != null
, {{{#!html }}}에 대한 내용은 [[]] 문서{{{#!if (문단2 == null) == (앵커2 == null)
를}}}{{{#!if 문단2 != null & 앵커2 == null
의 [[#s-|]]번 문단을}}}{{{#!if 문단2 == null & 앵커2 != null
의 [[#|]] 부분을}}}}}}{{{#!if 설명3 != null
, {{{#!html }}}에 대한 내용은 [[]] 문서{{{#!if (문단3 == null) == (앵커3 == null)
를}}}{{{#!if 문단3 != null & 앵커3 == null
의 [[#s-|]]번 문단을}}}{{{#!if 문단3 == null & 앵커3 != null
의 [[#|]] 부분을}}}}}}{{{#!if 설명4 != null
, {{{#!html }}}에 대한 내용은 [[]] 문서{{{#!if (문단4 == null) == (앵커4 == null)
를}}}{{{#!if 문단4 != null & 앵커4 == null
의 [[#s-|]]번 문단을}}}{{{#!if 문단4 == null & 앵커4 != null
의 [[#|]] 부분을}}}}}}{{{#!if 설명5 != null
, {{{#!html }}}에 대한 내용은 [[]] 문서{{{#!if (문단5 == null) == (앵커5 == null)
를}}}{{{#!if 문단5 != null & 앵커5 == null
의 [[#s-|]]번 문단을}}}{{{#!if 문단5 == null & 앵커5 != null
의 [[#|]] 부분을}}}}}}{{{#!if 설명6 != null
, {{{#!html }}}에 대한 내용은 [[]] 문서{{{#!if (문단6 == null) == (앵커6 == null)
를}}}{{{#!if 문단6 != null & 앵커6 == null
의 [[#s-|]]번 문단을}}}{{{#!if 문단6 == null & 앵커6 != null
의 [[#|]] 부분을}}}}}}{{{#!if 설명7 != null
, {{{#!html }}}에 대한 내용은 [[]] 문서{{{#!if (문단7 == null) == (앵커7 == null)
를}}}{{{#!if 문단7 != null & 앵커7 == null
의 [[#s-|]]번 문단을}}}{{{#!if 문단7 == null & 앵커7 != null
의 [[#|]] 부분을}}}}}}{{{#!if 설명8 != null
, {{{#!html }}}에 대한 내용은 [[]] 문서{{{#!if (문단8 == null) == (앵커8 == null)
를}}}{{{#!if 문단8 != null & 앵커8 == null
의 [[#s-|]]번 문단을}}}{{{#!if 문단8 == null & 앵커8 != null
의 [[#|]] 부분을}}}}}}{{{#!if 설명9 != null
, {{{#!html }}}에 대한 내용은 [[]] 문서{{{#!if (문단9 == null) == (앵커9 == null)
를}}}{{{#!if 문단9 != null & 앵커9 == null
의 [[#s-|]]번 문단을}}}{{{#!if 문단9 == null & 앵커9 != null
의 [[#|]] 부분을}}}}}}{{{#!if 설명10 != null
, {{{#!html }}}에 대한 내용은 [[]] 문서{{{#!if (문단10 == null) == (앵커10 == null)
를}}}{{{#!if 문단10 != null & 앵커10 == null
의 [[#s-|]]번 문단을}}}{{{#!if 문단10 == null & 앵커10 != null
의 [[#|]] 부분을}}}}}}
#!if 설명 == null
{{{#!if 리스트 != null
다른 뜻에 대한 내용은 아래 문서를}}} 참고하십시오.

#!if 리스트 != null
{{{#!if 문서명1 != null
 * {{{#!if 설명1 != null
파서(巴西): }}}[[브라질]] {{{#!if 문단1 != null & 앵커1 == null
문서의 [[브라질#s-|]]번 문단}}}{{{#!if 문단1 == null & 앵커1 != null
문서의 [[브라질#|]] 부분}}}}}}{{{#!if 문서명2 != null
 * {{{#!if 설명2 != null
: }}}[[]] {{{#!if 문단2 != null & 앵커2 == null
문서의 [[#s-|]]번 문단}}}{{{#!if 문단2 == null & 앵커2 != null
문서의 [[#|]] 부분}}}}}}{{{#!if 문서명3 != null
 * {{{#!if 설명3 != null
: }}}[[]] {{{#!if 문단3 != null & 앵커3 == null
문서의 [[#s-|]]번 문단}}}{{{#!if 문단3 == null & 앵커3 != null
문서의 [[#|]] 부분}}}}}}{{{#!if 문서명4 != null
 * {{{#!if 설명4 != null
: }}}[[]] {{{#!if 문단4 != null & 앵커4 == null
문서의 [[#s-|]]번 문단}}}{{{#!if 문단4 == null & 앵커4 != null
문서의 [[#|]] 부분}}}}}}{{{#!if 문서명5 != null
 * {{{#!if 설명5 != null
: }}}[[]] {{{#!if 문단5 != null & 앵커5 == null
문서의 [[#s-|]]번 문단}}}{{{#!if 문단5 == null & 앵커5 != null
문서의 [[#|]] 부분}}}}}}{{{#!if 문서명6 != null
 * {{{#!if 설명6 != null
: }}}[[]] {{{#!if 문단6 != null & 앵커6 == null
문서의 [[#s-|]]번 문단}}}{{{#!if 문단6 == null & 앵커6 != null
문서의 [[#|]] 부분}}}}}}{{{#!if 문서명7 != null
 * {{{#!if 설명7 != null
: }}}[[]] {{{#!if 문단7 != null & 앵커7 == null
문서의 [[#s-|]]번 문단}}}{{{#!if 문단7 == null & 앵커7 != null
문서의 [[#|]] 부분}}}}}}{{{#!if 문서명8 != null
 * {{{#!if 설명8 != null
: }}}[[]] {{{#!if 문단8 != null & 앵커8 == null
문서의 [[#s-|]]번 문단}}}{{{#!if 문단8 == null & 앵커8 != null
문서의 [[#|]] 부분}}}}}}{{{#!if 문서명9 != null
 * {{{#!if 설명9 != null
: }}}[[]] {{{#!if 문단9 != null & 앵커9 == null
문서의 [[#s-|]]번 문단}}}{{{#!if 문단9 == null & 앵커9 != null
문서의 [[#|]] 부분}}}}}}{{{#!if 문서명10 != null
 * {{{#!if 설명10 != null
: }}}[[]] {{{#!if 문단10 != null & 앵커10 == null
문서의 [[#s-|]]번 문단}}}{{{#!if 문단10 == null & 앵커10 != null
문서의 [[#|]] 부분}}}}}}

[[이론 컴퓨터 과학|'''이론 컴퓨터 과학
{{{#!wiki style="display: inline-block; font-family:Times New Roman, serif;font-style:italic"
]]
{{{#!wiki style="margin: 0 -10px -5px; min-height: calc(1.5em + 5px)"
{{{#!folding [ 펼치기 · 접기 ]
{{{#!wiki style="margin: -5px -1px -11px"
<colbgcolor=#a36,#a36> 이론
기본 대상 수학기초론{수리논리학(논리 연산) · 계산 가능성 이론 · 범주론 · 집합론} · 이산수학(그래프 이론) · 수치해석학 · 확률론통계학 · 선형대수학
다루는 대상과 주요 토픽
계산 가능성 이론 재귀함수 · 튜링 머신 · 람다대수 · 처치-튜링 명제 · 바쁜 비버 · 디지털 물리학
오토마타 이론 FSM · 푸시다운 · 튜링 머신(폰노이만 구조) · 정규 표현식 · 콘웨이의 생명 게임 · 형식언어
계산 복잡도 이론 점근 표기법 · 튜링 기계^고전, 양자, 비결정론적, 병렬 임의접근 기계^ · 알고리즘 · 자료구조 · 알고리즘 패러다임(그리디 알고리즘, 동적 계획법)
정보이론 정보 엔트로피 · 데이터 압축(무손실 압축 포맷 · 손실 압축 포맷) · 채널 코딩(채널 용량) · 알고리즘 정보 이론(AIT) · 양자정보과학
프로그래밍 언어론 프로그래밍 언어(함수형 언어 · 객체 지향 프로그래밍 · 증명보조기) · 메타프로그래밍 · 람다 대수 · 타입 이론 · 프로그래밍 언어 의미론 · 어휘 분석 · 파싱 · 구문 트리(완전 구문 트리 · 추상 구문 트리) · 컴파일러 이론
주요 알고리즘 및 자료구조
기초 정렬 알고리즘 · 순서도 · 탐색 알고리즘
추상적 자료형 및 구현 배열^벡터^ · 리스트^연결 리스트^ · 셋(set) · 트리^이진 트리(레드-블랙 트리, ), B-트리, 피보나치 힙^ · · 스택
수학적 최적화 <keepall> 조합 최적화 외판원 순회 문제 · 담금질 기법 · 유전 알고리즘 · 기계학습
<keepall> 볼록 최적화 내부점 방법 · 경사하강법
<keepall> 선형계획법 심플렉스법
계산 수론 및 암호학 밀러-라빈 소수판별법 · Pollard-rho 알고리즘 · 쇼어 알고리즘 · LLL 알고리즘 · 해시(MD5 · 암호화폐 · 사전 공격(레인보우 테이블) · SHA) · 양자 암호 · 난수생성
<keepall> 대칭키 암호화 방식 블록 암호 알고리즘(파이스텔 네트워크 · DES · AES · ARIA · LEA · Camellia) · 스트림 암호 알고리즘(RC4)
<keepall> 공개키 암호화 방식 공개키 암호 알고리즘(타원 곡선 암호 · RSA) · 신원 기반 암호 알고리즘(SM9)
계산기하학 볼록 껍질 · 들로네 삼각분할 및 보로노이 도형^Fortune의 line-sweeping 알고리즘^ · 범위 탐색^vp-tree, R-tree^ · k-NN
그래프 이론 탐색^BFS, DFS, 다익스트라 알고리즘, A* 알고리즘^ · 에드몬드-카프 · 크루스칼 알고리즘 · 위상 정렬 · 네트워크 이론
정리
정지 문제대각선 논법 · 암달의 법칙 · P-NP 문제미해결 · 콜라츠 추측미해결
틀:이산수학 · 틀:수학기초론 · 틀:컴퓨터공학 }}}}}}}}}

[[컴퓨터공학|'''컴퓨터 과학 및 공학
{{{#!wiki style="font-family: Times New Roman, serif; display: inline;"
]]
{{{#!wiki style="margin: 0 -10px -5px; min-height:calc(1.5em + 5px)"
{{{#!folding [ 펼치기 · 접기 ]
{{{#!wiki style="margin: -5px -1px -11px"
<bgcolor=#1282d7,#1282d7> 기반 학문 수학(해석학 · 이산수학 · 수리논리학 · 선형대수학 · 미적분학 · 미분방정식 · 대수학(환론 · 범주론) · 정수론) · 이론 컴퓨터 과학 · 암호학 · 전자공학 · 언어학(음운론 · 형태론 · 통사론 · 의미론 · 화용론) · 인지과학
하드웨어 SoC · CPU · GPU(그래픽 카드 · GPGPU) · ROM · RAM · SSD · HDD · 참조: 틀:컴퓨터 부품
기술 기계어 · 어셈블리어 · 바이오스 · 절차적 프로그래밍 · 객체 지향 프로그래밍 · 함수형 프로그래밍 · 해킹 · ROT13 · 일회용 비밀번호 · 사물인터넷 · 와이파이 · GPS · 임베디드 · 인공신경망 · OpenGL · EXIF · 마이크로아키텍처 · ACPI · UEFI · LinuxBoot · gRPC · 리버스 엔지니어링 · HCI · UI · UX · 대역폭 · DBMS · NoSQL · 해시(SHA · 브루트 포스 · 레인보우 테이블 · salt · 암호화폐) · RSA 암호화 · 하드웨어 가속
연구 및 기타 논리 회로(보수기 · 가산기 · 논리 연산 · 불 대수 · 카르노 맵 · 플립플롭) · 정보이론 · 임베디드 시스템 · 운영체제(멀티태스킹 · 프로세스 스케줄링 · 데드락 · 식사하는 철학자 문제 · 뮤텍스 · 세마포어 · 인터럽트) · 데이터베이스 · 컴퓨터 언어 · 프로그래밍 언어{컴파일러(어셈블러 · JIT) · 인터프리터 · 유형 이론 · 어휘 분석 · 파싱 · 링커 · 난해한 프로그래밍 언어} · 마크업 언어 · 메타데이터 · 기계학습 · 빅데이터 · 폰노이만 구조 · 양자컴퓨터 · 행위자 모델 · 인코딩(유니코드 · MBCS) · 네트워크(네트워크 포트) · 컴퓨터 보안 · OCR · 슈퍼컴퓨터 · 튜링 머신 · FPGA · 딥러닝 · 컴퓨터 구조론 · 컴퓨터 비전 · 컴퓨터 그래픽스 · 인공지능 · 시간 복잡도(최적화) · 소프트웨어 개발 방법론 · 디자인 패턴 · 정보처리이론 · 재귀 이론 · 자연어 처리(기계 번역 · 음성인식) · 버전 (버전 관리 시스템) · 난수생성 · 놀람 최소화 원칙 · 프레임워크 · 라이브러리 · 모듈 · API · ABI · 이진 탐색
}}}}}}}}} ||
1. 개요2. 과정
2.1. 어휘 분석(lexing)2.2. 구문 분석(parsing)
2.2.1. 예시
2.3. 파스 트리(parse tree)
3. 모호성(ambiguity)
3.1. 모호성 해결 방법
4. 파싱 방식
4.1. 하향식 파서(Top-down Parser)4.2. 상향식 파서(Bottom-up Parser)
5. 관련 문서

1. 개요

parsing, 구문 분석

형식 언어 또는 컴퓨터 언어로 짠 코드를 실행하거나, 프로그램으로 변환시키기 위해서는 어휘 분석(lexing) 또는 토큰화(tokenize)를 통해 키워드, 식별자(identifier), 연산자(operator) 및 리터럴(literal) 같은 개별 토큰으로 변환한다. 이후 이 코드가 프로그래밍 언어의 문법에 맞는지 확인하는 과정을 파싱(parsing)이라고 한다.

2. 과정

파일:HowToCheckSyntax.png
이러한 처리 부분을 컴파일러에서 front-end라고 하며, AST로 변환 후 back-end 부분에서 semantics에 대해 바로 해석을 수행하는 경우 인터프리터, 추가 분석, 최적화 및 다른 언어로의 변환을 수행하게 되면 컴파일러라고 한다.

2.1. 어휘 분석(lexing)

코드 문자열을 어휘 단위로 쪼개어 토큰화를 수행하는 과정이다. 어휘 분석기로 진행되며, 정규 표현식유한 상태 기계를 통해 검사한다. 예를 들어 다음 코드 같은 경우
#!syntax cpp
int x = 2 + 3;
int y = x - 5;

아래와 같이 토큰화 될 수 있다.
TYPE_INT IDENT("x") OP_EQ INT(2) OP_ADD INT(3) SEMICOLON
TYPE_INT IDENT("y") OP_EQ IDENT("x") OP_MIN INT(5) SEMICOLON
파일:상세 내용 아이콘.svg   자세한 내용은 어휘 분석 문서
#!if (문단 == null) == (앵커 == null)
를
#!if 문단 != null & 앵커 == null
의 [[어휘 분석#s-|]]번 문단을
#!if 문단 == null & 앵커 != null
의 [[어휘 분석#|]] 부분을
참고하십시오.

2.2. 구문 분석(parsing)

어휘 분석기에서 생성된 토큰들이 문법 규칙에 맞게 배열 되어있는지를 확인하고 그 구조를 파스 트리(parse tree)로 구성하는 과정이다. 이때 언어 규칙을 정의할 때 배커스-나우르 표기법(BNF)으로 기술하며, 이런 형식으로 표현되는 문법을 문맥 자유 문법(Context Free Grammar)라고 한다. 앞으로 서술할 내용은 BNF를 안다는 전제로 작성된다.

분석 과정을 간략히 적자면, 파서는 <숫자> + <숫자> 같은 토큰 뭉치를 보고, 언어 규칙 목록에서 <숫자> + <숫자> 꼴이 있는지를 확인한다. 예를 들어 <수식> ::= <숫자> + <숫자>라는 규칙을 발견하면, 이 토큰 뭉치를 <수식>이라는 더 큰 개념으로 바꿔버린다. 이렇게 규칙의 오른쪽(RHS)을 왼쪽(LHS)으로 바꾸는 걸 '축약(Reduction)'이라고 한다.

이 축약 과정을 계속 반복해서, 입력한 문자열이 시작 심볼 하나로 딱 줄어들면, 그 문자열은 '문법적으로 올바르다'고 결정된다. 이 상태를 '문자열 s가 문법 G가 정의하는 언어 L(G)에 속한다. ([math(s \in L(G))])'라고 한다.

2.2.1. 예시

아래 문법에 대해 문자열 [math(1+2*3)]이 있다고 하자. 표기에 대한 자세한 설명은 배커스-나우르 표기법 참조.
#!syntax java
<expr> ::= <term> | <expr> '+' <term> // 시작 non-terminal
<term> ::= <factor> | <term> '*' <factor>
<factor> ::= <number>
<number> ::= <digit> | <digit> <number>
<digit> ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
\

문자열 [math(1+2*3)]에 대해 해당 문법을 기반으로 파싱하면 다음과 같이 될 것이다. 굵은 글씨는 non-terminal, 일반 텍스트는 terminal 노드다. 간략화를 위해 수를 <digit>에서 <number>로 변환하는 부분은 생략한다.
[math(
\begin{array}{c|l}
1 + 2 * 3 &\Rightarrow_P 1 + 2 * \textbf{number} \\
&\Rightarrow_P 1 + 2 * \textbf{factor} \\
&\Rightarrow_P 1 + \textbf{number} * \textbf{factor} \\
&\Rightarrow_P 1 + \textbf{factor} * \textbf{factor} \\
&\Rightarrow_P 1 + \textbf{term} * \textbf{factor} \\
&\Rightarrow_P 1 + \textbf{term} \\
&\Rightarrow_P \textbf{number} + \, \textbf{term} \\
&\Rightarrow_P \textbf{factor} + \, \textbf{term} \\
&\Rightarrow_P \textbf{term} + \, \textbf{term} \\
&\Rightarrow_P \textbf{expr} + \textbf{term} \\
&\Rightarrow_P \textbf{expr}
\end{array}
)]

2.3. 파스 트리(parse tree)

파일:상세 내용 아이콘.svg   자세한 내용은 구문 트리 문서
#!if (문단 == null) == (앵커 == null)
를
#!if 문단 != null & 앵커 == null
의 [[구문 트리#s-|]]번 문단을
#!if 문단 == null & 앵커 != null
의 [[구문 트리#완전 구문 트리|완전 구문 트리]] 부분을
참고하십시오.
파일:parse_tree_1.png
위는 파싱 예시를 기반으로 한 parse tree로, 문자열의 유도 과정을 나타내는 트리다. 루트 노드는 시작 non-terminal이며, 내부 노드 역시 non-terminal로 이루어진다. 단말 노드만이 문자열에 직접 나오는 terminal로 구성된다.

파스 트리를 루트에서 단말 노드까지 아래 방향으로 읽으면 문법 규칙에 따라 문자열을 생성하는 유도(derivation) 과정이 된다. 반대로 단말 노드에서 루트 방향까지 읽으면, 주어진 토큰들을 상위의 non-terminal로 변환하는 파싱(parsing) 과정이 된다.

3. 모호성(ambiguity)

아래 문법에 대해
#!syntax java
<expr> ::= <expr> '+' <expr> | <expr> '-' <expr> | <number> // 시작 non-terminal
<number> ::= <digit> | <digit> <number> // <number>는 예시 부분과 동일

문자열 [math(3 - 2 + 1)]을 유도한다고 하자. 위의 BNF를 기반으로 좌측 유도(Leftmost derivation)와 우측 유도(Rightmost derivation)을 수행하면 아래와 같이 다른 형태의 파스 트리가 구성되는 것을 확인할 수 있다.
좌측 유도 파스 트리
[math(
\begin{array}{c|l}
\textbf{expr} & \Rightarrow_D \textbf{expr} - \textbf{expr} \\
& \Rightarrow_D \textbf{number} - \textbf{expr} \\
& \Rightarrow_D3 - \textbf{expr} \\
& \Rightarrow_D 3 - \textbf{expr + expr}\\
& \Rightarrow_D 3 - \textbf{number} + \textbf{expr}\\
& \Rightarrow_D 3 - 2+\textbf{expr} \\
& \Rightarrow_D 3 - 2+\textbf{number} \\
& \Rightarrow_D 3 - 2+1 \\
\end{array})]
파일:leftmost_parse.png
우측 유도 파스 트리
[math(
\begin{array}{c|l}
\textbf{expr} & \Rightarrow_D \textbf{expr} + \textbf{expr} \\
& \Rightarrow_D \textbf{expr} + \textbf{number} \\
& \Rightarrow_D \textbf{expr} + 1 \\
& \Rightarrow_D \textbf{expr} - \textbf{expr} + 1 \\
& \Rightarrow_D \textbf{expr} - \textbf{number} + 1 \\
& \Rightarrow_D \textbf{expr} - 2 + 1 \\
& \Rightarrow_D \textbf{number} - 2 + 1 \\
& \Rightarrow_D 3 - 2 + 1 \\
\end{array}
)]
파일:rightmost_parsepng.png

위와 같이 어떤 문법 [math(G)]에 대해 특정 문장이 2개 이상의 서로 다른 파스 트리를 가지면 문법 [math(G)]는 모호하다(ambiguous)고 한다.

3.1. 모호성 해결 방법

연산자의 우선순위와 결합 법칙을 기반으로 파스 트리가 모호하지 않게 수정할 수 있다. <term> ::= <number> '**' <term> | <number> // 제곱 연산은 우측 결합이므로 right recursion 적용
<number> ::= <digit> | <digit> <number> // <number>는 예시 부분과 동일
}}}
위 수정된 문법에 대해 문자열 [math(3-2+1)]을 파스 트리로 구성하면, [math(\textbf{expr} \Rightarrow_D \textbf{expr} +\textbf{term})]으로 시작하는 경우만 해당 문자열로 유도되며 [math(\textbf{expr} \Rightarrow_D \textbf{expr} - \textbf{term})]으로 시작하는 경우는 유도되지 않는다. 식 [math(1+2 \text{ ** } 3)]도 이전 방법은 [math((1+2)\text{ ** }3)], [math(1+(2 \text{ ** } 3))] 두 가지로 파스 트리가 구성될 수 있었지만 위와 같이 결합 법칙을 기반으로 수정하면 모호성이 해결된다.

====# 예제 1 #====

C언어의 포인터와 증가 연산자(++)에 대한 문법을 생각해보자.
#!syntax java
<expr> ::= <expr> '++'
       | '++' <expr>
       | '*' <expr>
       | <expr> '+' <expr>
       | id

이 문법에 대해 *p++라는 표현식은 (*p)++인지 *(p++)인지에 따라 결과가 완전히 달라진다.[2] 아래의 우선순위를 가지며 문법이 모호하지 않도록 문법을 재작성해보자.
  • 후위 증가 연산자(id++)가 가장 높은 우선순위를 갖는다.
  • 전위 증가 연산자(++id)와 역참조 연산자(*)는 후위 연산자보다 낮고, 이항 연산자 +보다는 높은 우선순위를 갖는다.
  • 전위 증가 연산자와 역참조 연산자들은 서로 같은 우선순위 레벨에 있으며, 우측결합한다.
  • 이항 연산자 +는 가장 낮은 우선순위를 가지며 좌측결합한다.

[풀이]
----
  • 연산자 우선 순위는 (후위 증가 연산자 > 전위 증가 연산자 = 역참조 연산자 > 이항 연산자)다.
  • 좌측 결합하는 연산자는 후위 증가 연산자, 이항 연산자, 나머지는 우측 결합한다.
이 연산자 우선 순위와 결합 방향을 정리하면 다음과 같이 나온다.
#!syntax java
<expr>        ::= <expr> '+' <unary_expr> | <unary_expr>
<unary_expr>  ::= '++' <unary_expr> | '*' <unary_expr> | <postfix_expr>
<postfix_expr>::= <postfix_expr> '++' | id

====# 예제 2 #====

이 문법은 문자열 if E1 then if E2 then S1 else S2 에 대해
  • if E1 then (if E2 then S1 else S2)
  • if E1 then (if E2 then S1) else S2
두 가지로 해석될 수 있어서 모호하다.[3]

#!syntax java
<stmt> ::= 'if' <expr> 'then' <stmt>
         | 'if' <expr> 'then' <stmt> 'else' <stmt>

이 문법을 수정해서 else가 가장 가까운 then과만 짝이 되어 유도되도록 해보자. 즉 if E1 then (if E2 then S1 else S2)으로만 유도되도록 해야 한다.

[풀이]
----
우선 if-then-else로 짝을 이루는 문장을 'matched statement', if-then으로 끝나는 문장을 else랑 매칭이 안 된 'unmatched statement'라고 하자. 이 두 statement에 대해 논터미널을 정의해서 문법을 다음과 같이 만들면 된다.
#!syntax java
<stmt>          ::= <matched_stmt> | <unmatched_stmt>
<matched_stmt>  ::= 'if' <expr> 'then' <matched_stmt> 'else' <matched_stmt>
<unmatched_stmt>::= 'if' <expr> 'then' <stmt>
                |   'if' <expr> 'then' <matched_stmt> 'else' <unmatched_stmt>

if 다음에 then이 오고, 그 뒤에는 반드시 <matched_stmt>만 올 수 있도록 강제하였다. if E1 then if E2 then S1 else S2 같은 문장은 if E1 then (if E2 then S1 else S2) 로만 해석될 수 있다. 안쪽의 if E2 then S1 else S2는 이미 else 절을 포함하여 완벽한 matched statement이기 때문이다.

이렇게 되면, if...then...else... 형태의 문장이 되려면, then 절에 들어가는 내용물 역시 else에 대한 모호함 없이 완전하게 된다. 만약 if E1 then ... 에서 then 뒤에 if E2 then S1 같은 짝 없는 문장이 온다면, 그건 if E1 then의 else를 잡아먹을 수 있는 가능성이 생길 것이다.

4. 파싱 방식

Top-down
파일:topdown-intro-1.jpg
Bottom-up
파일:bottomup-intro-0.jpg
파서의 구조는 크게 하향식(Top-down) 방식과 상향식(Bottom-up) 방식으로 나눌 수 있다. 상향식은 루트 노드에서부터 leaf 노드를 생성해나가는 방식이다. 좌측 유도 순서의 생성 규칙을 적용한다.

하향식은 leaf 노드들로부터 루트 노드 쪽으로 위로 생성해나가는 방식이다. 우측 유도의 역순의 생성규칙을 적용한다. 유도 자체는 우측부터 하지만 입력 문자열은 왼쪽부터 진행해 나가기 때문이다.

4.1. 하향식 파서(Top-down Parser)

파일:상세 내용 아이콘.svg   자세한 내용은 파싱/하향식 문서
#!if (문단 == null) == (앵커 == null)
를
#!if 문단 != null & 앵커 == null
의 [[파싱/하향식#s-|]]번 문단을
#!if 문단 == null & 앵커 != null
의 [[파싱/하향식#|]] 부분을
참고하십시오.

4.2. 상향식 파서(Bottom-up Parser)

5. 관련 문서


[1] 예를 들어 괄호, 세미콜론 등[2] 결과에 대한 내용은 해당 코드의 출력 참조[3] 이 문제를 흔히 'dangling else'라고 한다.