The SLC / metalanguage got a lot of updates
This commit is contained in:
parent
61794943fb
commit
f779f514b8
702
BASED.md
702
BASED.md
@ -285,6 +285,22 @@ a pointerre ki kell írni?
|
||||
|
||||
A tömböknél a restrict lehet ESETLEG a default - de ennek fényében kellene unrestrict kulcsszó rájuk!
|
||||
|
||||
## Típusos indexek
|
||||
|
||||
Egy pointer a modern gépen 64 bit, sokszor tömörebben tudsz tárolni "referencia-szerűséget" ha indexet tárolsz rá!
|
||||
|
||||
struct A { uint32_t a, b, c; }; // 3*4=12 bytes with 4 byte alignment
|
||||
struct B { child *a, *b, *c; }; // 3*8=24 bytes with 8 byte alignment
|
||||
|
||||
struct C { A aa; uint32_t x; }; // 4*4=16 bytes with 4 byte alignment
|
||||
struct D { B bb; uint32_t x; }; // 4*8=32 bytes with 8 byte alignment (4 wasted bytes)
|
||||
|
||||
Viszont! A pointerek - mint itt is látszik - típusosak, de az indexek NEM! Viszont miért ne lehetnének?
|
||||
|
||||
child@uint32_t index; // Például így
|
||||
|
||||
A syntax-on lehetne még variálni...
|
||||
|
||||
### NonOwningPointer - smartpointer
|
||||
|
||||
Ezt szerintem érdemes C++ template-el előre megcsinálni! A lényeg az, hogy kreálni lehet a dolgot - tehát van egy factory-szerű,
|
||||
@ -1001,6 +1017,10 @@ A C/C++ kimenettel az a nehéz, hogy egyeztetni kell a szemantikáinkat - de miv
|
||||
|
||||
- Természetesen érdemes elgondolkozni, hogy eleve adjunk-e build-system-et, vagy ne. Ez egy érdekes kérdés. Ha nem adunk, akkor a modul lookup stb. is bonyolódhat pl. de könnyebb beilleszteni a BASED programokat meglévő build rendszerbe amikor interop van (pl. makefile) és ugye kevesebb effort is megcsinálni. De inkább arra hajlok, hogy mi magunk, a fordítóval build-eljünk. Ez mondjuk még a "strukturált..." megvalósításától is függ, hogy miként is lenne jobb... Szóval valamennyire nyitott kérdés is...
|
||||
|
||||
## LSP
|
||||
|
||||
- Sajnos egyetértek JonBlow-val és fasságnak tartom... De ha valaki akar, próbáljon írni egyet oké...
|
||||
|
||||
## Csomagkezelés
|
||||
|
||||
Nem igazán támogatom, bár ha véletlen sikeres nyelv volna, nehéz lenne megoldani, hogy mások ne csináljanak hozzá. De a legjobb az volna, ha first-class támogatás lenne a manuális csomag / modul kezelésnek, a sima bemásolgatósnak...
|
||||
@ -1011,6 +1031,14 @@ Linux-first, onnan aki szeretné implementálja át portolással más OS-re szer
|
||||
|
||||
# A fordítóprogram szerkezete
|
||||
|
||||
## Linkek:
|
||||
|
||||
Infix -> lengyelforma
|
||||
|
||||
https://brilliant.org/wiki/shunting-yard-algorithm/
|
||||
|
||||
## Leírás
|
||||
|
||||
Nem a tipikus rekurzív leszállós, vagy LALR jellegű fordítást csináljuk, hanem a korábbi ötletem mentén történne!
|
||||
Ez egy FORTH-szerű nyelv (stack alapú), ami viszont kiegészül hierarchikussággal és zárójelezéssel!
|
||||
|
||||
@ -1022,7 +1050,473 @@ konvenció szerint # jellel kezdjük: tehát például #include, vagy #if, esetl
|
||||
|
||||
- Ha a fordításhoz akarunk új szavakat hozzáadni, azt konvenció szerint *.mag fájlokkal tesszük meg!
|
||||
- Az ilyen fájlok lényegében DSL-t írnak így le nekünk alapvetően és #include-al hozandók be!
|
||||
- Alapvetően #passes(...) {...} leíróval írható le, hogy milyen meneteket futtatunk, mely *.mag fájlokkal!
|
||||
- Alapvetően #passes(...) {...} leíróval írható le, hogy milyen meneteket futtatunk, mely *.mag (.slc?) fájlokkal!
|
||||
|
||||
## Compiler implementációs tippek-trükkök
|
||||
|
||||
Érdekes gondolatok (zig fordító implementáció):
|
||||
|
||||
https://www.youtube.com/watch?v=IroPQ150F6c
|
||||
|
||||
De szerintem mi a köztes adatot meghagyjuk string formában (ez sajnos valszeg több ramot eszik, mint kellene)
|
||||
|
||||
Megj.:
|
||||
|
||||
Igazából a bináris formát is támogatjuk, ha az SLC tud primitíveket bináris írás/olvasásra (és kell tudni legalább írásra!)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# SLC: Strukturált formában tárolt programszöveg (tm) fordítás
|
||||
|
||||
Az SLC jelentése kettős: SuckLessCode és SuckLessCompiler. Egy általános fordító / interpreter / transpiler / metaprogramozás tool.
|
||||
Alapjában véve egy forth-szerű, interpretált általános célú nyelv önmaga is, de speciális nyelvi elemekkel compiler íráshoz!
|
||||
|
||||
Az címet nehezebb érteni, ha nem ismerjük a kontextust: Van ez az ötletem, ami forth-szerű, de faszerkezetben strukturált "compiler", ahol a forth szavaknak lehetnek "gyerekei" és ilyen blokkjai. A (...) blokk is csak egy block, mint a [..], vagy akár a {...}. Ugyanúgy forth szavakat definiálunk és meg tudjuk mondani, hogy a compiler az adott szóhoz érve mit csináljon. Tehát konkrétan scriptelni tudjuk a fordítót. Most nem mennék bele ebbe, de pár kiegészítéssel (papíron ez részletesen is megvan) kb. az összes "értelmes" nyelvet lehet így "parzolni". A fordításban csak egymásba pipe-olva állítjuk elő a következő és következő változatokat több pass-ban - és az utolsó pass ugye mondjuk fizikai fájlba ír, vagy interpreter esetén mondjuk végrehajt. Ezzel debuggolni is tök könnyű a "compiler/interpreter"-t vagy nézni hol mit optimalizál.
|
||||
|
||||
Viszont ha ezt megcsinálom, akkor ezt az itt leírt nyelvet, ezzel implementálva alapból van metaprogramozásunk - méghozzá mindennél erősebb. De ugye nem feltétlenül kényelmes is... Pl. a jai, vagy a zig comptime lehet hogy sokkal kényelemsebb.
|
||||
|
||||
Megj.: A "néhány kiegészítés / részlet" azok olyasmik mint hogy nyilvántartjuk az indentálást (mind a hibajelzések, mind az ilyen python-szerű fos nyelvek miatt), kicsit trükközni kell a <..> jellegű dolgoknál (pl. generics, template), vagy épp hogy a "fordító scriptelése" azt is jelenti, hogy tudunk előre-olvasni vagy akár kézzel karakterenként olvasni és úgy mozogni az "input szöveg nyelén" ahogy Csörnyei mondaná Magyarosan a "handle"-t... Tehát ezzel tényleg nagyon testre szabható mi történik. Alapból stack-ed is van, mint a forth-nak, meg mellé vannak a fordító adatszerkezetei is (bár esetleg azokat csak akkor éred el, ha speciális jellegű szót definiálsz). De a gyakori state-machine használat miatt változói és adattagjai is vannak a szavaknak, továbbá zárójelezésük!
|
||||
|
||||
## Fordítási időben / interpretálási időben futó szavak és példák
|
||||
|
||||
#: int
|
||||
process_varname
|
||||
declare_int_var
|
||||
#
|
||||
|
||||
int alma;
|
||||
|
||||
Macerásabb:
|
||||
|
||||
struct MyAlma {
|
||||
};
|
||||
|
||||
var MyAlma alma; // ??? var ??? több menetessel megoldható, hogy ne kelljen var, mert a típusok
|
||||
|
||||
Mivel a szóvégek nem mindenhol "jó" helyen vannak, ezek átírandók:
|
||||
|
||||
set x=1+ a(1, b(3, 4));
|
||||
|
||||
Ilyenre:
|
||||
|
||||
set x = 1 + a(1 b(3 4));
|
||||
|
||||
Ha egy programnyelvnek saját "zárójelezése" van, ami esetleg még kontextusfüggő is, akkor ilyesmit lehet:
|
||||
|
||||
#: PROCESS_LOOPS
|
||||
#read
|
||||
#if(TOP=="L") {
|
||||
// .. O O P S...
|
||||
}
|
||||
#
|
||||
|
||||
#: LOOP
|
||||
WRITE('loops{')
|
||||
PROCESS_LOOPS // -> {... + count
|
||||
PROCESS_ENDLOOPS // -> }... + count
|
||||
#read_until('E');
|
||||
#
|
||||
|
||||
LOOP
|
||||
...
|
||||
ENDLOOP
|
||||
|
||||
## Deklaráció fordítási időben
|
||||
|
||||
Ezt a turbobuf-szerű dolgot lehet aztán úgy is használni, ahogy a Seed7 programnyelv deklarál típustól függően
|
||||
például egy min/max függvényt! Erről videót itt lehet látni:
|
||||
|
||||
https://youtu.be/9m8gdgbAIrE?t=580
|
||||
|
||||
Náluk ez így néz ki:
|
||||
|
||||
const proc: DECLARE_MIN_MAX(in type: T) is func
|
||||
begin
|
||||
const func T: min (in T: x, in T: y) is return x < y ? x : y;
|
||||
const func T: max (in T: x, in T: y) is return x >= y ? x : y;
|
||||
end func;
|
||||
...
|
||||
DECLARE_MIN_MAX(integer);
|
||||
DECLARE_MIN_MAX(MyType);
|
||||
|
||||
Tehát náluk a "deklaráció" és definíció ugyanúgy kód, mint a függvény egyéb más törzsei, ám ha top-levelként,
|
||||
azaz fordításkor futtatják ezt a procedúrát (nálunk "szó" lenne), akkor ugye deklarálódnak a dolgok.
|
||||
|
||||
No mármost, nálunk ez ehhez hasonlatosan néz ki:
|
||||
|
||||
#: DECLARE_MIN_MAX
|
||||
( #readword ) // runs first
|
||||
// code that uses compiler primitives to add / build the word
|
||||
#
|
||||
|
||||
Azonban ez a forma nem éppen a legkényelmesebb. Ugyanis alapvetően a #: segítségével definiálunk egy "szót" a forth
|
||||
nyelvhez hasonlatosan, ám nálunk a szavaknak lehet hierarchiája és így amikor a "fordító" meglátja az adott szót,
|
||||
nem csak a definícióját (függvény-szerűen, threaded-code szerűen) végrehajtja, hanem az alatta adott szavak úgy
|
||||
futnak le, hogy lehetnek (...) és [...] és {...} részei is (egészen a #-ig). Az adott szakaszban csak a belső
|
||||
hierarchiát látó kódot írhatjuk, tehát a fenti példában a #readword egy egész szót olvas (mint magunk is), de azt
|
||||
a (...) követő részéből a szónak - ha nincs ilyen, akkor semmi sem történik. A zárójeleken kívüli résznél lévő
|
||||
kód pedig a külső, a szó megjelenésének első betűjén álló olvasó (és író) fejjel fut.
|
||||
|
||||
Rendelkezésünkre áll egy(esetleg kettő?) forth-szerű stack, erre a #push stb. szavakkal lehet hivatkoznunk.
|
||||
Itt a push a nyelv struktúrája miatt használható "42" helyett "#push(42)" - ez azért kell, hogy a valódi prognyelv
|
||||
immediate-jei normálisan használhatók maradjanak, ugyanis nem tűnik jónak, ha alapesetben minden szám itt a stack
|
||||
tetejére csak felmenne, ha egy szó helyett egy számot látunk épp...
|
||||
|
||||
Egy minimál forth(-szerű) szószett áll rendelkezésre: #swap, #drop, #iadd, #imul, fadd(?), fmul(?), stb.
|
||||
De nem ilyen 32 / 10 szavas forth-ból érdemes kiindulni (bár lehetne), hanem valami praktikusból!
|
||||
|
||||
Lásd például innen jó sok dolog:
|
||||
|
||||
http://www.murphywong.net/hello/simple.htm
|
||||
|
||||
Emellett olyan szavak is rendelkezésre állnak, amelyek a "fordítót scriptelik". Ilyen például a #readword, ami
|
||||
a stackre olvassa a "talált szót" és mozgatja az input nyelét. A stack-en alapvetően uint32 méretű szám lehet!
|
||||
Természetesen rendelkezésre áll még a #readchar, #readline, #readuntil is, továbbá a #write(...) is!
|
||||
|
||||
Régi forth-os esetekre lásd hasonlóért:
|
||||
|
||||
https://www.forth.com/starting-forth/11-forth-compiler-defining-words/
|
||||
|
||||
## A #readword használata a következő:
|
||||
|
||||
- A szó string belseje olvasható karakterenként: 42 #wordchar, #wordchar[42], 1 #wordchar(41)
|
||||
- Ehhez természetesen a stack-re kerül a szó TÖVE (zárójelek nélkül) és hossza is (ebben a sorrendben)!
|
||||
- Szerintem nem árt egy #strcmp('for') jellegű dolog, amivel a word szó része olvasható... 0-1-et tesz a stackre!
|
||||
- Jó lehet még: #strprefix('starts-with-text'), esetleg #strsuffix(...) is ami 0 vagy N ad (N db megfelelő char!)
|
||||
- Ez a kialakítás pazarlónak tűnhet a 32 bites stack miatt, de így nem lesz ram szivárgás a rendszerben!
|
||||
- Egyébként a reprezentációt nem kötöttem ki ezzel - szóval lehet 4 karaktert tárolni egy szóban itt ám!
|
||||
- Ennek megfelelően kell #popword utasítás, ami leszedi az egész szót a stack-ről ha nem érdekel már!
|
||||
- Szükség lehet például még #dupword utasításra is - ezek végül is "string kezelő" rutinok...
|
||||
- Az olvasó fej a szó (nem-zárójeles része) mögé mozog.
|
||||
|
||||
A #readword(raw) a zárójelezéssel együtt az egészet olvassa be, míg #readword(full) ugyanez, de wspace*->space!
|
||||
Szükséges még a #skipword és #skipword(full) szavak, melyek spórolósabbak, mint olvasni és drop-olni...
|
||||
|
||||
Vegyük észre, hogy a zárójeleket ezzel alapesetben nem kezeltük:
|
||||
|
||||
- #has(), #has[], #has{} - ezek kiadják, a szót követőe nyélen állva, ahhoz tartozik-e adott szekció (0 vagy 1)
|
||||
- Nem tartozhat több (..) egy adott szóhoz (se a másik eseteknél)! Tehát mindegyik blokkféleségből max egy van!
|
||||
- De a fordító scriptelős feldolgozásnál ott viszont állhat többször és a sorrendiséget fejezi ki csupán!
|
||||
- #enter(), #enter[], #enter{} - ezekkel bemegyünk olyan módba, hol az adott blokk vége eof-ként értődik
|
||||
- #exit - ez lép eggyel vissza - de az adott enterrel megkezdett dolog VÉGE mögé állunk (feldolgoztuk)
|
||||
- FONTOS: Az enter-exit lényegében automatikus, amikor a definícióban a megfelelő helyre írjuk a kódunkat, tehát
|
||||
a zárójelek belsejébe írtuk azt a részt, amikor a zárójelen belüli dolgokat dolgozzuk fel...
|
||||
|
||||
Viszont azt is vegyük észre, hogy a szó tartalmazhat whitespace-t, ha teljességében olvassuk be
|
||||
|
||||
## Insert-álás (az input stream-en)
|
||||
|
||||
Factor programnyelven láttam olyat, hogy a bejövő szó-folyam aktuális pontjánra "írhatok" is akár...
|
||||
Ezt valahogy talán jó lenne támogatni, de lehet hogy felesleges. Ezzel nem csak a #write outputra írása lenne,
|
||||
hanem jelenleg ahol tart a végrehajtás, azt a programszöveget tudnánk módosítani. A fordításhoz szerintem ez
|
||||
nem kifejezetten ad plusz funkcionalitást, de az interpreterként működéshez viszont igen...
|
||||
|
||||
Ennek megfelelően valami hasonló lehetne:
|
||||
|
||||
#: DECLARE_MIN_MAX_INT
|
||||
#inserts {
|
||||
#: MIN_INT
|
||||
#IF(#LT) {
|
||||
#DROP
|
||||
} [
|
||||
#SWAP
|
||||
#DROP
|
||||
]
|
||||
#
|
||||
#: MAX_INT
|
||||
#IF(#GT) {
|
||||
#DROP
|
||||
} [
|
||||
#SWAP
|
||||
#DROP
|
||||
]
|
||||
#
|
||||
}
|
||||
#
|
||||
|
||||
Vegyük észre, hogy itt a #insert mögötti blokkban szereplő dolgok mind az olvasó fej jelen pozíciója MÖGÉ kerülő
|
||||
nyers programszöveg - itt az olvasó fej már ugyebár beolvasta a `DECLARE_MIN_MAX_INT` szót, tehát az mögött állunk
|
||||
és olyan eredményt kapunk, mintha az adott dolgokat titkon oda gépelte volna valaki, szóval amint kész ezen szó
|
||||
futtatása, a rendszer a #: deklarációs szót fogja az inputján látni. Ezzel az input kiegészítésre került!
|
||||
|
||||
A #inserts-hez tartozhatnak paraméterek:
|
||||
|
||||
42 21 #inserts (N K) { #push($N) #writechar #push($K) #push(2) #imul #writechar }
|
||||
|
||||
Természetesen ez sokkal érdekesebb, ha nem így magában áll, hanem szó deklarációban, de a lényeg,
|
||||
hogy a zárójelek között felsorolhatok dolgokat, ami a stack-ről értéket kap. A $$ a $ escape-elése csupán...
|
||||
|
||||
Természetesen itt kellhet típust adni:
|
||||
|
||||
'some text word' 21 #inserts (word(W) float(F)) { .... }
|
||||
|
||||
Az inserts továbbá rendelkezhez output átirányítós paraméterrel:
|
||||
|
||||
#inserts [0] { ... }
|
||||
|
||||
^^Ez például a 0.-dik kimenetre / pipe-ra ír, szerintem erre külön kéne saját szó:
|
||||
|
||||
#outputs { ... }
|
||||
42 21 #errors (N K) { ... }
|
||||
|
||||
Az insert-hez szükséges:
|
||||
|
||||
- Egy plusz verem / adatszerkezet, ahova az kerül amivel kiegészítettem a jelen pozíciót, ha beljebb vagyok, nyélmozog+másol!
|
||||
- A többit igazából meg kell tudjuk írni a nyelv meglévő elemeivel, de perf okból valszeg jó ha beépítetten jön?
|
||||
|
||||
## Szimbólumtábla
|
||||
|
||||
Rendelkezésre áll továbbá a "szimbólumtábla" is, ami egy map adatszerkezet és szónévből egy definícióra mutat
|
||||
illetve annak tulajdonságainak elérésére, illetve új bejegyzések beírására hasznos szavaink is lesznek...
|
||||
|
||||
Szükség lehet ezen a ponton fullword(W) jellegű paraméterre is, ami a zárójelekkel együtt értett teljes szót
|
||||
jelképezi, de szerintem alapjában a word, mint típus, lényegében "string" típus ugye a hossz + tárolás mód..
|
||||
|
||||
A szimbólumtábla egy szimbóluma megnyitható "fájlszerűen", ezért a definícióját write paranccsal megírhatjuk!
|
||||
|
||||
**Megj.: Talán ezzel kiváltható a #inserts kulcsszó használata! De egy plusz stack-el is...**
|
||||
|
||||
## A #write
|
||||
|
||||
Ezzel a szimbólumtáblával manuálisan már sok mindent megoldhatunk és a #insert-el együtt ez powerful már,
|
||||
de a fordítóprogram-jellegű használathoz jó, ha szerepel itt "#write[0](..) {...}" szó is. Ez az inserts-hez
|
||||
hasonló módon, de külső fájlba (vagy standard kimenetre, error-ra) tud írkálni.
|
||||
|
||||
Természetesen ennek megfelelően kell még #fopen[0](out.txt) jellegű dolog is, ami a nullás fájlt nyitja (mondjuk
|
||||
4-8 ilyen lehessen) és #fclose[0] szó is. Kell még stdout[0] és stderr[1] jellegű dolog is...
|
||||
|
||||
Igazából a "fordító" úgy fordít, hogy sok menetben, folyamatosan át-transzformálja a programszöveget egy másik
|
||||
programszöveggé, melynek elején van egy #include, ami behozza az adott új "makrókat" és azokkal az új menet mit
|
||||
fog pontosan is csinálni már... Ennek megfelelően például az ifeket hamar ugrásokra tudjuk fordítani stb.
|
||||
|
||||
A nyelvnek a köztes reprezentációja lényegében szintén emberileg olvasható szöveges kód és meg is állítható egy
|
||||
adott menet közepén a fordítás. Természetesen ez akkor van, ha az alaprendszert fordítónak használjuk és nem
|
||||
egy interpreternek éppen.
|
||||
|
||||
## Template makró és egyéb példák
|
||||
|
||||
Fordítandó (pl. JASS transpilerhez):
|
||||
|
||||
if a > 1 then
|
||||
set b = 2
|
||||
elseif a < -1 then
|
||||
set b = 3
|
||||
else
|
||||
set b = 0
|
||||
endif
|
||||
|
||||
Jó lenne (bnf-szerű):
|
||||
|
||||
$if = if $expr then $code (elseif $expr then $code)* (else $code)? endif
|
||||
|
||||
De imperatívan így írható ez le (expression gyárilag jöhet(?) és stack segítségével lengyelformára hozás, shunting yard algó):
|
||||
|
||||
#: expr
|
||||
#expression(+ - / *) [0 1 2 3]
|
||||
#writeexpr
|
||||
#
|
||||
|
||||
Azért code reuse lehetséges:
|
||||
|
||||
#: if
|
||||
#progress_until("then") {
|
||||
#expr
|
||||
}
|
||||
#
|
||||
|
||||
Az első menet után "standardabb" formába írva vannak a dolgok és deklaratív leírás adható már:
|
||||
|
||||
// PASS #2
|
||||
|
||||
if (expr(3)[a 1 >])
|
||||
{
|
||||
set b = 2
|
||||
}
|
||||
[
|
||||
if (expr(3)[3 a -1 <])
|
||||
{
|
||||
set b = 3
|
||||
}
|
||||
[
|
||||
set b = 0
|
||||
]
|
||||
]
|
||||
|
||||
// Alapvetően #: esetén a () utáni részbe írt az imperatívan fut le
|
||||
// Itt viszont paraméter a template-ezéshez - mindegy a sorrend?
|
||||
// Ez már nem kell C-s szó legyen, csak egy #insert-re forduljon!
|
||||
##: if($con){$then}[$else]
|
||||
condition($con) // ebx és eax között hasonlításra felépít - stack-re vissza adja milyen jump
|
||||
asm(cmp eax,ebx)
|
||||
jumptype(else) // jnz / jg / jl stack alapján....
|
||||
loclabel(then:)
|
||||
$then
|
||||
loclabel(else:)
|
||||
$else
|
||||
#
|
||||
|
||||
Bonyolultabb példa (bogus példa - "bement-e az if ágba az alapján az if true-false ad vissza mint expression pl")
|
||||
de valamiért külön match-elni akarom
|
||||
|
||||
##: if(if($con) {$value1} [$value2]) {$then} [$else]
|
||||
|
||||
^^lehet hogy ezt azért nem kéne, mert fadiffelést okoz...
|
||||
|
||||
másik példa (Jass nyelvről újra):
|
||||
|
||||
set a = 1
|
||||
LOOP
|
||||
set a = (a + 1)
|
||||
EXITWHEN a == 42
|
||||
ENDLOOP
|
||||
|
||||
Ebből legyen - útána meg már elvileg nem olyan nehéz:
|
||||
|
||||
set a = 1
|
||||
LOOP {
|
||||
set(a) {(a + 1)}
|
||||
EXITWHEN(a == 42)
|
||||
}
|
||||
|
||||
## A makró nyelven a FORTH-szerű szavaknak változói / adattagjai is lehetnek (nem csak kódja)!
|
||||
|
||||
- a szóhoz tartozó olvasása a stack-re tehát csak a neve, illetve a kukacos neve
|
||||
- írása meg a zárójelbe tett dolgot írja bele - kivéve hogy ha ott "pont" áll akkor a stack tetejét írja bele és csőváz
|
||||
- csak 4 byte-os int van és csőváz... Ha valaki mást akar megoldja "handle"-kkel majd meg float-ra lesz gyakorlatilag reinterpret cast-olgatás vagyis a művelet határozza meg, hogy float-ként dolgozol-e a négy byte-al, de ez talán nem baj, ha extension, mert a fordítóba nem nagyon kellenek float-ok szerintem.....
|
||||
|
||||
Egy adattagokat(változókat) is tartalmazó szó és példa a "lokális" változó-elérésre...
|
||||
|
||||
#: MY_WORD a b c
|
||||
#a
|
||||
#inc
|
||||
#a(.)
|
||||
#
|
||||
|
||||
Máshonnan elérni így lehet, namespace-elés szerűen:
|
||||
|
||||
MYWORD@a(41)
|
||||
MYWORD
|
||||
MYWORD@a
|
||||
#intprint
|
||||
|
||||
Ha nem szerepel több szó a definíciós első sorban az enter előtt / zárójelek előtt, akkor csak kódot tartalmazó "funkcionális" szó:
|
||||
|
||||
#: #just_code
|
||||
#dup
|
||||
#inc
|
||||
#swap
|
||||
#
|
||||
|
||||
#push(12)
|
||||
#just_code
|
||||
#intprint // 12
|
||||
#intprint // 13
|
||||
|
||||
Vagy:
|
||||
|
||||
#: #just_code (
|
||||
#dup
|
||||
#inc
|
||||
#swap
|
||||
)
|
||||
#
|
||||
|
||||
Globális változót ezt követően úgy definiálhatunk, hogy namespace-eléssel valami értelmes "namespace"-be tesszük egy szó alá,
|
||||
tehát alapból van egy rendszerezettség (például egy adott state-machine globális változói stb.)
|
||||
|
||||
Ha nagyon ki akarjuk hagyni a namespace-elést, akkor a változó név helyett írjunk "típust" (ez csak név!) és üres szót neki:
|
||||
|
||||
#: MY_VAR int
|
||||
#
|
||||
|
||||
Esetleg:
|
||||
|
||||
#: MY_VAR int #
|
||||
|
||||
Használat:
|
||||
|
||||
#push(41)
|
||||
MYVAR@int(.)
|
||||
|
||||
MYVAR@int
|
||||
#inc
|
||||
#print // 42
|
||||
|
||||
Ja nem mondtam, de az érték megadása a zárójelek közt működik, a kiolvasás meg anélkül. Ha pont szerepel, a stackről kap értéket!
|
||||
|
||||
Megj.:
|
||||
|
||||
A zárójelek közti rész NEM expression... csak simán egy szám (esetleg ugye 'a' 'abcd' módon 0..4 karakter!)
|
||||
|
||||
Megj.:
|
||||
|
||||
Igazából kicsit fura, hogy a forth-ban nem találták ezt ki a változókra... jó ötletnek néz ki interpretálásnál...
|
||||
|
||||
Megj.:
|
||||
|
||||
Az adattagok arra is "jók", hogy a menetek egymásnak kommunikáljanak vele és így kvázi "blokkokra ható" dolgokat írhatunk.
|
||||
Ennek akkor van jeletősége, ha a "blokkot" előtte lévő, korábban azt megelőző dolgok "változtatják" jelentésében, mert akkor
|
||||
létrehozhatunk egy számozott blokk_42 szót a kimeneten (definícióval), míg a blokk helyén "hívhatjuk" és ott elérhető a
|
||||
korábban beállított változó anélkül, hogy nagy káosz keletkezne (de ez csak egy példa, nem kell így csinálni!)
|
||||
|
||||
## Típusok a meta-nyelven
|
||||
|
||||
Alapból a változók és a stack 32bites (előjeles) int típusú - ez kb. mindent jól leír és a legtöbb architektúrán gyors is.
|
||||
|
||||
Nem igazán vannak, de a forth-szavakba elkódolható a típus (assembly-hez hasonlóan).
|
||||
|
||||
Például string-kezelő dolgok kellenek inputon! Az input nyelét olvasva pl. karakter kerülhet a stack-re (int ascii),
|
||||
de hasonlóan karakterláncot is "építhetünk" (vagy olvashatunk) a stack-en (-re), olyankor minden elem max 4 karakter és van a
|
||||
stack tetején egy hossz jelző! Ahhoz, hogy könnyen építhessük a stack mélyebb része a szó eleje és a tetejéhez közel a vége!
|
||||
Ez fontos, mert így minimális stack műveletet eredményez ha "stringbuilderezgetünk"! Ami egy transpiler tech-nek elég fontos...
|
||||
|
||||
Szerintem kellenek ugyan ilyen szavak arra is, hogy bináris adat stream-et olvassunk és írjunk. Ugyanez oldja meg ezt is!
|
||||
|
||||
## Naming convention ('#'-jelek itt mindenfele...)
|
||||
|
||||
Ha az slc-t csak magában használjuk (interpreterként - default működés):
|
||||
|
||||
Akkor nincsenek a gyári szavaknak prefixei, ellenben meg kell adni a "záró" szót (ami pontosvessző defaultként).
|
||||
|
||||
Ha programnyelvet csinálunk:
|
||||
|
||||
Alapből minden, nem a célnyelvhez tartozó szó '#'-al kezdődjön. A "gyári" forth szavak így jönnek tehát, de amiket csinálsz is
|
||||
jó ha ilyenek - kivéve amikor a nyelvet, amit transpile-olsz szeretnéd már definiálni, vagy ha eleve nem nyelvet csinálsz
|
||||
hanem a meta-nyelven magán "nyersen" programozol... tehát ha interpretált programnyelvnek használod a meta-nyelvet magát...
|
||||
|
||||
|
||||
Lehetővé tesszük, hogy a meta-nyelv indításakor (pl. parancssori paraméterrel) a gyári szavak prefixje
|
||||
megváltoztatható legyen... Tehát ne #dup hanem mondjuk @dup legyen és a tieiddel ezt lekövetheted...
|
||||
|
||||
slc -prefix='#' my.app
|
||||
|
||||
Ha nem akarunk prefix-et, akkor meg kellhet mondani, hogy mi a "záró jelző" karakter
|
||||
|
||||
- ez alapból a prefix maga, de csak ahogy önmagában áll, tehát a fenti példában '#' (lásd a példáinkat)
|
||||
- üres prefix esetén alapból a pontosvessző karakter (forth-os szokás)
|
||||
|
||||
slc -ender='%'
|
||||
|
||||
Default: Üres prefix és pontosvessző ender. Ezzel forth-szerű interpretert kapunk!
|
||||
|
||||
Megj.:
|
||||
|
||||
Trükkösködést jelenthet, ha adott fordító implementációban a "gyári" szavak egy részét SLC kódként implementáljuk,
|
||||
például helytakarékossági okokból egy embedded környezetben. Ilyenkor ugyanis az így implementált "gyári" szavak
|
||||
prefixje is megfelelően kell változzon. Ennek az egyik egyszerű módja, ha "gyári szó deklaráláshoz" külön szó van,
|
||||
de igazából ezt a "külön szót" valószínűleg mi magunk is megint csak implementálhatjuk valamilyen insertálással!
|
||||
|
||||
Megoldás erre: #builtin: prefixelendő_szó
|
||||
|
||||
## Névtelen szó
|
||||
|
||||
Hasznos leíírni, hogy szó nélkül, csak zárójel esetén mi történjen...
|
||||
|
||||
Ez lehet hogy baromira elbonyolít mindent mondjuk... Talán csak API-t kéne adni erre ki...
|
||||
|
||||
## Pipeline és párhuzamosság
|
||||
|
||||
@ -1054,172 +1548,96 @@ kiegészítettünk potencionálisan egy jó kis aszinkronitással.
|
||||
Ennek a megfelelője talán meglehetne a BASED programnyelven is egyébként! Esetleg ott nem stdout/err meg ilyen
|
||||
szöveges interfésszel, hanem simán csatornákkal és egy DAG-ot leírva, azért sok minden kifejezhető.
|
||||
|
||||
## Strukturált formában tárolt programszöveg (tm) fordítás
|
||||
## Reprezentáció
|
||||
|
||||
Az első pontot nehezebb érteni, ha nem ismerjük a kontextust: Van ez az ötletem, ami forth-szerű, de faszerkezetben strukturált "compiler", ahol a forth szavaknak lehetnek "gyerekei" és ilyen blokkjai. A (...) blokk is csak egy block, mint a [..], vagy akár a {...}. Ugyanúgy forth szavakat definiálunk és meg tudjuk mondani, hogy a compiler az adott szóhoz érve mit csináljon. Tehát konkrétan scriptelni tudjuk a fordítót. Most nem mennék bele ebbe, de pár kiegészítéssel (papíron ez részletesen is megvan) kb. az összes "értelmes" nyelvet lehet így "parzolni". A fordításban csak egymásba pipe-olva állítjuk elő a következő és következő változatokat több pass-ban - és az utolsó pass ugye mondjuk fizikai fájlba ír, vagy interpreter esetén mondjuk végrehajt. Ezzel debuggolni is tök könnyű a "compiler/interpreter"-t vagy nézni hol mit optimalizál.
|
||||
struct word {
|
||||
int16_t len; // (*): A codelen helyett teljes rekord hossz (ender-el bezárólag), a codelen számítható: a vars hossza+len!
|
||||
char name[]; // inline! Tehát nem egy pointer!
|
||||
char vars[]; // inline! zero-terminált! Ebben simán lineárisan keresünk csak! Kevés változót használjanak felsorolva!
|
||||
char data[]; // inline! Előbb a változók, aztán a kód - így írható primitív forth-szavakkal is ha kell!
|
||||
};
|
||||
|
||||
Viszont ha ezt megcsinálom, akkor ezt az itt leírt nyelvet, ezzel implementálva alapból van metaprogramozásunk - méghozzá mindennél erősebb. De ugye nem feltétlenül kényelmes is... Pl. a jai, vagy a zig comptime lehet hogy sokkal kényelemsebb.
|
||||
Variációk:
|
||||
|
||||
Megj.: A "néhány kiegészítés / részlet" azok olyasmik mint hogy nyilvántartjuk az indentálást (mind a hibajelzések, mind az ilyen python-szerű fos nyelvek miatt), kicsit trükközni kell a <..> jellegű dolgoknál (pl. generics, template), vagy épp hogy a "fordító scriptelése" azt is jelenti, hogy tudunk előre-olvasni vagy akár kézzel karakterenként olvasni és úgy mozogni az "input szöveg nyelén" ahogy Csörnyei mondaná Magyarosan a "handle"-t... Tehát ezzel tényleg nagyon testre szabható mi történik. Alapból stack-ed is van, mint a forth-nak, meg mellé vannak a fordító adatszerkezetei is (bár esetleg azokat csak akkor éred el, ha speciális jellegű szót definiálsz).
|
||||
* pozitív vagy nulla len: 4-byte-os változók (n db) és SLC kód szövegként.
|
||||
* negatív len legfelső bit 1: A legfelső bitet nullázva és a címet egy nagy indexként véve megkapjuk a "complex_word" indexet
|
||||
|
||||
### Fordítási időben / interpretálási időben futó szavak
|
||||
Mint az egyértelmű, a szó deklaráció a kód szövegben legalább 4 byte-ot igénybe vesz:
|
||||
|
||||
Ezt a turbobuf-szerű dolgot lehet aztán úgy is használni, ahogy a Seed7 programnyelv deklarál típustól függően
|
||||
például egy min/max függvényt! Erről videót itt lehet látni:
|
||||
* ':'
|
||||
* whitespace
|
||||
* egy karakter a névből (kötelező)
|
||||
* lezáró karakter
|
||||
* a szó tartalma se lehet amúgy üres és legalább egy whitespace és egy karakter nevű szó áll majd ott...
|
||||
|
||||
https://youtu.be/9m8gdgbAIrE?t=580
|
||||
Emiatt ha a legfelső bit egyes volt a word-ben, akkor ott egy négybyte-os indexre cserélhetjük a dolgot, ami egy complexword index:
|
||||
|
||||
Náluk ez így néz ki:
|
||||
struct complex_word {
|
||||
int64_t len; // a szó végére mutat, tehát ahol az input folytatódik!
|
||||
char *name;
|
||||
|
||||
const proc: DECLARE_MIN_MAX(in type: T) is func
|
||||
begin
|
||||
const func T: min (in T: x, in T: y) is return x < y ? x : y;
|
||||
const func T: max (in T: x, in T: y) is return x >= y ? x : y;
|
||||
end func;
|
||||
...
|
||||
DECLARE_MIN_MAX(integer);
|
||||
DECLARE_MIN_MAX(MyType);
|
||||
int64_t var_count;
|
||||
char **var_names;
|
||||
int32_t variables;
|
||||
|
||||
Tehát náluk a "deklaráció" és definíció ugyanúgy kód, mint a függvény egyéb más törzsei, ám ha top-levelként,
|
||||
azaz fordításkor futtatják ezt a procedúrát (nálunk "szó" lenne), akkor ugye deklarálódnak a dolgok.
|
||||
// Regular word definition code
|
||||
int64_t main_len;
|
||||
char *main_data;
|
||||
|
||||
No mármost, nálunk ez ehhez hasonlatosan néz ki:
|
||||
// (...)
|
||||
int64_t parentheses_len;
|
||||
char *parentheses_data;
|
||||
|
||||
#: DECLARE_MIN_MAX
|
||||
( #readword ) // runs first
|
||||
// code that uses compiler primitives to add / build the word
|
||||
#end
|
||||
// [...]
|
||||
int64_t squarebracket_len;
|
||||
char *squarebracket_data;
|
||||
|
||||
Azonban ez a forma nem éppen a legkényelmesebb. Ugyanis alapvetően a #: segítségével definiálunk egy "szót" a forth
|
||||
nyelvhez hasonlatosan, ám nálunk a szavaknak lehet hierarchiája és így amikor a "fordító" meglátja az adott szót,
|
||||
nem csak a definícióját (függvény-szerűen, threaded-code szerűen) végrehajtja, hanem az alatta adott szavak úgy
|
||||
futnak le, hogy lehetnek (...) és [...] és {...} részei is (egészen a #end-ig). Az adott szakaszban csak a belső
|
||||
hierarchiát látó kódot írhatjuk, tehát a fenti példában a #readword egy egész szót olvas (mint magunk is), de azt
|
||||
a (...) követő részéből a szónak - ha nincs ilyen, akkor semmi sem történik. A zárójeleken kívüli résznél lévő
|
||||
kód pedig a külső, a szó megjelenésének első betűjén álló olvasó (és író) fejjel fut.
|
||||
// {...}
|
||||
int64_t brace_len;
|
||||
char *brace_data;
|
||||
};
|
||||
|
||||
Rendelkezésünkre áll egy(esetleg kettő?) forth-szerű stack, erre a #push stb. szavakkal lehet hivatkoznunk.
|
||||
Itt a push a nyelv struktúrája miatt használható "42" helyett "#push(42)" - ez azért kell, hogy a valódi prognyelv
|
||||
immediate-jei normálisan használhatók maradjanak, ugyanis nem tűnik jónak, ha alapesetben minden szám itt a stack
|
||||
tetejére csak felmenne, ha egy szó helyett egy számot látunk épp...
|
||||
Bármikor átalakítható egy szó egy "complexword"-re!
|
||||
|
||||
Egy minimál forth(-szerű) szószett áll rendelkezésre: #swap, #drop, #iadd, #imul, fadd(?), fmul(?), stb.
|
||||
De nem ilyen 32 / 10 szavas forth-ból érdemes kiindulni (bár lehetne), hanem valami praktikusból!
|
||||
Megjegyzés:
|
||||
|
||||
Lásd például innen jó sok dolog:
|
||||
* Azért ilyennek választottam, mert a ": " miatt a forrás szöveget beolvasva pont marad ott 16 byte mindenképp!
|
||||
* Lásd még a rust compilerről szóló youtube videó valahol fentebb az SLC-s blokk előttről!!!
|
||||
* Ugyanis: a számított mezők jobbak, mint nagyobb / másik memória terület szükséges volna csak a node-ok tárolgatására.
|
||||
|
||||
http://www.murphywong.net/hello/simple.htm
|
||||
## Az engine-hez szükséges
|
||||
|
||||
Emellett olyan szavak is rendelkezésre állnak, amelyek a "fordítót scriptelik". Ilyen például a #readword, ami
|
||||
a stackre olvassa a "talált szót" és mozgatja az input nyelét. A stack-en alapvetően uint32 méretű szám lehet!
|
||||
Természetesen rendelkezésre áll még a #readchar, #readline, #readuntil is, továbbá a #write(...) is!
|
||||
Szerintem ezeket inline-olható, function pointerré kéne "elkódolnom", akár úgy, hogy feles paraméterek vannak + szétifelés!
|
||||
|
||||
Régi forth-os esetekre lásd hasonlóért:
|
||||
* Engine kódja
|
||||
* Callstack - előre adott méret (pl. parancssori paraméter, vagy embeddednél beállított)
|
||||
* Adatstack, a műveleteivel - előre adott méret (pl. parancssori paraméter, vagy embeddednél beállított)
|
||||
* Szimbólumtáblára MAP adatstruktúra (pl. kismap - név alapú lookupra + változó tároláshoz is [key alapján tudható melyik!])
|
||||
* Complexword-ök "vektora" (mindig indexelés alapú! Nem pointerezős!
|
||||
* Session storage - egy charakter vektorhoz hasonló, de csak állandóan növő storage + session reset rá.
|
||||
|
||||
https://www.forth.com/starting-forth/11-forth-compiler-defining-words/
|
||||
^^Ezzel a memória kialakítással a memory layout:
|
||||
|
||||
A #readword használata a következő:
|
||||
| engine kód | callstack | adatstack | szimbólumtábla -> ... <-complexwords|-> ... <- sessionstorage | src |
|
||||
|
||||
- A szó string belseje olvasható karakterenként: 42 #wordchar, #wordchar[42], 1 #wordchar(41)
|
||||
- Ehhez természetesen a stack-re kerül a szó TÖVE (zárójelek nélkül) és hossza is (ebben a sorrendben)!
|
||||
- Szerintem nem árt egy #strcmp('for') jellegű dolog, amivel a word szó része olvasható... 0-1-et tesz a stackre!
|
||||
- Jó lehet még: #strprefix('starts-with-text'), esetleg #strsuffix(...) is ami 0 vagy N ad (N db megfelelő char!)
|
||||
- Ez a kialakítás pazarlónak tűnhet a 32 bites stack miatt, de így nem lesz ram szivárgás a rendszerben!
|
||||
- Egyébként a reprezentációt nem kötöttem ki ezzel - szóval lehet 4 karaktert tárolni egy szóban itt ám!
|
||||
- Ennek megfelelően kell #popword utasítás, ami leszedi az egész szót a stack-ről ha nem érdekel már!
|
||||
- Szükség lehet például még #dupword utasításra is - ezek végül is "string kezelő" rutinok...
|
||||
- Az olvasó fej a szó (nem-zárójeles része) mögé mozog.
|
||||
Alternatíva:
|
||||
|
||||
A #readword(raw) a zárójelezéssel együtt az egészet olvassa be, míg #readword(full) ugyanez, de wspace*->space!
|
||||
Szükséges még a #skipword és #skipword(full) szavak, melyek spórolósabbak, mint olvasni és drop-olni...
|
||||
| engine kód | callstack | szimbólumtábla -> ... <-complexwords|adatstack-> ... <- sessionstorage | src |
|
||||
|
||||
Vegyük észre, hogy a zárójeleket ezzel alapesetben nem kezeltük:
|
||||
Igazából embedded környezetben, ilyen kismap-szerű (vagy még egyszerűbb) szimbólumtáblával tehát a legtöbb dolog
|
||||
vagy konstans, vagy csak két ponton van balról-jobbra és jobbról-balra folyton akár végtelenig (memhatár) növő rész!
|
||||
|
||||
- #has(), #has[], #has{} - ezek kiadják, a szót követőe nyélen állva, ahhoz tartozik-e adott szekció (0 vagy 1)
|
||||
- Nem tartozhat több (..) egy adott szóhoz (se a másik eseteknél)! Tehát mindegyik blokkféleségből max egy van!
|
||||
- De a fordító scriptelős feldolgozásnál ott viszont állhat többször és a sorrendiséget fejezi ki csupán!
|
||||
- #enter(), #enter[], #enter{} - ezekkel bemegyünk olyan módba, hol az adott blokk vége eof-ként értődik
|
||||
- #exit - ez lép eggyel vissza - de az adott enterrel megkezdett dolog VÉGE mögé állunk (feldolgoztuk)
|
||||
- FONTOS: Az enter-exit lényegében automatikus, amikor a definícióban a megfelelő helyre írjuk a kódunkat, tehát
|
||||
a zárójelek belsejébe írtuk azt a részt, amikor a zárójelen belüli dolgokat dolgozzuk fel...
|
||||
A complexwords egy embedded megoldásban "mozoghat", tehát mivel csak indexálással érjük el és NEM pointeresen, ezért
|
||||
ott memcpy-vel mozgatható, ha kezd elfogyni vagy a szimbólumtábla, vagy a session storage.
|
||||
|
||||
Viszont azt is vegyük észre, hogy a szó tartalmazhat whitespace-t, ha teljességében olvassuk be
|
||||
A jobbra-balra mozgó complexwords-ön túl még egy ilyen memóriát tudnánk csinálni, tehát egy cövek két oldalát is használva!
|
||||
Odakerülhet tehát például még egy másik stack is ha szeretnénk (pl. memhatárig növelhető adat stack beállítás / paraméter?)
|
||||
|
||||
### Insert-álás az input stream-en
|
||||
Ennél bonyolultabb memory management nem szükséges - tehát nem kell "malloc-implementáció" hozzá embeddedben!
|
||||
|
||||
Factor programnyelven láttam olyat, hogy a bejövő szó-folyam aktuális pontjánra "írhatok" is akár...
|
||||
Ezt valahogy talán jó lenne támogatni, de lehet hogy felesleges. Ezzel nem csak a #write outputra írása lenne,
|
||||
hanem jelenleg ahol tart a végrehajtás, azt a programszöveget tudnánk módosítani. A fordításhoz szerintem ez
|
||||
nem kifejezetten ad plusz funkcionalitást, de az interpreterként működéshez viszont igen...
|
||||
Megj.:
|
||||
|
||||
Ennek megfelelően valami hasonló lehetne:
|
||||
|
||||
#: DECLARE_MIN_MAX_INT
|
||||
#inserts {
|
||||
#: MIN_INT
|
||||
#IF(#LT) [
|
||||
#DROP
|
||||
] {
|
||||
#SWAP
|
||||
#DROP
|
||||
}
|
||||
#end
|
||||
#: MAX_INT
|
||||
#IF(#GT) [
|
||||
#DROP
|
||||
] {
|
||||
#SWAP
|
||||
#DROP
|
||||
}
|
||||
#end
|
||||
}
|
||||
#end
|
||||
|
||||
Vegyük észre, hogy itt a #insert mögötti blokkban szereplő dolgok mind az olvasó fej jelen pozíciója MÖGÉ kerülő
|
||||
nyers programszöveg - itt az olvasó fej már ugyebár beolvasta a DECLARE_MIN_MAX_INT szót, tehát az mögött állunk
|
||||
és olyan eredményt kapunk, mintha az adott dolgokat titkon oda gépelte volna valaki, szóval amint kész ezen szó
|
||||
futtatása, a rendszer a #: deklarációs szót fogja az inputján látni. Ezzel az input kiegészítésre került!
|
||||
|
||||
A #inserts-hez tartozhatnak paraméterek:
|
||||
|
||||
42 21 #inserts (N K) { #push($N) #writechar #push($K) #push(2) #imul #writechar }
|
||||
|
||||
Természetesen ez sokkal érdekesebb, ha nem így magában áll, hanem szó deklarációban, de a lényeg,
|
||||
hogy a zárójelek között felsorolhatok dolgokat, ami a stack-ről értéket kap. A $$ a $ escape-elése csupán...
|
||||
|
||||
Természetesen itt kellhet típust adni:
|
||||
|
||||
'some text word' 21 #inserts (word(W) float(F)) { .... }
|
||||
|
||||
### Szimbólumtábla
|
||||
|
||||
Rendelkezésre áll továbbá a "szimbólumtábla" is, ami egy map adatszerkezet és szónévből egy definícióra mutat
|
||||
illetve annak tulajdonságainak elérésére, illetve új bejegyzések beírására hasznos szavaink is lesznek...
|
||||
|
||||
Szükség lehet ezen a ponton fullword(W) jellegű paraméterre is, ami a zárójelekkel együtt értett teljes szót
|
||||
jelképezi, de szerintem alapjában a word, mint típus, lényegében "string" típus ugye a hossz + tárolás mód..
|
||||
|
||||
A szimbólumtábla egy szimbóluma megnyitható "fájlszerűen", ezért a definícióját write paranccsal megírhatjuk!
|
||||
|
||||
**Megj.: Szerintem ezzel kiváltható a #inserts kulcsszó használata!!!**
|
||||
|
||||
### A #write
|
||||
|
||||
Ezzel a szimbólumtáblával manuálisan már sok mindent megoldhatunk és a #insert-el együtt ez powerful már,
|
||||
de a fordítóprogram-jellegű használathoz jó, ha szerepel itt "#write[0](..) {...}" szó is. Ez az inserts-hez
|
||||
hasonló módon, de külső fájlba (vagy standard kimenetre, error-ra) tud írkálni.
|
||||
|
||||
Természetesen ennek megfelelően kell még #fopen[0](out.txt) jellegű dolog is, ami a nullás fájlt nyitja (mondjuk
|
||||
4-8 ilyen lehessen) és #fclose[0] szó is. Kell még stdout[0] és stderr[1] jellegű dolog is...
|
||||
|
||||
Igazából a "fordító" úgy fordít, hogy sok menetben, folyamatosan át-transzformálja a programszöveget egy másik
|
||||
programszöveggé, melynek elején van egy #include, ami behozza az adott új "makrókat" és azokkal az új menet mit
|
||||
fog pontosan is csinálni már... Ennek megfelelően például az ifeket hamar ugrásokra tudjuk fordítani stb.
|
||||
|
||||
A nyelvnek a köztes reprezentációja lényegében szintén emberileg olvasható szöveges kód és meg is állítható egy
|
||||
adott menet közepén a fordítás. Természetesen ez akkor van, ha az alaprendszert fordítónak használjuk és nem
|
||||
egy interpreternek éppen.
|
||||
|
||||
## LSP
|
||||
|
||||
- Sajnos egyetértek JonBlow-val és fasságnak tartom... De ha valaki akar, próbáljon írni egyet oké...
|
||||
A session storage alapvetően arra kell, hogy stringeket építsünk. Tudom... Erre a stack is alkalmas, de kellhet az olvasott
|
||||
inputról (src) valahogy a complex szó átírásnál, meg az outputra írásokhoz előkészítésnél valami ilyen tárhely, ami azért
|
||||
perzisztensebb, mint a sima stack! Az src természetesen épp függ attól, amely fájlt olvasunk, szóval a session kezdetén az
|
||||
egész session storage..src végig törlődhet majd. Egy embedded (vagy pl. retró számítógép) memóriáját ezzel kihasználjuk!
|
||||
|
Loading…
x
Reference in New Issue
Block a user