문제

이미 작성하는 발전기지 않지만,나는 알고 싶어 최상의 가능한 방법을 구현 off 측 규칙이 있습니다.

직후: Off 측 규칙 수단을 이 상황에서는 들여쓰기를 얻으로 인식되는 구문론적인 요소입니다.

여기에 오프사이드 규칙에 의사를 만들기 위한 토크나이저를 토대를 캡처하는 들여쓰기에서 사용 가능한 형태로,나는 원하지 않을 제한 답변 언어:

token NEWLINE
    matches r"\n\ *"
    increase line count
    pick up and store the indentation level
    remember to also record the current level of parenthesis

procedure layout tokens
    level = stack of indentation levels
    push 0 to level
    last_newline = none
    per each token
        if it is NEWLINE put it to last_newline and get next token
        if last_newline contains something
            extract new_level and parenthesis_count from last_newline
            - if newline was inside parentheses, do nothing
            - if new_level > level.top
                push new_level to level
                emit last_newline as INDENT token and clear last_newline
            - if new_level == level.top
                emit last_newline and clear last_newline
            - otherwise
                while new_level < level.top
                    pop from level
                    if new_level > level.top
                        freak out, indentation is broken.
                    emit last_newline as DEDENT token
                clear last_newline
        emit token
    while level.top != 0
        emit token as DEDENT token
        pop from level

comments are ignored before they are getting into the layouter
layouter lies between a lexer and a parser

이 layouter 를 생성하지 않는 이상 중 하나 줄 바꿈에서는 시간,그리고 생성하지 않는 줄 바꿈이 있을 때의 들여쓰기입니다.따라서 분석 규칙은 아주 간단합니다.그것의 아주 좋은 생각하지만 알려가 있다면 더 나은 방법으로 달성하는니다.

을 사용하는 동안 이에 대한하는 동안,나는 것으로 나타났는 후 DEDENTs 수 있습 니스를 방출하는 줄 바꿈 문자는 어쨌든,이 방법은 당신할 수 있는 별도의 식으로 줄 바꿈 문자를 유지하면서 들여쓰기 DEDENT 로 트레일러 표현이다.

도움이 되었습니까?

해결책

내가 쓴 토크나이저를 토대하고 파서의 약간의 들여쓰기를 중심 도메인 특정 언어에서 지난 몇 년 동안,그리고 당신이 무엇을 거기 보이는 저에게 매우 합리적,무엇을 위해 그 가치가있다.내가 틀리지 않는 경우에,당신의 방법은 매우 비슷한 파이썬은,예를 들어,들이 있는 것처럼 보이는 아름다 그것이 해야하는 일부를 수행중이다.

변환 NEWLINE NEWLINE 들여쓰기 단지 들여쓰기 전에 파서 확실히 같다 올바른 방법을 할 것들-그것은 고통이(IME)항상 앞서 엿에서 해당 파서!나는 실제적으로 수행하는 단계로 별도의 레이어에서는 이 세 가지 단계는 프로세스:첫 번째 결합된 무엇 렉 및 layouter 지 마이너스는 모든 NEWLINE 내 물건(는 아주 간단),두 번째(도 매우 간단하다)레이어 접속바꿈으로 변환 NEWLINE 들여쓰기 단지 들여쓰기(또는,실제로,콜론을 줄 바꿈을 들여쓰기를 들여쓰기 때문에,이 경우에는 모든 들여 블록 항상 앞에 콜론),다음을 파서 세 번째 단계에 있습니다.그러나 그것은 또한 감각을 많이 나에게 일을 하는 방식을 설명 하고자 하는 경우에 특히 분리하는 테스트 결과에서 layouter 는,아마도 당신하고 싶어 하는 경우에 당신은 코드를 사용하세대 도구의 렉서,예를 들어,같은 일반적인 관행입니다.

나는 하나가 있는 응용 프로그램에 필요한 좀 더 유연에 대해 들여쓰기 규칙,기본적으로 떠나는 파서 그들을 시행할 때 필요한 다음 필요한 유효한 특정 컨텍스트에서,예를 들어:

this line introduces an indented block of literal text:
    this line of the block is indented four spaces
  but this line is only indented two spaces

