Skip to content

제안 - 아희 2015 #8

@youknowone

Description

@youknowone

제안: 아희2015

아희의 표준을 보다 명확하게 정리하고 창제 원리에 맞게 기능 추가 및 미정의 부분 보완을 제안합니다. 아희의 원 표준은 http://aheui.github.io/specification.ko/ 를 참고해 주세요.

#제안-보완으로 표시된 부분은 기존의 표준에서 정의되지 않았던 부분입니다. #제안-추가는 기존의 표준과 달라지는 부분입니다. 아무 것도 표시되지 않은 부분은 기존의 표준과 동일한 내용을 재정의한 부분입니다.

개요

인터프리터가 아희를 실행하는 방법은 befunge와 비슷합니다. 즉, 코드 공간 안에 커서가 있어서 커서가 위치한 곳에 적혀 있는 명령을 수행하고, 또 그 명령에 따라 커서가 움직이는 것입니다. 하지만, 그 코드가 ASCII가 아니라 한글이라는 점이 다릅니다.

한글은 홀소리와 닿소리로 나눌 수 있습니다. 홀소리는 커서가 이동할 방향을 지정하고, 닿소리는 인터프리터가 수행할 명령을 지정합니다. 받침이 있는 글자는 닿소리가 두 개가 되는데, 이 때 받침은 명령을 보조하는 인자로 작용합니다.

아희에서 쓰이는 저장 공간은 여러 개가 있습니다. 대부분이 스택이고, 큐가 하나 있습니다. 그리고 확장기능과 소통하는 통로가 있는데 2015표준에서는 정의하지 않습니다. 집어넣기(push)로 인수를 전달하고 뽑아내기(pop)로 결과를 받아옵니다.

