← 목록
기타 2026-07-07 8KB 읽기 7분

high2rpn.sh 고도화 — 결함 3종 해소 (2026-07-07/08)

개요

/Users/ef/CrownyOS/crownyc/tools/high2rpn.sh(고수준 한선씨 → RPN 한선씨 배치 변환기)가 "패턴별 라인 치환기" 수준이라 무인 배치 변환 신뢰도가 낮다는 감사 지적에 따라, 3가지 결함을 해소하고 회귀 테스트 스위트를 신설했다.

무엇을 했는지

결함(a) — 함수 선실행 사고 방지 (가드 자동삽입)

  • convert_file()이 파일에 함수 정의가 있고 원본에 @본문 가드가 없으면,
모든 함수 블록을 파일 앞부분으로 모아 @본문 점프 / .본문으로 감싼다.
  • 원본에 @본문이미 있으면 재배치를 하지 않고 원래 줄 순서를 그대로
보존한다 — 처음 구현에서 "가드 유무와 무관하게 항상 함수블록을 앞으로 재배치"했더니, 사용자가 이미 배치해 둔 @본문 점프가 함수 뒤로 밀려나 함수가 프로그램 시작과 동시에 폴스루 실행되고, 이후 정상 호출까지 스택이 오염돼 VM 무한루프로 이어지는 실측 버그를 냈다(테스트로 적발 → 수정: has_guard=1이면 원본 순서 그대로 단일 스트림 처리).

결함(b) — 중첩 호출식 → 임시변수 경유 후위형 변환

  • resolve_calls(): 정규식으로 가장 안쪽 호출부터 찾아 임시변수(_tN)에
대입하는 줄을 만들고, 식 안의 호출부를 임시변수 이름으로 치환. 더 이상 호출 패턴이 없을 때까지 반복.
  • call_nesting_depth(): 문자열 스캔으로 "호출 괄호"의 최대 중첩 깊이를 셈
(그룹핑 괄호는 제외). 깊이 2(출력값(등급(85))류, 과제 예시)까지 지원, 3 이상은 "조용한 통과" 대신 [경고] 중첩 호출식 2단계 이상 미지원을 stderr+주석(; [경고-미변환])으로 명시하고 원문을 보존.
  • 사용자 정의 함수는 사전스캔(scan_user_funcs)으로 감지해 실용 RPN 규약대로
인자 @이름 호출 형태로, 내장 호출은 인자 이름(예: 출력값보여줘 매핑) 형태로 방출. 출력값은 값을 반환하지 않는 void 내장으로 특별 처리(임시변수로 감싸면 안 됨 — 감싸면 보여줘 이후 빈 스택을 다시 pop하려다 깨짐).
  • 부수적으로, 순수 산술/비교/논리 중위식을 실제로 후위형으로 변환하는
shunting-yard(to_postfix)를 새로 구현했다. 기존 convert_exprecho "$expr"로 그대로 통과시키는 스텁이었고 — 이는 "단순 산술" 조차 실제로는 변환되지 않고 있었다는 뜻이라(x+1 → RPN에서 "+"는 미인식 단어) — 결함(c) 컴파일 게이트가 요구하는 "변환됨=컴파일 보장" 기준을 만족하려면 이 부분의 실질 구현이 선행조건이었다.

결함(c) — 변환 직후 자동 컴파일 게이트

  • compile_gate(): 산출 .rpn.한선hanseonc_rpn으로 즉시 컴파일해
(1) exit 비0, (2) stderr에 "미인식 단어" 포함, (3) TOAU 산출 0바이트 중 하나라도 해당하면 실패로 판정하고 사유를 출력한다(기존엔 exit만 보고 "미인식 단어" 경고가 있어도 성공으로 오판했다 — 실측: + 같은 미지원 연산자가 있어도 컴파일러가 exit 0을 반환하면서 결과값만 조용히 틀리는 사례를 확인).
  • 단일 파일(default/--sample)과 --batch 모두에 적용. --batch는 기존에
컴파일 실패도 "PARTIAL"이라며 success로 집계하던 버그를 고쳐 성공/실패를 정확히 집계하고, 실패가 하나라도 있으면 배치 전체가 exit 1을 반환한다.

bash 3.2 함정 (실측, 이 작업 중 적발 — 향후 참고)

