(이 문서는 진행중인 작업입니다…)
참고 : "CPP"지점에는이 프로젝트의 "멍청한"포트가 C에서 C ++까지 포함되어 있습니다.
J2는 미니멀리스트 프로그래밍 언어 ( "Execeable Dictionary"의 경우 "Edict")와 C 반사/FFI 시스템을 결합한 시스템입니다. 공유 라이브러리를 쉽게 가져 와서 "접착제"코드를 작성하지 않고도 직접 데이터 유형, 변수 및 기능 (적어도 글로벌 범위의 기능)을 사용할 수 있습니다.
예를 들어, "inc.c"파일이 포함 된 경우 :
typedef struct mystruct { int i; float f; } mystruct;
extern mystruct increment(mystruct x) { x.i+=1; x.f+=1; return x; }
... 그리고 나는 그것으로 공유 된 라이브러리를 만듭니다.
gcc --shared -g inc.c -o inc.so
... 그러면 해당 공유 라이브러리를 Edict 통역사로 가져 와서 사용할 수 있습니다.
e> loadlib([inc.so]) @mylib
Finished curating module
e> mylib<mystruct! <2@i 4@f> @x increment(x)>/ stack!
VMRES_STACK
<null>
structure_type "struct mystruct"
member "i"
base_type "int" 0x3 (0x7f361c0121a0)
member "f"
base_type "float" 5 (0x7f361c0121a4)
간단 해 보이지만 여기에 커버 아래에 많은 일이 일어나고 있습니다 ...
"Edict" 포장지 또는 접착제 코드. 또는 런타임에 자체 내부에 동적 액세스를 노출시킬 수있는 C 프로그램의 반사 라이브러리로 볼 수 있습니다.
언어는 세 가지 요소의 기초를 기반으로합니다.
이 세 가지 요소는 런타임에 다목적 프로그래밍 가능한 환경으로 조립됩니다. 시스템은 다음 자체로 부트 스트랩됩니다.
Edict의 진화는 Forth, Lisp, Joy, Factor, TCL, Mathematica 등의 영향을 받았습니다.
핵심 사항 :
while (call=vm_dispatch(call)); // VM's inner loop
(참고 :이 "지그재그"구조가 매우 유사한 (그리고 사전)를 발견했습니다.
"Listree"는 Edict와 VM의 핵심 데이터 구조입니다. Listree의 인스턴스는 단순히 Listree 값으로 구성되며 여기에는 다음이 포함됩니다.
Listree 값이 다른 Listree 값에 대한 참조를 포함 할 가능성은 Listree를 "계층 적"또는 "재귀 적"데이터 구조로 만듭니다. Listree는 Edict의 핵심과 그것을 구현하는 시스템 모두에 있습니다.
*이 간단한 설명에서 명시 적은 아니지만 (의도적으로) 각 레이블은 실제로 다른 Listree 값에 대한 참조 목록 을 나타냅니다.
언급 한 바와 같이, VM은“데이터 스택”및“사전”하위 부처를 포함하여 Listree 값 내에서 모든 상태를 유지합니다.
Edict에는 두 가지 유형의 데이터 값이 있지만 두 유형의 값은 VM의 데이터 스택 또는 사전 내에 존재하는 Listree 값을 사용하여 저장됩니다.
가장 간단한 유형의 값은 "문자"입니다. 리터럴은 단지 사각형 괄호로 묘사 된 텍스트입니다.
[This is a literal]
LISP 배경에서 온다면 해석자가 리터럴을 S- 표현으로 나누는다고 생각할 수도 있지만 그렇지 않습니다. 브래킷 사이의 모든 것은 Listree 값의 "데이터 버퍼"에서 "문자 그대로"표시됩니다.
칙령 통역사는 중첩 된 사각형 괄호를 추적합니다.
[This is a [nested] literal]
"이것은 [중첩 된] 문자입니다"값을 가진 단일 문자로 해석됩니다.
문자 그대로 "" "" "" "문자"는 다음 문자를 빠져 나와 통역사가 (예 : 균형 잡힌 정사각형 괄호를 포함하는 리터럴을 만들 수 있습니다.
[This is a literal containing an unbalanced [ bracket]
통역사가 하나를 가로 질러 오면 문자 그대로 값 (또는 값에 대한 참조 - 중요한 차이)이 단순히 데이터 스택에 배치됩니다.
OTOH, 통역사는 문자가 아닌 것에 대해 조금 더 처리합니다. (리터럴이 아닌 다른 종류의 값이 있으며, 나중에 논의 할 것입니다…)
칙령 프로그래머는 스택의 값에 이름을 할당 한 후 해당 값을 해당 이름으로 언급 할 수 있습니다. 과제는 단순히 다음과 같습니다.
@mylabel
이름을 값에 할당하면 실제로 여러 가지 작업을 수행합니다.
통역사가 레이블에 대한 참조를 볼 때, 해당 참조는 해당 레이블과 관련된 값에 대한 참조로 대체됩니다.
칙령은 한 가지 중요한 방식으로 다른 언어와 다릅니다. 많은 언어는 "homoiconic", 즉 코드 및 데이터는 동일한 기본 구조를 사용하여 표시됩니다. (LISP는 동종 언어의 전통적인 예입니다.) Edict는 Homoiconic 또는 비 호소 닉이 아닙니다. 전혀 "기능"이 없습니다. 단순히 값에 적용 할 수있는 평가 연산자가 있습니다.
칙령의 기본적인 "기능과 같은"것은 다음과 같습니다.
[1@x]
( "x"라벨을 "1"값에 할당하십시오.)
그것은 단지 문자 그대로입니다 .
이를 호출 하려면 평가 연산자 가 사용됩니다.
[1@x]!
이것의 결과는 통역사가 다음을 직접 읽은 것과 정확히 동일합니다.
1@x
모든 평가 연산자는 스택 상단의 상단의 내용을 통역사에게 공급하는 것입니다.
이제 : 레이블을 값에 할당 할 수 있고 레이블을 호출하여 값을 리콜 할 수 있으며 해당 값은 스택으로 푸시되며 평가 연산자가 스택의 내용을 다시 통역사로 공급합니다.
[1@x]@f
f!
이 작은 시퀀스는 다음을 수행합니다.
edict는 사용 가능한 경우 라이브러리의 디버깅 섹션 (DWARF)을 통해 C 라이브러리 유형 및 글로벌 변수/기능 정보를 가져올 수 있습니다. 드워프 정보는 사전에 처리되고 저장되며 VM 은이 정보를 "이해"하고 문자 그대로 작동하는 동일한 간단한 "기본"구문을 사용하여 Edict Interpreter 내에서 제시 할 수 있습니다.
int! @x
MyCGlobalInt @y
xy Multiply!
(아래의 wip…)
심판 | 참조 |
-ref | 참조 (꼬리) |
@ | TOS에 할당 |
@Ref | 참조 할당 |
/ | 릴리스 TOS |
/ref | 릴리스 ref |
^Ref | Metareference |
ref^ | 상단 스택 레이어를 참조로 병합하십시오 |
^ref^(^ref +^) | 상단 스택 레이어를 회의 및 병합 : 참조 |
! | TOS를 평가하십시오 |
tos <... ...> | “DICT-CONTEXT로 평가하십시오”: TOS를 푸시하여 DICT <...>의 내용을 평가하여 DICT 스택의 팝 상단을 TOS로 평가하십시오. |
tos (...) | "코드 컨텍스트 평가": NULL 스택/DICT 레이어를 푸시하고, TOS를 코드 스택으로 푸시하고, 파렌의 내용을 평가하고, 코드 스택의 상단을 평가하고, DITT의 상단을 버리고, 스택의 상단을 이전 레이어로 연결합니다. |
간단한 반사 프로그램 :
int! [3]@ square! stack!
고장:
int | 스택에 "int"(기본 C 유형)의 조회 및 푸시 값 |
! | 스택 상단 평가,이 경우 "int"의 인스턴스를 할당하십시오. |
[3] | 문자 그대로의 "3"을 스택에 밀어 넣습니다 |
@ | 과제; 이 경우 문자열 "3"은 자동으로 C "int"로 강요됩니다. |
square | "Square"(기본 C 메소드)의 값을 스택에 조회하고 밀어 넣으십시오. |
! | 스택 상단 평가,이 경우 FFI 호출 기본 C 메소드 "Square" |
stack | "스택"(기본 C 메소드)의 값을 스택에 조회하고 푸시 |
! | 스택 상단 평가 ... |
int 0x9, 즉 3 제곱이 표시됩니다.
C 정수의 명백한 생성 및 할당은 예제에 대해서만 표시됩니다. 더 간단한 버전은 다음과 같습니다.
[3] square! stack!
FFI 인수의 마샬링 중에 동일한 강요가 자동으로 수행되었을 것입니다.
"코드"는 자동으로 평가되지 않습니다. 평가는 "!"를 통해 명시 적 으로 호출됩니다. 코드는 "실행"하기로 결정할 때까지 데이터 일뿐입니다.
[3] square stack! | 스택의 데이터 및 "코드" |
! stack! | TOS를 평가하고 결과를 관찰하십시오 |
계승:
[@n int_iszero(n) 1 | int_mul(fact(int_dec(n)) n)]@fact
Listree에서 값에는 키/CLL 쌍 사전이 포함되어 있으며, 여기서 각 CLL ( "원형 연결 목록", 이중 끝 큐를 구현)에는 하나 이상의 값이 포함되며, 각각은 사전을 포함합니다. .. 그리고 그렇게. Listree의 키/DEQ 구성 요소는 Arne Andersson의 "간단한"rbtree 변형을 기반으로 한 BST 구현입니다. (http://user.it.uu.se/~annea/ps/simp.pdf)
VM은 매우 간단합니다. 바이트 코드를 평가하며, 각각은 바이트 코드를 구현하는 C 메소드 배열로 인덱스입니다.
다시 놓기 | 명확한 조명 |
내선 | 문자 순서 디코딩 및 세트 조명 ( "[The Two 3]", "ABC") |
ext_push | 데이터 스택에 불을 붙입니다 |
심판 | Lit에서 사전 참조 참조를 만듭니다 |
데리프 | 사전에서 심판을 해결하십시오 |
양수인 | 데이터 스택의 팝 상단 및 Location Ref ( "@")에서 사전에 삽입하십시오. |
제거하다 | ref |
평가 | 데이터 스택의 팝 탑 및 a) 호출 FFI 또는 b) 코드 스택으로 밀고 VM을 생성합니다. |
CTX_PUSH | 데이터 스택의 팝 상단 및 사전 스택 헤드로 밀어 새 레이어를 데이터 스택으로 밀어 넣으십시오. |
CTX_POP | Data Stack의 팝 헤드 인 Top Top 두 계층의 퓨즈 및 데이터 스택으로 푸시하십시오. |
fun_push | 데이터 스택의 팝 상단 및 Func 스택에 푸시하고 데이터 스택에 레이어를 추가하고 널 레이어를 사전에 추가하십시오. |
fun_eval | {fun_pop}을 코드 스택으로 누르고 func 스택의 팝 상단 및 "Eval" |
fun_pop | 상단 2 개의 스택 레이어를 퓨즈하고 널 사전 레이어를 버립니다 |
던지다 | 예외를 던져* |
잡다 | 예외를 잡다* |
*VM 오류와 조건부가 모두 구현되는 방법은 예외이며, VM의 상태와 평균 작업보다 약간 더 많은 경우 자체 단락을받을 자격이 있습니다.
이 간단한 운영 제품군은 사전과 상호 작용하고, 언어 구성을 재귀 적으로 평가하기에 충분합니다 (VM은 스택이없는 구현입니다) 및 가장 중요한 것은 C 유형, 기능 및 데이터를 이용합니다. 기능을 쉽게 확장하기 위해 C에 대한 단단한 커플 링에 의존하는 베어 본 프레임 워크입니다.
(소금 가치가있는 모든 GNU/Linux 배포판에는 다음과 같습니다.
실행 : GCC, CMAKE 및 라이브러리가 너무 오래 아니다고 가정하면 단순히 "Make"를 실행하여 대답을 구축하고 들어갑니다.