코드

  • 아희의 코드는 UTF-8로 표현된 유니코드 문자로만 이루어진 텍스트입니다.
  • 아희의 코드에는 어떤 utf-8 문자도 올 수 있으나, 프로그램의 진행에는 오직 유니코드 한글 낱자 영역(16진수 코드 포인트 AC00-D7A3, hangul syllable 영역)의 문자만 영향을 끼칩니다.
    • 완전하지 않은 낱자인 ㄱ, ㄷ, ㅑ, ㅓ 등은 무시합니다. 이런 기능을 사용하고 싶다면 기능이 없는 닿소리나 기능이 없는 홀소리를 조합해 쓸 수 있습니다.
    • 첫가끝 코드 등의 다른 방식으로 표현된 한글도 무시합니다.
  • 아희의 코드는 줄바꿈에 민감합니다. 줄바꿈 문자는 Line feed 문자인 유니코드 0A 또는 흔히 '\n'로 가리키는 문자를 사용합니다. 단 그 앞에 Carriage return 문자인 유니코드 0D 또느 흔히 '\r'로 가리키는 문자가 있는 경우 두 문자를 합쳐서 줄바꿈으로 다룹니다. (#제안-보완)
  • 코드는 닿소리부터 실행하고 홀소리에 따라서 움직입니다. 하지만 닿소리가 홀소리의 동작을 재정의할 경우에는 진행방향을 먼저 결정한 후, 실제로 이동하기는 전에 재정의가 이루어집니다.
    1. 닿소리를 먼저 실행합니다. 이때 진행방향 재정의가 있다면 재정의를 예약합니다.
    2. 홀소리에 따라 이동 방향을 결정합니다.
    3. 예약된 진행방향 재정의가 있다면 이동 방향을 변경합니다.
    4. 이동 방향에 따라 이동합니다.

커서 - 홀소리

  • 아희는 코드를 매 유니코드 문자 하나를 격자 단위로 하는 평면으로 해석합니다.
  • 커서를 옮기는 데는 한글 문자의 홀소리에만 영향을 받습니다. 각 홀소리의 동작은 아래의 정리를 참고합니다.
  • 커서의 진행에는 관성이 있습니다. 홀소리가 아무 일도 하지 않으면 이전의 이동 방향과 크기를 유지하려는 성질이 있습니다.
  • 프로그램이 시작할 때 커서는 1행 1열에 있고 아래 방향으로 한 칸 진행하려는 상태입니다.
    • 이는 가상의 0행 1열에 '우' 문자가 있어 아래로 한 칸 이동해 온 것과 같은 상태로 해석할 수 있습니다.
    • 이는 기본 방향이 오른쪽인 funge와는 다른 점입니다. 이렇게 함으로서 코드 맨 윗줄에 #!을 추가로 넣더라도 문제없이 동작할 수 있습니다.
  • 커서가 코드 공간의 한 쪽 끝에 다다르면 커서는 반대편 끝으로 이동합니다.
    • 반대편 끝은 코드 텍스트에서 진행방향 반대편에 존재하는 첫 문자를 가리킵니다. 첫 문자는 줄바꿈 문자를 제외한 어떤 문자도 될 수 있습니다. (#제안-추가)
      • 진행 방향이 오른쪽인 경우 진행 방향의 끝은 그 행의 마지막 문자이고 반대편 끝은 그 행의 첫 문자입니다.
      • 진행 방향이 왼쪽인 경우 진행 방향은 그 행의 첫 문자이고 반대편 끝은 그 행의 마지막 문자입니다.
      • 진행 방향이 아래인 경우 진행 방향의 끝은 그 열에서 가장 마지막으로 나타나는 줄이고 반대편 끝은 첫 줄입니다.
      • 진행 방향이 위인 경우 진행 방향의 끝은 첫 줄이고 반대편 끝은 그 열에서 가장 마지막으로 나타나는 줄입니다.
      • 진행 방향이 오른쪽 위인 경우 진행 방향의 끝은 첫 줄이고 반대편 끝은 출발점에서 진행 방향의 끝까지 그은 연장선 중 첫 열을 지나는 점입니다.
      • 진행 방향이 왼쪽 아래인 경우 진행 방향의 끝은 첫 열이고 반대편 끝은 출발점에서 진행 방향의 끝까지 그은 연장선 중 첫 행을 지나는 점입니다.
      • 코드 공간 사이에 코드가 없는 빈 공간은 한글 영역 밖의 임의의 문자로 간주하여 관성에 따라서만 움직입니다.
    • 한 번에 두 칸씩 이동하는 홀소리를 만나면 먼저 두 칸을 이동한 뒤 코드 공간의 끝임을 확인하고 반대편 끝으로 이동합니다. 즉 코드 공간의 끝에서 두 칸을 이동하더라도 반드시 반대편 끝으로 도착합니다. (#제안-보완)
  • 연산에 필요한 충분한 갯수의 값이 저장공간에 저장되어 있지 않은 경우, 커서는 그 명령을 실행하지 않고 진행해야 할 방향의 반대방향으로 같은 크기만큼 움직입니다. (#제안-보완)
    • 종료만 제외하고, 중복과 바꿔치기 명령을 포함한 모든 뽑아내기를 쓰는 명령에 해당합니다.
  • 따라서 각 이동성분 속력의 합은 최소 1, 최대 2입니다. 커서는 정지하거나 두 칸을 초과하는 속도로 이동할 수 없습니다.

각 홀소리의 기능은 다음과 같습니다.

  • ㅏ, ㅓ, ㅗ, ㅜ: 커서를 각각 오른쪽, 왼쪽, 위, 아래로 한 칸 옮깁니다.
  • ㅑ, ㅕ, ㅛ, ㅠ: 커서를 각각 오른쪽, 왼쪽, 위, 아래로 두 칸 옮깁니다.
  • ㅡ: 커서의 가로 이동 성분은 유지하고, 세로 이동 성분은 반대로 뒤집어 이동합니다.
  • ㅣ: 커서의 세로 이동 성분은 유지하고, 가로 이동 성분은 반대로 뒤집어 이동합니다.
  • ㅢ: 커서의 진행 방향을 뒤집어 이동합니다.
  • ㅘ - 오른쪽으로 한칸 이동 후 위로 한칸 옮깁니다. 커서 관성은 오른쪽과 위쪽 이동이 모두 보존됩니다. 첫 이동 후 코드 공간 끝에 다다를 경우 먼저 반대편 끝으로 이동 후 다음 이동을 합니다. (#제안-추가)
  • ㅝ - 왼쪽으로 한칸 이동 후 아래로 한칸 옮깁니다. 커서 관성은 왼쪽과 아래쪽 이동이 모두 보존됩니다. 첫 이동 후 코드 공간 끝에 다다를 경우 먼저 반대편 끝으로 이동 후 다음 이동을 합니다. (#제안-추가)
  • ㅚ - 커서의 세로 이동을 ㅗ와 같이 바꾸고, 가로 이동 성분에 대해서는 ㅣ와 같이 반대로 뒤집어 이동하되 원래 두 칸이라면 한 칸만 이동합니다. (#제안-추가)
  • ㅟ - 커서의 세로 이동을 ㅜ와 같이 바꾸고, 가로 이동 성분에 대해서는 ㅣ와 같이 반대로 뒤집어 이동하되 원래 두 칸이라면 한 칸만 이동합니다. (#제안-추가)
  • 기능 없음: ㅐ ㅔ ㅒ ㅖ ㅙ ㅞ (#제안-추가)

명령어 - 닿소리

각 닿소리의 기능은 다음과 같습니다.

ㅇ 묶음 - 받침은 모두 무시합니다.

  • ㅇ은 없음 명령으로 아무 일도 하지 않습니다.
  • ㅎ은 끝냄 명령으로 커서의 실행을 끝냅니다. 이 때 현재 선택된 저장 공간에 값이 하나 이상 남아 있으면 ㅁ 명령으로 뽑아낼 수 있는 값을 뽑아내 운영체제에 돌려 줍니다. 저장 공간이 비어 있으면 0을 돌려줍니다.
    • 저장 공간이 비어 있더라도 커서의 실행은 끝냅니다. 반대 방향으로 이동하지 않습니다.

ㄷ 묶음 - 셈. 받침은 모두 무시합니다.

  • ㄷ은 덧셈 명령으로 저장공간에서 두 값을 뽑아낸 다음 둘을 더한 값을 저장공간에 집어넣습니다.
  • ㄸ은 곱셈 명령으로 저장공간에서 두 값을 뽑아낸 다음 둘을 곱한 값을 저장공간에 집어넣습니다.
  • ㅌ은 뺄셈 명령으로 저장공간에서 두 값을 뽑아낸 다음 나중 값에서 먼저 값을 뺀 값을 저장공간에 집어넣습니다.
  • ㄴ은 나눗셈 명령으로 저장공간에서 두 값을 뽑아낸 다음 나중 값에서 먼저 값을 나눈 값을 저장공간에 집어넣습니다.
  • ㄹ은 나머지 명령으로 저장공간에서 두 값을 뽑아낸 다음 나중 값에서 먼저 값을 나눈 나머지를 저장공간에 집어넣습니다.

ㅁ 묶음 - 저장공간

  • ㅁ은 뽑기 명령입니다. 지금 저장공간이 스택이라면 맨 위의 값, 큐라면 맨 앞의 값을 뽑아냅니다.(pop)
    • ㅇ 받침이 오면 뽑아낸 값을 표준 출력에 음수의 경우 부호 -를 포함해 0-9 사이의 문자만을 사용해 10진수로 출력합니다.
    • ㅎ 받침이 오면 표준 출력에 뽑아낸 값에 해당하는 코드포인트의 유니코드 문자를 utf-8로 출력합니다.
    • ㅎ 받침에서 유니코드 코드 포인트가 아닌 값을 출력하려 하면 저장공간에서 값을 뽑지 않은 채 진행 방향을 반대로 바꿉니다. (#제안-추가)
    • 다른 받침이 오면 뽑아낸 값을 버립니다.
  • ㅂ은 집어넣기 명령입니다. 지금 저장공간이 스택이라면 맨 위에, 큐라면 맨 뒤에 값을 집어넣습니다.(push)
    • ㅇ 받침이 오면 표준 입력에서 정수 문자열을 받아 이에 해당하는 값을 지금 저장공간에 집어넣습니다.
    • ㅎ 받침이 오면 표준 입력에서 utf-8로 유니코드 문자를 받아 이에 해당하는 유니코드 코드포인트를 지금 저장공간에 집어넣습니다.
    • ㅎ 받침이 왔지만 utf-8로 해석할 수 없는 문자가 입력될 경우 1바이트를 소비하고 진행방향을 뒤집습니다. (#제안-보완)
    • ㅇ이나 ㅎ이 아닌 받침에 대해서는 각각 상수를 저장공간에 집어넣습니다. 그 상수 값은 아래의 표를 참고합니다.
    • ㅇ에서 입력할 수 있는 숫자는 음수 부호 -가 첫 자리에 올 수 있는 0-9 사이의 숫자로만 이루어진 10진수입니다. (#제안-보완)
    • ㅇ에서 숫자가 아닌 문자를 받을 경우 16진수 코드포인트 09('\t'), 0A('\n'), 0D('\r'), 20(' ')에 해당하는 문자라면 소비시키고, 다른 문자라면 다음 입력에 쓸 수 있도록 보존합니다. 단 0D('\r')와 0A('\n')가 연달아 나타나면 둘 모두 소비시킵니다. (#제안-보완)
    • ㅇ이나 ㅎ에서 EOF를 만나 더이상 입력을 받을 수 없는 경우 진행 방향을 뒤집습니다. (#제안-추가)
  • ㅃ은 중복 명령입니다. 지금 저장공간이 스택이라면 맨 위의 값을 그 값 위에 하나 더 집어넣고, 큐라면 맨 앞의 값을 앞에 하나 더 덧붙입니다.
  • ㅍ은 바꿔치기 명령입니다. 지금 저장공간이 스택이라면 맨 위 값과 그 바로 아래 값을, 큐라면 맨 앞의 값과 그 바로 뒤 값을 바꿉니다.

ㅂ의 경우 ㅇ, ㅎ 외의 나머지 받침이 있으면 그 받침을 구성하는 직선의 수와 원의 수의 합에 따른 값을 집어넣습니다. 받침이 없으면 0을 집어넣습니다.

2 2 3 5 4 4 2 3 4 3 4 4
4 4 5 5 7 9 9 7 9 9 8 6 4

받침 중에는 1획인 것이 없는데, 1은 2/2나 3-2 같은 셈으로 간단하게 만들 수 있습니다. 예: 반밧나, 밪반타 등.

ㅅ 묶음 - 제어, 저장공간 확장

  • ㅅ은 선택 명령으로 저장공간을 선택합니다. 어느 것을 선택하는지는 받침을 따르는데, 이에 대한 설명은 아래를 참고하세요.
  • ㅆ은 이동 명령으로 지금의 저장공간에서 값 하나를 뽑아내 받침이 나타내는 저장공간에 그 값을 집어 넣습니다.
  • ㅈ은 비교 명령으로 저장공간에서 값 두 개를 뽑아 내서 비교합니다. 나중에 뽑아낸 값이 더 크거나 같으면 1을, 아니면 0을 지금 저장공간에 집어넣습니다.
  • ㅊ은 조건 명령으로 저장공간에서 값 하나를 뽑아내서 그 값이 0이 아니면 진행해야 할 방향대로, 0이면 그 반대 방향으로 갑니다.

저장공간

  • 아희에는 총 28개의 저장공간이 있습니다.
  • 저장공간은 스택, 큐, 통로 세 가지 종류가 있습니다.
  • 스택이 26개, 큐가 1개, 통로가 1개 이며 각각의 저장공간에는 이름이 붙어 있어 그 중 스택은 (받침 없음), ㄱ, ㄴ, ㄷ, ㄹ, ㅁ, ㅂ, ㅅ, ㅈ, ㅊ, ㅋ, ㅌ, ㅍ, ㄲ, ㄳ, ㄵ, ㄶ, ㄺ, ㄻ, ㄼ, ㄽ, ㄾ, ㄿ, ㅀ, ㅄ, ㅆ가 있고, ㅇ은 큐이며, ㅎ은 확장 기능과 소통하기 위한 통로입니다.
  • 각 저장공간은 ㅅ나 ㅆ 명령에서 받침으로 선택할 수 있습니다.
  • 처음에 선택되어 있는 저장공간은 (받침 없음) 스택입니다.
    • (“사” 와 같은 명령으로 다시 선택할 수 있습니다.)
  • 저장공간에는 정수만 담을 수 있으며 정수는 부호를 지원합니다. (#제안-보완)
  • 저장공간은 최소한 32비트의 부호 있는 정수를 지원해야합니다. (#제안-보완)
    • 구현체에 따라 그 이상의 큰 정수를 지원할 수 있습니다.
  • 저장공간에 넣을 수 있는 값의 수는 무한합니다. (#제안-보완)

예제

다음은 “Hello, world!”를 출력하는 프로그램입니다.

밤밣따빠밣밟따뿌
빠맣파빨받밤뚜뭏
돋밬탕빠맣붏두붇
볻뫃박발뚷투뭏붖
뫃도뫃희멓뭏뭏붘
뫃봌토범더벌뿌뚜
뽑뽀멓멓더벓뻐뚠
뽀덩벐멓뻐덕더벅

더 많은 코드는 github.com/aheui/snippets를 참고하세요.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions