# 컴파일러
깊게 다루지는 않았고 이론적으로만 참고하였다.
# Syntax 용어
# 프로그램 코드 (code)
문장의 집합
- 토큰들로 구성된 문자열들의 집합
# 식 / 표현식 (Expression)
1 이상의 피연산자(상수, 변수 등) 들이 연산자와 결합되어 그 계산 결과를 반환하는 식
- 프로그램 내에서 값을 만들어냄
# 문장 (Statement / Expression Statement)
표현식 등으로 구성되며, 그 결과에 따라 컴퓨터에 명령을 내리게 됨
# Syntactic Sugar
코드를 더 읽기 좋게 표현하는 대체 문법
# 컴파일러의 구조
# 컴파일러 compiler
프로그램 (프로그래밍 언어:코드) -> 컴퓨터에서 실행
must to
코드 -번역(컴파일러)
-> 기계어
# 컴파일러의 구조
언어 분석 과정 요약
- 소스 프로그램
- Lexical Analyzer (어휘 분석 : 토큰 분리)
- Syntactic Analyzer (구문 분석 : 구문 트리 생성)
- Type Checker (의미 분석 : 타입 검사)
- Code Optimizer (코드 최적화)
- Code Generator (코드 생성)
- 기계 코드
# 어휘 분석 Lexical Analysis (Scanning)
어휘 분석기 (Lexical Analyze, Lexer)
원시 프로그램을 읽어들여, 정규 문법에 따라 토큰 이라는 의미있는 문법 단위로 분류하는것.
- 토큰들을 생성하는것
예시
- 문자열
value
<id, 1>
토큰으로 사상되는 어휘항목- 토큰 이름(식별자):
id
- 속성값:
1
, 심볼 테이블 내에서 해당 토큰의 위치 - 토큰의 이름이나 속성값은 컴파일러 설계자에 따라 달라질 수 있다.
- 문자열
=
<assign, NULL>
토큰으로 사상되는 어휘항목- 토큰 이름:
assign
:=
연산자를 가리키는 추상 기호 - 속성값:
NULL
심볼 테이블에 입력될 필요가 없음
- 어휘 분석기가 위의 코드를 모두 토큰으로 사상하면 생성되는 토큰 스트림
어휘항목과 토큰의 정의와 구분이 사이트마다 모호한 경우가 있다. TODO
# 어휘항목 (lexeme)
- 어휘분석에서, 가장 낮은 단위로써 논리적으로 구분가능한(의미있는) 조각
- 어휘분석기는 어휘항목을 검출하여 토큰을 생성한다.
- 예약어, 식별자, 리터럴(문자열, 숫자), 특수기호, 키워드 등
# 패턴 (Pattern)
토큰이 어휘항목을 서술하는 규칙으로써, 정규 문법에 따라 표현된다.
# 토큰 (Token)
- 데이터쌍 구조
<토큰이름, 속성값>
- 각 토큰은 토큰의 패턴에 부합하는 어휘항목을 갖는다.
- 어휘 항목들을 구분할 수 있는 요소들
# 식별자 (Identifier)
프로그램 안에서는, 구성요소 간에 구별/식별성을 주는 이름
- 변수명, 상수명, 레이블명, 부프로그램명(함수명), 메서드명, 클래스명 등
- 주로 사용자/프로그래머가 정하는 이름
# 키워드/핵심어 (keyword)
프로그램의 구성단위를 강조한 용어
# 예약어 (reserved word)
의미가 고정되어서, 프로그램 도중에 그 의미가 변경될 수 없음
대부분 키워드/예약어가 같은 의미이나, 드물게 예약어 이지만 키워드가 아닐 수 있음
- 언어 표준에서 예약어로써 정하기만 했고, 키워드가 되기에는 아직 그 내용/기능이 구체적으로 정해지지 않은 경우
프로그래밍 언어에서는, 미리 정의되는 언어 구성자를 2가지로 구분
- 재정의 불가능 식별자 : 예약어
- 재정의 가능 식별자 : 미리 정의되지만 다르게 재정의 가능한 식별자
# 어휘 오류 검출
어휘 오류
소스 코드상에서 정의되지 않은 어휘항목이 발견되었을 때 발생하는 오류
명칭 검증 : 변수명 앞에 숫자가 올 수 없음 등의 변수명 검증 처리
식별자, 예약어 판단, 대소문자 구분, 줄바꿈 등
어휘 분석기가 독립적으로 어휘오류를 검출하는 것은 매우 어렵거나 많은 비용이 소모된다.
if2 (var === 5)
if2
를if
가 잘못 입력된 것인가?if2
라는 함수를 호출하는 구문인가?
위 판단은 심볼테이블을 참조해야 가능하다.
따라서 어휘 분석기는 심볼테이블을 생성하고, 구문분석기가 어휘 오류를 검출하는 것이 더욱 일반적이다.
# 구문 분석 / 파싱 (Syntax Analysis / Parsing)
구문분석기 / 파서 (Syntax Analyzer / Parse)
구문 문법을 적용하여 분석을 수행하는 것 주로 표현식, 문장 등 큰 단위들을 처리함
- 구문적으로 올바르다는 것을 보증
- 정형화된 형식 (구문 트리) 으로 변환함
# 구문 트리 Syntax Tree / 파스 트리 Parse Tree
- 소스 코드(문장)의 문법 구조를 그대로 트리 형식으로 옮겨놓은 구조
- 노드: 어휘 분석기에서 생성한 토큰들
- 표현: 토큰 간의 우선순위 / 토큰 간의 결합 관계
# 점검 : 문법 준수 여부
- 토큰 간의 관계를 서술함
- 구문 구조가 문법 규칙에 맞는지 여부를 따짐
# 출력 : 구문 트리 생성
- 어휘 분석으로 생성된 토큰을 입력하여
- 구조화된 구문트리를 생성하는 후처리
통상, 구문 분석이 끝나면 (구문 트리가 생성되면)
- 컴파일러에서는 그 내부에서만 사용하는 중간 코드 (Intermediate Code) 를 생성한다.
- 중간 코드를 생성하는 이유는 여러 종류의 프로그래밍 언어에 대응하기 위함이다.
# 파서의 종류
보편적(universal), 하향식(top-down), 상향식(bottom-up)
# 보편적 파싱방법
- 어떠한 문법도 파싱할 수 있지만 파싱과정이 매우 비효율적이므로 상용 컴파일러에는 적용될 수 없다.
예시: 2 + 3 - 1
# 하향식 파서
- 구문의 상위 구조로부터 일치하는 부분을 찾기 시작한다.
2 + 3
->2 + 3 - 1
# 상향식 파서
주로 컴파일러에서 이용되는 파서
구문의 낮은 수준에서 점차 높은 수준으로 일치하는 부분을 찾는다.
입력 값이 규칙에 맞을 때까지 찾아서 맞는 입력 값을 규칙으로 바꾼다. 부분적으로 일치하는 표현식은 파서 스택에 쌓인다.
입력 값의 처음을 가리키는 포인터가 오른쪽으로 이동
# 의미 분석 Semantic Analysis
- 지역변수 / 전역변수 구별
- 변수 선언 - 참조 연결
- 타입 검사 (Type Checking)
- 피연산자가 연산자에 부합하는지 검사함
- 의미적으로 올바르지 않은 코드의 유무 검사
- 정수와 문자열의 덧셈, 값을 0 으로 나누는 행동 등
구문 트리와 심볼 테이블에 있는 정보를 이용하여 소스 코드가 언어 정의에 의미적으로 부합하는지 검사함
구문 트리를 중심으로 의미를 부여하여, 코드 생성이 가능하게 함.
- 구문 트리를 사용하여 실행가능한 중간 코드를 생성하는 것
# 코드 생성 Code Generation
의미 분석을 통해 분석된 소스코드를 목표 기계에 맞는 어셈블리어나 기계어로 변환하는 단계
# BNF 표기법, EBNF 표기법
# 문맥 종속 문법 Context Dependent Grammar : 자연어
- 한국어, 영어, 독어, 일본어
# 문맥 무관 문법 Context Independent Grammar : 형식 언어
- 문법과 의미의 분리
- 프로그래밍 언어들에서, 일반적인(공통적인) 특성들을 더욱 추상화시킨 언어
- 대개의 프로그래밍 Context-free Language 의 구조
- 충분히 단순한 구조를 유지 -> 기계의 효율적인 번역
- 특정 언어의 구문을 명확하게/엄격하게 기술하는 표기법
# 문맥 자유 문법의 용도
- 프로그래밍 언어의 구문 문법, 통신 프로토콜 동작에 대한 구문 문법
# 문맥 자유 문법의 표기법
- BNF, EBNF, 구문도표(Syntax Diagram) 등
# 문맥 자유 문법의 구성
- 비단말 기호 : 정의할 대상
- 단말 기호 : 해당 언어에서 직접 사용되는 표현
- 시작 비단말 기호 : 언어에서 독립적으로 사용되는 단위
- 각 규칙, 하나의 비단말 기호(정의할 대상)의 정의
- 단말 기호(표현)와 비단말 기호의 조합
# BNF 표기법 Backus-Naur Form
프로그래밍 언어의 구문을 서술할 수 있는 표기법
- John Backus 가 Peter Naur 의 도움으로 개발
- 1963년, ALGOL 60 언어 구문을 기술할 때 처음으로 사용
- 이후에, Ada, Pascal, C, Java 등 대부분의 프로그래밍 언어의 구문에 대한 표기법으로 사용
- 규칙
Symbol ::= Expression
(심볼 ::= 표현식)
- 메타 기호
::=
⇒ 정의를 뜻함 (좌변을 우변으로써 정의함)|
⇒ 선택/택일(or)을 뜻함< >
⇒ 비단말 기호를 뜻함
# EBNF 표기법 Extended Backus-Naur Form
원래의 BNF 에 추가적인 메타 기호 등을 사용하고 확장한 표기법으로 많은 변종이 있음
Small_Alphabet ::= [a-z]
Number ::= [0-9]
# ABNF 표기법 Augmented Back-Naur Form
표준화된 확장 BNF 표기법
# 중간 정리
여기까지 가볍게 읽어 보았으면 다음 내용을 이해해 보자
어휘
(token) 는 보통 정규 표현식으로 표현한다.INTEGER : 0|[1-9][0-9]* PLUS : + MINUS : -
1
2
3구문은 BNF 형식에 따라 정의한다.
expression := term operation term operation := PLUS | MINUS term := INTEGER | expression
1
2
3
문법이 문맥 자유 문법(BNF 으로 표기) 이라면 언어는 정규 파서로 파싱할 수 있다.
여기까지 HTML 파서를 이해하기 위한 조금의 궁금증 해결을 위한 공부라고 생각해보자.
# Reference
- https://d2.naver.com/helloworld/59361
- http://www.ktword.co.kr/abbr_view.php?m_temp1=3673
- http://www.ktword.co.kr/abbr_view.php?nav=&m_temp1=4859&id=871
- http://www.ktword.co.kr/abbr_view.php?nav=&m_temp1=5787&id=588
- http://www.ktword.co.kr/abbr_view.php?nav=&m_temp1=5788&id=588
- https://untitledtblog.tistory.com/9?category=670012