2013 m. rugpjūčio 13 d., antradienis

Programa išplečianti kodo santrumpas

Kažkada svajojau apie tokią programą, kuri leistu rašant Pascal'iu, naudoti santrumpas (pvz. "++A", vietoje "A:=A+1" ar "inc(A)"), bei leistų vietoje "begin" ir "end", rašyti "{" ir "}", kas užima mažiau vietos, ir yra paplitę C kalbų šeimoje.
Taigi, pamėginau su Perlu parašyti programą, kuri redaguoja tekstą: "sutrumpintą" Pascal programos kodą verčia tikru kodu. Įvykdžiau tik keletą savo paties pageidavimų, jie yra tokie:

{ / } => begin / end,
++/-- A => inc(A) / dec(A),
A+=B => A:=A+B,
A-=B => A:=A-B,
A%=B => A:=A mod B,
A//=B => A:=A div B,
A&=B => A:=A and B,
A|=B => A:=A or B,
A!>B => if A>B then A:=B (patogi santrumpa),
A**B => A*A*A*...{B kartų} (o ką? :D)

fu I N { => for I:=1 to N do {
fd I N { => for I:=1 downto N do { (ups, nelogiška...)
(fu - for up, fd - for down),

ir kt.

Jau keletą kartų pasinaudojau, patiko.
Tik, žinoma, programos galvojimas dažnai užima daug daugiau laiko, negu pats kodo rinkimas, todėl programa parašyta be sportinio tikslo, bet iš įdomumo.

Ir programa realizuota menkokai: nenaudoju asociatyviųjų masyvų, silpnos ir galimai lėtos reguliariosios išraiškos, prastokas kodavimo stilius, neaiškūs kintamųjų vardai.

Kodas:
( http://ideone.com/2RJkeM )

$_=join"",<>;

print "(*\nModified from: \n\n", $_, "\n*)\n\n";

s/\blint\b/longint/gm;
s/\bint\b/integer/gm;
s/\bstr\b/string/gm;
s/\bbool\b/boolean/gm;
s/\bwln\b/writeln/gm;
s/\brln\b/readln/gm;

/{/m;

$s=$`; $t=$';

$s=~s#([=:])([^=:;]*?),\s*(\b\w+\b)\s*;#
    ($m1=$1,$m2=$2,$m3=$3) and
    (@m=$m2=~s/\s*(\w+)\s*/1..$1/g) and
    $m1."array [".$m2."] of ".$m3.";"
    #gme;

$t=~s/([+-])\1\s*([a-z][\w\[\],]*)/($1 eq "+"?"in":"de")."c($2)"/gemi;
$t=~s/([a-z][\w\[\],]*)\s*([+-])=\s*(\w[\w\[\],]*)/"$1:=$1".($2 eq "+"?"+":"-")."$3"/gemi;
#  $t=~s/([a-z][\w\[\],]*)\s*(\*|\/)=\s*(\w[\w\[\],]*)/"$1:=$1".($2 eq "*"?"*":"/")."$3"/gemi;
$t=~s/([a-z][\w\[\],]*)\s*([&|])=\s*(\w[\w\[\],]*)/"$1:=$1".($2 eq "&"?" and ":" or ")."$3"/gemi;
$t=~s/([a-z][\w\[\],]*)\s*(\%|\/\/)=\s*(\w[\w\[\],]*)/"$1:=$1".($2 eq "%"?" mod ":" div ")."$3"/gemi;

$t=~s/([a-z][\w\[\],]*)\s*!([><])\s*(\w[\w\[\],]*)/if $1$2$3 then $1:=$3/gmi;

$t=~s#f([ud])\s*(.*?)\s*{#
    (($m0=$1 eq "u"?"":"down"),$m=$2) and (@m=$m=~s/,/ /g) and (@m=$m=~s/ +/ /g) and
    "for ".(
    $m=~/ (\S)+ /?("$`:=$1 ".$m0."to $'"):
    ($m=~/ / and "$`:=1 ".$m0."to $'")
    )." do {"
    #gemi;
   
$t=~s#rot\s*\(?([^;}]+)\)?\s*([;}])#
    ($m1=$1, $m2=$2, $m1=~s/[^,]+//emi, $t1=$&, $t1=~s/\s//g, $t11="$t1:=", $m1=~s/,\s*(\w+)\s*/
        (1, $t11.="$1; $1:=")
        /gemi, $t11.="$t1"."$m2") and ($t11)
    #gemi;
   
$t=~s/([a-z][\w\[\],]*)\s*\*{2}\s*(\d+)/"$1".("*$1"x($2-1))/gemi;
   
$t=~s/{/ begin /gm;
$t=~s/}/ end /gm;

$_=$s." begin ".$t;

# s/ +/ /gm;
# s/^ | $//gm;

print;






Kartu plačiau paaiškinsiu (išskaidysiu) kurią nors kodo eilutę, pvz. 44-ą: 

"$t=~s/([a-z][\w\[\],]*)\s*\*{2}\s*(\d+)/"$1".("*$1"x($2-1))/gemi;

"$t" yra teksto dalis (čia išsaugota visas kodas einantis po pirmojo begin'o ("{")).
Šiai teksto daliai darome keitimus, naudojant konstrukciją: "$t=~s///".
Gale prirašyti modifikatoriai: g, e, m, i. Reiškias: "global", "evaluate", "multi-line", "ignore case". Reiškias: 1) modifikuos visas (o ne vieną) surastas ieškomas eilutės vietas, 2) apskaičiuos, ką reikia įrašyti vietoje surastų ieškomų eilutės vietų, 3) tekstą įsivaizduos kaip vieną didelę eilutę, suklijuotą eilutės pabaigos ženklais, 4) ieškos bet kokių (mažųjų ir didžiųjų) raidžių.
Ką ieško?
Ieško to, kas yra "$t=~s/čia//".

Į ką keičia?
Į tą, ką apskaičiuos "$t=~s//šičia/".
Ieško štai ko:
dviejų iš eilės pasikartojančių žvaigždučių (daugybos ženklų) - "\*{2}", po kurių gali sekti įvairūs tarpai "\s*" ir tada - seka skaičius - "\d+". Surastą skaičių mes išsisaugojame, nes apskčiaudžiame - "(\d+)". Prieš pasikartojančias žvaigždutes, gali būti tarpų - vėl "\s*", o prieš juos privalo būti kintamasis, kuris prasideda lotyniška raide (didžiąja ar mažąja), o tolimesni jo simboliai (jeigu yra) privalo būti iš tokios simbolių aibės: "a-z" + "0-9" + "_" + "[" + "]" + ",". Kintamojo pavyzdys - "mas1[3,j]". Kintamasis, kurio (deja) paieška nesuras - "mas1[i+1,j]".
Keičia į štai ką:
surastą ir į kintamąjį "$1" išsaugotą kintąmąjį, po kurio seka "$2" (surastą skaičių) kartų (minus vienas) pasikartojantis užrašas "*$1" (daugybos ženklas ir kintamasis).