needmoreeasy EN 한국어
배우기

46 — 컴파일러: 표현식 언어

★★★★☆ (4/5)컴파일러
선수 지식
28 — 첫 컴파일러, 29 — 부트스트랩
결과물
2 + 3 * 4를 연산자 우선순위에 맞게 계산하는 아주 작은 계산기

가이드 2829은 줄을 나누고 번역했습니다. 진짜 컴파일러는 식도 계산해야 하는데, 첫 규칙은 우선순위 — 2 + 3 * 4에서 곱셈이 먼저 일어납니다.

단계

  1. 줄을 숫자와 연산자의 혼합 목록으로 바꿉니다 — 2 + 3 * 4의 토큰 목록은 [2, "+", 3, "*", 4]입니다:

    line = "2 + 3 * 4"
    값들 = []
    for 단어 in line.split():
        if 단어 in ["*", "+", "-"]:
            값들.append(단어)
        else:
            값들.append(int(단어))
    
    실행해 보기 →
  2. 왼쪽부터 읽으면 (2 + 3) * 4 = 20이지만, 곱셈이 더 세게 묶여 2 + (3 * 4) = 14가 정답입니다. 해결책은 목록을 두 번 지나가는 것 — 곱셈통과 먼저, 그다음 덧셈통과. 계산기를 expr.ko.nme으로 저장합니다:

    # expr.ko.nme — 2 + 3 * 4 같은 식 계산기.
    # 실행: nme 실행 expr.ko
    
    def 곱셈통과(값들):
        i = 0
        while i < len(값들):
            if 값들[i] == "*":
                값들[i - 1 : i + 2] = [값들[i - 1] * 값들[i + 1]]
                i = i - 1
            i = i + 1
        return 값들
    
    def 덧셈통과(값들):
        i = 0
        while i < len(값들):
            if 값들[i] == "+":
                값들[i - 1 : i + 2] = [값들[i - 1] + 값들[i + 1]]
                i = i - 1
            elif 값들[i] == "-":
                값들[i - 1 : i + 2] = [값들[i - 1] - 값들[i + 1]]
                i = i - 1
            i = i + 1
        return 값들
    
    def 계산(line):
        값들 = []
        for 단어 in line.split():
            if 단어 in ["*", "+", "-"]:
                값들.append(단어)
            else:
                값들.append(int(단어))
        값들 = 곱셈통과(값들)
        값들 = 덧셈통과(값들)
        return 값들[0]
    
    말해 "식 계산기 — 2 + 3 * 4, 또는 quit"
    while True:
        물어봐 line, "> "
        if line == "quit":
            말해 "안녕!"
            break
        if line == "":
            continue
        답 = 계산(line)
        말해 f"{line} = {답}"
    
    실행해 보기 →

    슬라이스 값들[i - 1 : i + 2] = [결과]a, *, b 세 칸을 그 곱으로 바꿔 목록을 [14] 하나로 접습니다.

  3. 파이프로 식을 넣어 실행합니다:

    printf '2 + 3 * 4\n10 - 2 * 3\n2 * 3 + 4\n1 + 2 + 3\n5 * 2 - 3\nquit\n' | nme 실행 expr.ko
    
    식 계산기 — 2 + 3 * 4, 또는 quit
    > 2 + 3 * 4 = 14
    > 10 - 2 * 3 = 4
    > 2 * 3 + 4 = 10
    > 1 + 2 + 3 = 6
    > 5 * 2 - 3 = 7
    > 안녕!
    

    2 + 3 * 420이 아니라 14 — 곱셈 통과가 먼저 실행됐습니다.

직접 해보기

첫 번째 통과에 나눗셈을 더해 보세요 — 계산에서 "/"를 받고 곱셈통과elif 값들[i] == "/": 가지를 //로 만들어 10 - 8 / 26이 되게 합니다.

배운 것

  • line.split()이 식을 단어로 만들고, 숫자와 연산자가 하나의 혼합 목록이 됩니다.
  • *+보다 세게 묶여 2 + 3 * 420이 아니라 14입니다.
  • 곱셈통과가 먼저 *를 접고, 덧셈통과가 그다음 더하고 뺍니다.
  • 목록을 두 번 지나가는 것이 표현식 파서의 씨앗입니다.

GitHub에서 이 문서 보기