는 작동하지 않게 잘 들여쓰기/DEDENT 토큰 때문에,당신은 끝까지 할 필요성이 들여쓰기를 위한 각각의 열을 들여쓰기와 같은 수의 DEDENTs 에 방지 않는 한,당신을 찾는 방법은 앞서는 들여쓰기 수준을 끝나는것같이 보이지 않는 당신이 원하는 토지.이 경우에는 제가 몇 가지를 시도하고는 다른 것들과 끝난 저장하는 카운터에서 각 NEWLINE 는 토큰을 준 변경에서 들여쓰기(긍정적 또는 부정적)에 대한 다음과 같은 논리 라인.(각 토큰 또한 저장된 모든 후행 공백을 경우에는,그것은 필요한 보;에 대한 NEWLINE,저장 공백을 포함 EOL 자체,중간의 빈 줄이고 들여쓰기에 다음과 같은 논리 라인.) 별도의 들여쓰기 또는 DEDENT 토큰다.을 받고 파서를 다루는 더 작품보다 중첩 그냥 들여쓰기 및 DEDENTs 할 수 있으며,잘 되었습니다 지옥으로 복잡한 문법을 필요로하는 멋진 파서 생성기,하지만 거의 나쁜 것을 두려워했습니다.다 필요 없음에 대한 파서 앞에 줄바꿈을 볼 수 있으면의 들여쓰기에 나오는 이 체계입니다.

여전히,나는 당신이 거라고 동의하는 것을 허용하고 유지의 모든 방법을 미친 보이는 공백에서 토/layouter 시키는 파서 무엇을 결정하는 문자 그대로 무엇을 의 코드가 약간의 특이한 요구 사항!당신은 확실히 없을 원하는 파서 매 것을 들여쓰기 카운터의 경우에 당신을 분석하이,예를 들어.방법은 당신이 일을 하는 것은 거의 확실히 오른쪽에 접근 방법의 응용 프로그램 그리고 많은 다른 사람에 게.하지만 사람이 다른 사람이 생각하는 최선의 방법에 이런 종류의 물건,나는 분명히 듣고 사랑을 것입니다.

다른 팁

필자는 실험이 최근에,그리고 나왔다는 결론에 도달한 나의 필요에 적어도,내가 원하는 줄 바꿈의 끝을 표시하기 위해 각각"문"는지 여부,그것은 마지막 문에 들여쓰기를 차단하거나지 않는,즉내가 필요로바꿈하기도 전에 DEDENT.

나의 솔루션을 머리에 대바꿈의 끝을 표시하는 라인을 사용하여 라인 토큰을의 시작을 표 시하는 라인입니다.

나는 테스트 결과는 축소 빈 줄을 포함하여(주석-유선)방출 단일 라인 토큰에 대한 정보의 들여쓰기 마지막 라인입니다.그런 다음 전처리 기능 나이는 토큰 스트림을 추가 들여쓰기 또는 DEDENT"사이에서"어떤 점 들여쓰기 변경합니다.그래서

line1
    line2
    line3
line4

제 토큰트림

LINE "line1" INDENT LINE "line2" LINE "line3" DEDENT LINE "line4" EOF

이것을 작성하는 나에게 명확한 문법 제작을 위한 문을 걱정이 없는 검출 끝의 문을 때도 그들은 결국과 중첩된,subblocks,무언가를 하기 어려울 수 있습니다면 당신은 일치하는 줄 바꿈(및 DEDENTS)다.

여기에는 코어의 전처리기는,서면에서 O'Caml:

  match next_token () with
      LINE indentation ->
        if indentation > !current_indentation then
          (
            Stack.push !current_indentation indentation_stack;
            current_indentation := indentation;
            INDENT
          )
        else if indentation < !current_indentation then
          (
            let prev = Stack.pop indentation_stack in
              if indentation > prev then
                (
                  current_indentation := indentation;
                  BAD_DEDENT
                )
              else
                (
                  current_indentation := prev;
                  DEDENT
                )
          )
        else (* indentation = !current_indentation *)
          let  token = remove_next_token () in
            if next_token () = EOF then
              remove_next_token ()
            else
              token
    | _ ->
        remove_next_token ()

지 못에 대한 추가 지원 괄호는 아직,그러나 해야 하는 간단한 확장자.그것은,그러나 피하기 방출은 길 잃은 라인의 끝에서 파일입니다.

토 루비에 대한 재미있:

def tokenize(input)
  result, prev_indent, curr_indent, line = [""], 0, 0, ""
  line_started = false

  input.each_char do |char|

    case char
    when ' '
      if line_started
        # Content already started, add it.
        line << char
      else
        # No content yet, just count.
        curr_indent += 1
      end
    when "\n"
      result.last << line + "\n"
      curr_indent, line = 0, ""
      line_started = false
    else
      # Check if we are at the first non-space character.
      unless line_started
        # Insert indent and dedent tokens if indentation changed.
        if prev_indent > curr_indent
          # 2 spaces dedentation
          ((prev_indent - curr_indent) / 2).times do
            result << :DEDENT
          end
          result << ""
        elsif prev_indent < curr_indent
          result << :INDENT
          result << ""
        end

        prev_indent = curr_indent
      end

      # Mark line as started and add char to line.
      line_started = true; line << char
    end

  end

  result
end

지만 작품에 대한 두 개의 공간 들여쓰기가 있습니다.결과 같은 것 ["Hello there from level 0\n", :INDENT, "This\nis level\ntwo\n", :DEDENT, "This is level0 again\n"].

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top