Паскаль готов
May. 26th, 2021 10:13 pmПрошу любить и жаловать: https://github.com/besm6/pasauto-re/blob/main/pasauto.pas
Эти пять с половиной тысяч строк заняли от силы полторы дюжины вечеров.
Теперь любители компиляторов приглашаются восстанавливать мнемонические названия переменных и процедур.
Вот пример программы (решето Эратосфена, https://rosettacode.org/wiki/Sieve_of_Eratosthenes#Pascal с машинно-зависимыми модификациями и исправленной off-by-one ошибкой):
В результате получаем:
Несколько комментариев: СЧ - считывание, ЗЧ - запись, ИК - индексирование, ПВ - вызов процедур (в частности, OWI - output write integer), Э050 - элементарные функции, У0/У1 - условные переходы, ПБ - безусловный переход, АС - арифметическое сложение, ОВ - обратное вычитание, ЛС - логическое сложение, АД - деление, СР - сравнение.
Эти пять с половиной тысяч строк заняли от силы полторы дюжины вечеров.
Теперь любители компиляторов приглашаются восстанавливать мнемонические названия переменных и процедур.
Вот пример программы (решето Эратосфена, https://rosettacode.org/wiki/Sieve_of_Eratosthenes#Pascal с машинно-зависимыми модификациями и исправленной off-by-one ошибкой):
(*=P-,T-,L+ - no stack dump, no range checking, with assembly listing *)
_program primes;
_const PrimeLimit = 1023;
_var
primes: _array [2..PrimeLimit] _of Boolean;
n, k, width, pos: integer;
_begin
(* calculate the primes *)
_for n := 2 _to PrimeLimit _do primes[n] := true;
_for n := 2 _to trunc(sqrt(PrimeLimit)) _do _begin
_if primes[n] _then _begin
k := sqr(n);
_while k <= PrimeLimit _do _begin
primes[k] := false;
k := k + n
_end
_end
_end;
(* output the primes *)
pos := 1;
_for n := 2 _to PrimeLimit _do
_if primes[n] _then _begin
width := trunc(ln(n)/ln(10)+1)+1;
pos := pos + width;
write(n:width);
_if pos > 120 _then _begin
writeln; pos := 1;
_end
_end;
_if pos <> 1 _then writeln
_end.
В результате получаем:
ПАСКАЛЬ-АВТОКОД 9.(17.05.88)
________________________________________________________________________________________________________________________________
АВТОКОД 00.00.70. БЛОК N 000001 ЛИСТ 000000
В;КД=0021,ЗАГР=77040,LОАD,UNLОАD,СН,Ч=12,LI=4,ИА=74000,УРЕГ=ИА(3),
Z0=УРЕГ(2),ПБИ15,ЕF,Н,Т,Е,ОС=Е(5),SL=ОС(2),Z64,РR=SL(10),МОD=РR(3),
VR,СПТ,СПЛ,RF=VR(5),ЧМ1,ГТ=RF(5),RС=ГТ(6),СР=RС(4),АВ,ОВ,RWF,СТХТ=ОВ(5),
WS,WС,WА,WВ,WI,WR,WL,ОWS,ОWС,ОWА,ОWВ,ОWI,ОWR,ОWL,ИК=ОWL(2),СЧ,
ЗЧ,ЦУ=74136,ТR=74141,D=74145,N=74151,РА=74173,R=74202,АL=74206,
GI=74222,RI=74251,РО=74257,RО=74313,МI=74323,UN=74337,РF=74715,
GF=74760,СL=75075,ГА=75104,ЯГА=75115,ТNL=75165,ОV=75241,IА=75361,
АI=75363,ГГ=75365,Ф=75675,RSR=75714,
Н; КД,
К; АД: 14 ПВ Z1= , РRIМЕS 00021 14 31 00103 00 000 0000
17 СА СА= СЧ 15, 00022 17 25 02014 00 010 0015
1 ЗЧ 2010= , 00023 01 000 2010 00 000 0000
А2: 1 СЧ 2010= ОВ 14, 00024 01 010 2010 00 006 0014
У1 А3= СЧ 13, 00025 00 27 00031 00 010 0013
1 ИК 2010= 1 ЗЧ 10, 00026 01 23 02010 01 000 0010
1 СЧ 2010= АС 13, 00027 01 010 2010 00 004 0013
1 ЗЧ 2010= ПБ А2, 00030 01 000 2010 00 30 00024
А3: СЧ 15= 1 ЗЧ 2010, 00031 00 010 0015 01 000 2010
А4: СЧ 14= 16 ПВ R, 00032 00 010 0014 16 31 74202
Э050 = , 00033 00 050 0000 00 000 0000
16 ПВ ТR= , 00034 16 31 74141 00 000 0000
1 СМ 2010= 17 ОВ , 00035 01 003 2010 17 006 0000
У1 А5= 1 ИК 2010, 00036 00 27 00053 01 23 02010
1 СЧ 10= У0 А6, 00037 01 010 0010 00 26 00051
1 СЧ 2010= 17 ЗЧ , 00040 01 010 2010 17 000 0000
ЛС Z64= 17 АУ , 00041 00 115 4022 17 017 0000
16 ПВ ЦУ= , 00042 16 31 74136 00 000 0000
1 ЗЧ 2011= , 00043 01 000 2011 00 000 0000
А7: 1 СЧ 2011= ОВ 14, 00044 01 010 2011 00 006 0014
У1 А10= СЧ 12, 00045 00 27 00051 00 010 0012
1 ИК 2011= 1 ЗЧ 10, 00046 01 23 02011 01 000 0010
1 СЧ 2011= 1 АС 2010, 00047 01 010 2011 01 004 2010
1 ЗЧ 2011= ПБ А7, 00050 01 000 2011 00 30 00044
А10:
А6: 1 СЧ 2010= АС 13, 00051 01 010 2010 00 004 0013
1 ЗЧ 2010= ПБ А4, 00052 01 000 2010 00 30 00032
А5: СЧ 13= 1 ЗЧ 2013, 00053 00 010 0013 01 000 2013
СЧ 15= 1 ЗЧ 2010, 00054 00 010 0015 01 000 2010
А11: 1 СЧ 2010= ОВ 14, 00055 01 010 2010 00 006 0014
У1 А12= 1 ИК 2010, 00056 00 27 00100 01 23 02010
1 СЧ 10= У0 А13, 00057 01 010 0010 00 26 00076
СЧ 16= 16 ПВ R, 00060 00 010 0016 16 31 74202
Э050 5= , 00061 00 050 0005 00 000 0000
1 СМ 2010= 16 ПВ R, 00062 01 003 2010 16 31 74202
Э050 5= , 00063 00 050 0005 00 000 0000
17 АД = АС 17, 00064 17 016 0000 00 004 0017
16 ПВ ТR= , 00065 16 31 74141 00 000 0000
АС 13= 1 ЗЧ 2012, 00066 00 004 0013 01 000 2012
1 СЧ 2013= 1 АС 2012, 00067 01 010 2013 01 004 2012
1 ЗЧ 2013= 1 СЧ 2012, 00070 01 000 2013 01 010 2012
17 ЗЧ = 1 СЧ 2010, 00071 17 000 0000 01 010 2010
16 ПВ ОWI= , 00072 16 31 74104 00 000 0000
1 СЧ 2013= ОВ 20, 00073 01 010 2013 00 006 0020
У0 А14= 16 ПВ РR, 00074 00 26 00076 16 31 74031
СЧ 13= 1 ЗЧ 2013, 00075 00 010 0013 01 000 2013
А14:
А13: 1 СЧ 2010= АС 13, 00076 01 010 2010 00 004 0013
1 ЗЧ 2010= ПБ А11, 00077 01 000 2010 00 30 00055
А12: 1 СЧ 2013= СР 13, 00100 01 010 2013 00 012 0013
У0 А15= 16 ПВ РR, 00101 00 26 00102 16 31 74031
А15: ПБ Е= , 00102 00 30 74012 00 000 0000
У; А1,
К; Z1: РА 3= СЧ 5, 00103 00 037 0003 00 010 0005
УИ 1= 1 ПИ 17, 00104 00 040 0001 01 044 0017
________________________________________________________________________________________________________________________________
АВТОКОД 00.00.70. БЛОК N 000001 ЛИСТ 000001
1 ПИ 13= 15 ПВ RI, 00105 01 044 0013 15 31 74251
СЧ = 1 ЗЧ LI, 00106 00 010 0000 01 000 0004
14 ПИ 16= ПБ RО, 00107 14 044 0016 00 30 74313
Х:
Н; 11,
С; 64000, 00011 00 000 0000 00 006 4000
0, 00012 00 000 0000 00 000 0000
1, 00013 00 000 0000 00 000 0001
1777, 00014 00 000 0000 00 000 1777
2, 00015 00 000 0000 00 000 0002
12, 00016 00 000 0000 00 000 0012
4050000000000000, 00017 10 050 0000 00 000 0000
170, 00020 00 000 0000 00 000 0170
Н; 1,
С; 1404350213022510, 00001 03 004 3502 02 30 22510
0040400001201001, 00002 00 040 4000 00 120 1001
Н; 5,
Л; ДХ, 00005 00 000 0000 00 000 0110
Н; 7,
К; 10 ПВ УРЕГ= ИА = 00007 10 31 74003 00 22 00000
10 СА -10= 10 ПБ АД, 00010 10 25 77770 10 30 00021
Э; СА:2014,
К;
Н; 66005,
Е;
________________________________________________________________________________________________________________________________
АВТОКОД 00.00.70. БЛОК N 000001 ЛИСТ 000001
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157 163
167 173 179 181 191 193 197 199 211 223 227 229 233 239 241 251 257 263 269 271 277 281 283 293 307 311 313 317 331 337
347 349 353 359 367 373 379 383 389 397 401 409 419 421 431 433 439 443 449 457 461 463 467 479 487 491 499 503 509 521
523 541 547 557 563 569 571 577 587 593 599 601 607 613 617 619 631 641 643 647 653 659 661 673 677 683 691 701 709 719
727 733 739 743 751 757 761 769 773 787 797 809 811 821 823 827 829 839 853 857 859 863 877 881 883 887 907 911 919 929
937 941 947 953 967 971 977 983 991 997 1009 1013 1019 1021
Несколько комментариев: СЧ - считывание, ЗЧ - запись, ИК - индексирование, ПВ - вызов процедур (в частности, OWI - output write integer), Э050 - элементарные функции, У0/У1 - условные переходы, ПБ - безусловный переход, АС - арифметическое сложение, ОВ - обратное вычитание, ЛС - логическое сложение, АД - деление, СР - сравнение.
no subject
Date: 2021-05-27 05:41 am (UTC)Исторический исходник, на который многие тогда мечтали хотя бы взглянуть.
no subject
Date: 2021-05-28 08:56 am (UTC)no subject
Date: 2021-05-28 02:51 am (UTC)А что потом этот ассемблер перекручивает в машкод?
no subject
Date: 2021-05-28 08:46 am (UTC)no subject
Date: 2021-05-30 02:01 am (UTC)Код достаточно компактный получается на выходе. Целый компилятор и это всё в 5500 строках кода!
no subject
Date: 2021-05-30 04:07 am (UTC)no subject
Date: 2021-05-30 04:16 am (UTC)А вот интересно, а есть же наверняка версии (или прообразы) языка Си которые также можно было компилиировать в один проход (условно, конечно, т.к. придется накладывать ограничения на объявления функций и меток до использования).
Я на godbolt посмотрел то, что выдает freepascal без оптимизаций примерно также +-
DEBUGSTART_$OUTPUT:
primes(smallint):
pushq %rbp
movq %rsp,%rbp
leaq -1088(%rsp),%rsp
movq %rbx,-1080(%rbp)
movw %di,-8(%rbp)
movw $1,-1036(%rbp)
.Lj5:
movw -1036(%rbp),%ax
addw $1,%ax
movw %ax,-1036(%rbp)
movzwl -1036(%rbp),%eax
movb $1,-1034(%rbp,%rax,1)
cmpw $1023,-1036(%rbp)
jge .Lj7
jmp .Lj5
.Lj7:
movw $1,-1036(%rbp)
.Lj8:
movw -1036(%rbp),%ax
addw $1,%ax
movw %ax,-1036(%rbp)
movzwl -1036(%rbp),%eax
cmpb $0,-1034(%rbp,%rax,1)
jne .Lj11
jmp .Lj12
.Lj11:
movswl -1036(%rbp),%eax
movl %eax,-1052(%rbp)
movl -1052(%rbp),%edx
movl -1052(%rbp),%eax
imull %edx,%eax
movw %ax,-1040(%rbp)
jmp .Lj14
.Lj13:
movzwl -1040(%rbp),%eax
movb $0,-1034(%rbp,%rax,1)
movswl -1040(%rbp),%edx
movswl -1036(%rbp),%eax
leal (%edx,%eax),%eax
movw %ax,-1040(%rbp)
.Lj14:
cmpw $1023,-1040(%rbp)
jle .Lj13
jmp .Lj15
.Lj15:
.Lj12:
cmpw $31,-1036(%rbp)
jge .Lj10
jmp .Lj8
.Lj10:
movw $1,-1048(%rbp)
movw $1,-1036(%rbp)
.Lj16:
movw -1036(%rbp),%ax
addw $1,%ax
movw %ax,-1036(%rbp)
movzwl -1036(%rbp),%eax
cmpb $0,-1034(%rbp,%rax,1)
jne .Lj19
jmp .Lj20
.Lj19:
fnstcw -1056(%rbp)
fnstcw -1052(%rbp)
orw $3840,-1056(%rbp)
movswl -1036(%rbp),%eax
movl %eax,-1060(%rbp)
fildl -1060(%rbp)
fldln2
fxch
fyl2x
fldt _$OUTPUT$_Ld1
fdivrp %st,%st(1)
fld1
faddp %st,%st(1)
fldcw -1056(%rbp)
fistpq -1072(%rbp)
fldcw -1052(%rbp)
fwait
movq -1072(%rbp),%rax
leaq 1(%rax),%rax
movw %ax,-1044(%rbp)
movswl -1048(%rbp),%edx
movswl -1044(%rbp),%eax
leal (%edx,%eax),%eax
movw %ax,-1048(%rbp)
call fpc_get_output
movq %rax,%rbx
movswq -1036(%rbp),%rdx
movswl -1044(%rbp),%edi
movq %rbx,%rsi
call fpc_write_text_sint
call fpc_iocheck
movq %rbx,%rdi
call fpc_write_end
call fpc_iocheck
cmpw $120,-1048(%rbp)
jg .Lj21
jmp .Lj22
.Lj21:
call fpc_get_output
movq %rax,%rbx
movq %rbx,%rdi
call fpc_writeln_end
call fpc_iocheck
movw $1,-1048(%rbp)
.Lj22:
.Lj20:
cmpw $1023,-1036(%rbp)
jge .Lj18
jmp .Lj16
.Lj18:
cmpw $1,-1048(%rbp)
jne .Lj23
jmp .Lj24
.Lj23:
call fpc_get_output
movq %rax,%rbx
movq %rbx,%rdi
call fpc_writeln_end
call fpc_iocheck
.Lj24:
movq -1080(%rbp),%rbx
movq %rbp,%rsp
popq %rbp
ret
_$OUTPUT$_Ld1:
.byte 23,172,168,170,221,141,93,147,0,64
_$OUTPUT$_Ld4:
.quad _$OUTPUT$_Ld6
.quad _$OUTPUT$_Ld2
.byte 0
_$OUTPUT$_Ld5:
.quad _$OUTPUT$_Ld4
.byte 0
_$OUTPUT$_Ld2:
.ascii "SMALLINT\000"
.quad .La1
.La1:
.ascii "SMALLINT\000"
.byte 5
.byte 2
_$OUTPUT$_Ld3:
.quad _$OUTPUT$_Ld2
_$OUTPUT$_Ld6:
.ascii "BOOLEAN\000"
.quad .La2
.La2:
.ascii "Boolean\000"
.byte 2
.byte 1
_$OUTPUT$_Ld7:
.quad _$OUTPUT$_Ld6
.byte 0
DEBUGEND_$OUTPUT:
no subject
Date: 2021-05-30 05:54 am (UTC)Но есть и проблемы даже с той самой syntax-directed translation. Скажем, выражение "c-(a*b)", которое по-хорошему нужно компилировать как, в понятных терминах, "LOAD a, MUL b, RSUB c" благодаря наличию команды обратного вычитания (и как это делает другой, более умный Паскаль-компилятор, который с деревьями выражений), этим компилируется примерно как "LOAD a, MUL b, PUSH c, SUB (stack)". И это только то, что первым пришло мне в голову во время прогулки проверить после возвращения домой. На более сложных выражениях, возможно, разница будет ещё более заметной. Впрочем, она и так заметна - более сложный компилятор компилируется сам собой в более компактный код.