어떤 프로세스에서 구문 오류가 발생합니까? (토큰 화 또는 파싱)


23

총 이미지를 파악하는 단계적으로 컴파일과 해석을 이해하려고합니다. 그래서 http://www.cs.man.ac.uk/~pjj/farrell/comp3.html 이 기사 를 읽는 동안 질문을했습니다 .

그것은 말한다 :

컴파일러의 다음 단계를 파서라고합니다. 컴파일러의이 부분은 언어의 문법을 이해합니다. 구문 오류를 식별하고 오류가없는 프로그램을 다른 언어로 해석하거나 작성할 수있는 내부 데이터 구조로 변환합니다.

그러나 토크 나이저가 구문 오류가있는 주어진 스트림을 올바르게 토큰 화하는 방법을 알 수 없었습니다.

거기에 붙어 있거나 파서에 잘못된 정보를 제공해야합니다. 토큰 화도 일종의 번역가가 아닙니까?

토큰 화하는 동안 어휘 손상된 코드 줄을 극복하는 방법.

위의 링크에는 토큰 화기 제목 의 토큰 예가 있습니다 .

내가 이해하는 것처럼 토큰의 형태는 코드 토큰에 문제가 있으면 손상 될 수 있습니다.

내 오해를 분명히 해 주시겠습니까?

답변:


32

토크 나이 저는 단지 파서 최적화입니다. 토크 나이저없이 파서를 구현할 수 있습니다.

토크 나이저 (또는 렉서 또는 스캐너)는 입력을 토큰 목록으로 잘라냅니다. 문자열의 일부 (주석, 공백)는 일반적으로 무시됩니다. 각 토큰에는 유형 (언어에서이 문자열의 의미)과 값 (토큰을 구성하는 문자열)이 있습니다. 예를 들어, PHP 소스 스 니펫

$a + $b

토큰으로 나타낼 수 있습니다

Variable('$a'),
Plus('+'),
Variable('$b')

토크 나이 저는이 상황에서 토큰이 가능한지 고려하지 않습니다. 예를 들어, 입력

$a $b + +

행복하게 토큰 스트림을 생성합니다

Variable('$a'),
Variable('$b'),
Plus('+'),
Plus('+')

그런 다음 파서가 이러한 토큰을 사용하면 두 변수가 서로 뒤따를 수없고 두 개의 중위 연산자도 둘 수 없습니다. (다른 언어는 그러한 토큰 스트림이 합법적이지만 PHP에서는 합법적이지 않은 다른 구문을 가지고 있습니다.

토큰 화기 단계에서 파서는 여전히 실패 할 수 있습니다. 예를 들어, 잘못된 문자가있을 수 있습니다.

$a × ½ — 3

PHP 토크 나이 저는이 입력을 규칙과 일치시킬 수 없으며 기본 구문 분석이 시작되기 전에 오류를 생성합니다.

보다 공식적으로, 토큰 화기는 각 토큰이 일반 언어 로 설명 될 수있을 때 사용됩니다 . 그런 다음 토큰을 DFA로 구현하여 매우 효율적으로 일치시킬 수 있습니다. 반대로 기본 문법은 일반적으로 컨텍스트가 없으며 LALR과 같이 더 복잡하고 성능이 낮은 구문 분석 알고리즘이 필요합니다.


따라서 우리는 토크 나이저를 파서의 일부로 생각할 수 있으며 구문 오류는 구문 오류 형식에 따라 토큰 화 단계 또는 구문 분석 단계에서 발생할 수 있습니다. 설명해 주셔서 감사합니다.
FZE

4
@ FZE : 당신 그렇게 생각할 있지만 오도합니다. Lexing은 "단지 파서 최적화"가 아닙니다. 오히려, 렉싱 (lexing)은 물리적 표현 (일부 문자 시퀀스)을 논리적 표현 (해당 문자로 표현되는 토큰)으로 매핑합니다. 이 줄의 끝이 표시되는 방법과 같은 사소한에서 파서를 분리, 또는 당신은 논리와 같은 표현하기로 결정 여부 and또는 &&다른 사람이나 뭐. (주로) 파싱과는 별개이며 다릅니다. 최적화 (있는 경우)는 거의 우연한 부작용입니다.
Jerry Coffin

@JerryCoffin 더 자세한 설명에 감사드립니다.
FZE

2
@ JerryCoffin, amon은 기본이 아닌 차이점입니다. "렉서"및 "파서"부분을 모두 다루는 응집성 BNF 문법을 만들 수 있습니다. 우리는 일반적으로 규칙을 낮은 수준 (예 : 숫자, 덧셈 연산자)과 높은 수준 (요약)으로 분류하지만 문법 자체는 그러한 구분을하지 않습니다.
Paul Draper

1
@PaulDraper 일반 언어를 첫 단계로 분리하는 것이 올바른 선택인지 확실하지 않습니다. 예를 들어, 일부 언어에서 문자열 리터럴을 설명하려면 일치하는 쌍 (정규 아님)이 필요할 수 있지만 여전히 첫 번째 단계에서 문자열 리터럴을 처리하는 것이 좋습니다. 역 추적을 피하거나 최소화하는 것이 더 나은 지침 인 것 같습니다.
코드 InChaos

16

당신은 것입니다 일반적으로 대부분의 구문 오류는 파서가 아니라 렉서에서 올 것으로 기대합니다.

어휘 분석기는 입력에 토큰화할 수없는 것이 있으면 오류를 발생시킵니다. 그러나 많은 언어에서 거의 모든 문자 시퀀스가 ​​일종의 토큰으로 바뀔 수 있으므로 여기서 오류는 매우 드문 경우입니다.

입력에 유효한 토큰이 포함되어 있으면 구문 분석기가 오류를 생성하지만 해당 토큰이 배열되지 않아 대상 언어로 유효한 명령문 / 표현을 구성합니다. 이것은 일반적으로 훨씬 일반적입니다.


11

토큰 화기는 문자 스트림을 토큰으로 분리합니다. 토크 나이저 POV에서 이것은 완전히 유효합니다.

1 * * 1

와 같은로 변환 : ["1", MULTIPLY, MULTIPLY, "1"] 만 파서는 표현을 거부 할 수 있습니다 - 그것은 또 다른 곱셈 연산자를 따라 갈 수 없어 곱셈 연산자를 알고있다. 예를 들어 JavaScript에서 다음을 생성합니다.

Uncaught SyntaxError: Unexpected token *(…)

토크 나이저가 감지 할 수있는 오류가 있습니다. 예를 들어, 완료되지 않은 문자열 리터럴 : "abc또는 유효하지 않은 숫자 : 0x0abcdefg. 그래도 여전히 구문 오류로보고 될 수 있습니다.

Uncaught SyntaxError: Unexpected token ILLEGAL

그러나 토큰은 인식되지 않았으며로보고됩니다 ILLEGAL.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.