이 스크립트는 shebang이 /bin/bash라 macOS 기본 bash 3.2로 실행된다(brew bash 5가 PATH에 있어도 shebang 절대경로가 우선). 3.2에는 없는 기능들:

  1. 음수 배열 인덱스 ${arr[-1]} 미지원(4.2+) → ${arr[$((${#arr[@]}-1))]}로 대체.
  2. 연관배열 declare -A 미지원(4.0+) → 안 씀(사용자함수 목록도 인덱스 배열 선형탐색).
  3. "${arr[@]}"을 빈 배열에 set -u로 순회하면 "unbound variable" 에러
→ 항상 if [[ ${#arr[@]} -gt 0 ]]; then for x in "${arr[@]}"; do ...로 가드.
  1. "${var/"$pat"/"$rep"}"처럼 패턴·치환 둘 다 따옴표로 감싸면 결과에
리터럴 큰따옴표가 섞여 들어가는 버그(실측 최초 적발) → 치환문은 따옴표 없이 "${var/"$pat"/$rep}".
  1. [[ "$t" =~ ^함수[[:space:]]+([^([:space:]]+)\( ]]처럼 정규식을
[[ ]] 안에 인라인하면 파싱 에러(unbalanced paren으로 셸 파서가 혼동) → local re='...'; [[ "$t" =~ $re ]]로 변수 경유.

그 외 실측 발견(범위 밖이나 중요)

  • 문자열 리터럴 안의 "=" 오인식 버그(사전 존재, 이번에 컴파일 게이트가
처음 실측 적발): 출력값("gcd(48,18)=" + ...)처럼 문자열 안에 "="이 있으면 옛 변수/재대입 정규식이 그 "="을 대입 연산자로 오인해 줄 전체를 엉뚱하게 잘랐다. top_level_eq_pos()(문자열 밖 "=" 위치 스캔, "==" 등 비교연산자 제외)로 교체해 해결.
  • 배열 인덱싱(arr[i])과 배열 리터럴([1,2,3])은 이번 작업 범위 밖
기존에도 미지원이었고(RPN사용법.md 배열 함정 문서화됨), 이번에도 convert_expr[ 포함 식을 안전하게 원문 통과시킨다(오변환 대신 컴파일 게이트가 명확히 실패로 표시).

검증 결과

  • 신규 회귀 테스트: /Users/ef/CrownyOS/crownyc/tools/high2rpn-test.sh
14개 케이스(단순산술/변수재대입/조건3단/동안루프/함수정의호출/중첩호출/ 가드자동삽입 구조+값/가드기존존재 값+비중복/컴파일게이트 실패/비교연산/ 문자열출력) 전부 PASS.
  • 기존 산출물 재변환 비교(/Users/ef/CrownyOS/crownyc/pkg/libs/):
  • 최대공약수.한선: 기존 수기 .rpn.한선은 호출식·복합식이 애초에
  • 컴파일 불가능한 형태였다. 새 도구는 루프/함수/산술을 정확히 변환하고, 3단계 중첩(출력값(문자열변환(최대공약수(...))))이 있는 3줄만 명시적으로 "미변환" 경고 후 컴파일 게이트 실패로 정직하게 보고 — 조용한 오변환보다 개선.
  • 버블정렬.한선: 배열 인덱싱 위주라 범위 밖(기존과 동일하게 미지원),
  • 무한루프 없이 8초 내 정상 종료, 게이트가 정확히 실패 보고.
  • 양심지표.한선(614줄, 실측 이력 파일): 8초 내 완주(이전 버전의
  • 가드 재배치 버그였다면 무한루프 위험), 배열 인덱싱·3단계 중첩 다수로 게이트 실패하지만 크래시/행 없음.

    관련 파일

    • /Users/ef/CrownyOS/crownyc/tools/high2rpn.sh — 본체(수정)
    • /Users/ef/CrownyOS/crownyc/tools/high2rpn-test.sh — 회귀 테스트(신규)
    • /Users/ef/CrownyOS/crownyc/tools/high2rpn.sh.bak-20260707 — 이전 세션이
    남긴 백업(건드리지 않음)

    잔여 이슈

    • 배열 인덱싱(arr[i])/배열 리터럴([1,2,3]) 변환은 여전히 범위 밖 —
    다음 고도화 대상 후보.
    • 2단계 이상 중첩 호출식(예: 출력값(문자열변환(f(x))))은 의도적으로
    미지원(명시적 경고) — 필요시 재귀적 다단계 지원으로 확장 가능하나 이번 과제 범위는 "1단계 중첩부터"로 한정됨.
    • MUL 좌항/우항 문자 타입경고는 VM/컴파일러 쪽의 기존 표시성 이슈로
    실제 값(payload)은 정상 — memory feedback_learnsh_... 계열과 유사하게 기지식화된 항목, 이번 작업에서 재확인만 함.