From d4975c29e1d68a058cfa1f87cc00a7efd9c30514 Mon Sep 17 00:00:00 2001 From: Gaby Date: Wed, 14 Oct 2020 10:00:59 -0400 Subject: [PATCH 001/162] First commit --- __pycache__/ast_nodes.cpython-38.pyc | Bin 0 -> 7167 bytes __pycache__/cool_grammar.cpython-38.pyc | Bin 0 -> 9477 bytes __pycache__/cool_tokenizer.cpython-38.pyc | Bin 0 -> 1605 bytes __pycache__/cool_visitor.cpython-38.pyc | Bin 0 -> 6776 bytes __pycache__/errors.cpython-38.pyc | Bin 0 -> 2507 bytes __pycache__/methods.cpython-38.pyc | Bin 0 -> 2057 bytes __pycache__/parser_automatons.cpython-38.pyc | Bin 0 -> 5068 bytes .../shift_reduce_parsers.cpython-38.pyc | Bin 0 -> 6070 bytes ast_nodes.py | 182 +++++++ cmp/__init__.py | 0 cmp/__pycache__/__init__.cpython-38.pyc | Bin 0 -> 174 bytes cmp/__pycache__/automata.cpython-38.pyc | Bin 0 -> 7952 bytes cmp/__pycache__/evaluation.cpython-38.pyc | Bin 0 -> 1191 bytes cmp/__pycache__/pycompiler.cpython-38.pyc | Bin 0 -> 16544 bytes cmp/__pycache__/utils.cpython-38.pyc | Bin 0 -> 9713 bytes cmp/__pycache__/visitor.cpython-38.pyc | Bin 0 -> 2375 bytes cmp/ast.py | 62 +++ cmp/automata.py | 207 +++++++ cmp/cil.py | 231 ++++++++ cmp/evaluation.py | 36 ++ cmp/languages.py | 228 ++++++++ cmp/nbpackage.py | 87 +++ cmp/pycompiler.py | 512 ++++++++++++++++++ cmp/semantic.py | 214 ++++++++ cmp/utils.py | 219 ++++++++ cmp/visitor.py | 80 +++ cool_grammar.py | 184 +++++++ cool_tokenizer.py | 43 ++ cool_visitor.py | 161 ++++++ errors.py | 61 +++ main.py | 98 ++++ methods.py | 150 +++++ parser_automatons.py | 225 ++++++++ shift_reduce_parsers.py | 273 ++++++++++ 34 files changed, 3253 insertions(+) create mode 100644 __pycache__/ast_nodes.cpython-38.pyc create mode 100644 __pycache__/cool_grammar.cpython-38.pyc create mode 100644 __pycache__/cool_tokenizer.cpython-38.pyc create mode 100644 __pycache__/cool_visitor.cpython-38.pyc create mode 100644 __pycache__/errors.cpython-38.pyc create mode 100644 __pycache__/methods.cpython-38.pyc create mode 100644 __pycache__/parser_automatons.cpython-38.pyc create mode 100644 __pycache__/shift_reduce_parsers.cpython-38.pyc create mode 100644 ast_nodes.py create mode 100755 cmp/__init__.py create mode 100644 cmp/__pycache__/__init__.cpython-38.pyc create mode 100644 cmp/__pycache__/automata.cpython-38.pyc create mode 100644 cmp/__pycache__/evaluation.cpython-38.pyc create mode 100644 cmp/__pycache__/pycompiler.cpython-38.pyc create mode 100644 cmp/__pycache__/utils.cpython-38.pyc create mode 100644 cmp/__pycache__/visitor.cpython-38.pyc create mode 100755 cmp/ast.py create mode 100755 cmp/automata.py create mode 100755 cmp/cil.py create mode 100755 cmp/evaluation.py create mode 100755 cmp/languages.py create mode 100755 cmp/nbpackage.py create mode 100755 cmp/pycompiler.py create mode 100755 cmp/semantic.py create mode 100755 cmp/utils.py create mode 100755 cmp/visitor.py create mode 100644 cool_grammar.py create mode 100644 cool_tokenizer.py create mode 100644 cool_visitor.py create mode 100644 errors.py create mode 100644 main.py create mode 100644 methods.py create mode 100644 parser_automatons.py create mode 100644 shift_reduce_parsers.py diff --git a/__pycache__/ast_nodes.cpython-38.pyc b/__pycache__/ast_nodes.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..84bd791eb3de643d82e4a274335e429dd3806838 GIT binary patch literal 7167 zcmb`M%X8b-6~+OAZ#_u8Y|D~tS&HK@j?LJP<2Zg%qU=;NDeD<0=?teG4$KS5a7jYF zfHIOtU38Lmri(7R=%R}*y68fSF0#nq(iwEw|DvmY-z5RUCdF3^4esCv+^2Q9J`)6>H!%#k1f`;xhQM;v9Hg zTmfHEoCj}+P4K4TIq-YpD)_46dGPz<8u*%(NBw*u1K(4;0{%?g2j92m zQGXTuxp)A6pm+`ZP&@)ZQhW*gSUdqgQG6L(5?kOc#p~d0Q3jV4Ujgrkr{JfGH^j3S zTH%X&G@E#><1FEHk#3r$Rdu0NV?syWm>;h=!m6Aae!5m`nN6!!^Ru;D(-DUaUQgF* zzdke@?I)+2Ou~XH{`0)}%4u4~*G)@U(s7GBPW`ZHwLG_YM~d}h%ap~k(>$;nX5DsL z#plvFw(1@#-foHY1L?d56;0Qxwa@|g=E1RKH+j0qdo8Ui?$N?$C01HQ(bXbi-)mJv z7|;~=r{HW~noUZpvq5n1nr9iO%TaiupJ+7h0@m77wT_@I@ZW*X+}y18KP~Vl~874yI{7a7FHM#Tb=X=^Tpi&BoP? zr{mo+Ulaafxna8QyDIC9ZE)~9e9JV}e#<8Y-nD)bLmA^6ml-@N7=Fwae)7PS$X!3Z zXPMq1L>1z43Xgrm7DsXcS8|?3nEomW)O+MZm-jV2iN7~%{W=&XLqV^|nYS%<-+mqs z=q3mgxhG6iR$`?A17P9VVXOX5jOxs*;NW!_qE$dAL=29u0u?)nW9bxK-@VynhF@&a%73EV~8cbVYrz#(+2eYzb+Zb00Y zU}KrqCxhHO;rPsoi=gD^>R~ae0BBARB%}_y;=g}cQt>z2s=%ABZDqenqF*=eA zM!z6!;C?i_R{QiX4AH>kVt}sDS|>>434=8MjrsqJ(P=bBafC-k<0DtlO?in$pA;%k zPh{+^^mc5t;BW|hKx3WYkb8o|XC+n|F!Hinm=E{Wd{}431qZL$zKql5xQ-6EZob6Y z`9i$~BQmPa3c$xSr{+FRJqumuq3i*}<}w-=X`myTJdx`+bFdo`wfHRHXq zTAfR);acjlGZ3oDcCBhUs8mgdb^45ohZGkX6}fglM~Te_nm%CjPHe~%#U}IfS9Zgi zJSj4DrzLD|!`@1X_t2j+Q=-g{hbb{1_Fxp@n`pbu_8sBmiG-)iraQTAHPiXoI&9Qz z&uY4zvEUoblK0W6e$(JCJ01$33wkh$?yG3}6E^SYCQqb$nqGI&<^O3&$Tj%yo&T@l zZa?8aW6vX*z7*}mDDpYyS7@XopWGwgz|9gX4cwUG#WxxhUm3E~;x@EB{dYE_Jv%Mm za9+M{Z@1#6+;{zy>8ZWcTRW}m=#u=9#YZgqOa#AVr_(6H9Tsw<-N`UGg;-_462S%b z7qrre54k5kd{$zm0qbIByW!M-rE-JSgM-&R%Q)ZpLDt@$>;5b=-{OyqTElj|LaedRX={VwxJeIF%?9y%XWqW%tz!A52zlk^^kL4)) z!jpDuUrowq>$wNBzm2#dkL4z}?Klm~Y<(pU)yh9W(r2*!yNECHSibTdU(ZZz5{C%8 z595D`I3thcEVtXv3ET9B`T88T{}}N_9?Ms%;;7#c1A@nm>7OD#$Yc4)?z-PPwipsN zZlC`gaYG)o97&l`vC5Fw9Y^sf;oOMds2ITlb32DlK6`wxl^jscaW5-U~xhIM3+?U6*$tIf+cH>>)aHxc^I#WG%XQ!vV-R;B~ zx)zBn3*uN-+!8CnB0v}fLcm`$eB@KUg2V?t0Pj`LbY>FQ*qPYs?s~sh^{ZD`*Q?j_ z`AjAifxo~1`@_|{laa_jQ0V?sK)42%`xCg)2$kv)OCpklX}K<23Q;VTs8*Cjtr&?} zaT2!@Bw-~<(n^t(HAIH2G)Y?-lCiQRYvoAJ%9Fe`OopujDOe+9#2O`|))*PH#>u!f zK_;vsDO!_c(wZVu);_Y&nkLiM44JX^ll|5KascX%Qa9vK2 z!PFb?ZR&L{CZ8n}@6SbBwT2Hpb-?*N(FZkQ6!ulFEu~ zl1;IF97%KiG@Id4hU@pU159JH9LWNru!HOnJIv)AmyfWc>=>8xAP=$Qti(>Rlk60m zWAki*on~j)S*{-jeUhDH=h+2zkzHb!A$^5i<+=jsVr-F>*%GU;*Vr{*_7yrpM?Z+v zabqG7+I;A*LWk$Gc?JFZzoU5q}=8C|nD09fvX#VICD&f;^L;+bM6cD{s_~ zVR_`DlOZ1UqkcTZr+RSdflBvvAu)f^FSTnr1J4vNO^5mz@P~Rj(}l+YKLz;{aLvKh z;lP#w2eypv5A(gn+w zY>1Y+!bklvw2jV(*r*Q}UFed> zo|W~_w%dyH@pPDH%pZdP%b-gGekQ~b9rDk$@w3n2SK9cw9z0FYcgbl#?VpEy8Q{GT z;)tgG3vK*j51yfyy5x+X@h?KYER??-;)rJaOKtp051yr0yX36D&(A^G#SqK-S^p}> z%01W;u0y)igXL(YOV0VH_ruW&*7&5$93P) zzuu!Cr#E`!JiXZ^=lwE$Bb4)g-e07*dgRyW?H>6W{Y;Nsp?A9E5m-$)A3hsmBYqph zcF{Mx@Nt++_(qt33;W@%P&e*R01vKy(9ydgK7lx0?vZizzukpIK8`t`cu`+^0)CAz zK^^6q0)E9i%gtnYBk&_C_rSjxf_>ESRvugT?Rv9V26w`B=jx{GRkSiSYI7W@G!K_+ zhVE@TMz>A}zoMP327X7SIa=NTZ^Y{4;Xz-{@nv-Rdg4|&X1hZj!m8Mp{kNZ7jt%B1r*CUwVf>fI0Wi)B73cdgm zI%@$*~~pcA4#j*_J+0r zK0`B&wQ6=vGhDseoLJPZYNxb$?YLIbzN#_pnpU3EmMYD{l6F#?(@tm$T3K7t%1he& z&1sWD9iG-O9%(LjE;J9k4XuVwNL6mT7x=(5x~eO1xoNn0FpyN5j69K6BHQxvQ}jnl zl7o4+<(9PGlHBcxa}>n?tSqeCma*`_GN|F$?!ryGx`}=3E}V0y_Sn#!g&Qy!W?ip> z>$m`ps34kkEU3Pd~G31%U+dSSxjd~lEJ64DDhgY}DU|_!f9rw9G z>u^r*%8eH8Y(FjoZa;SS8YH)+<^Fcw6LRgT>$jonae6vu;Pw=Yz*zHP5Ow~Sgca^G zqk@jPfW<}JM97UM@s8OKiJj&V%qA6PlM1sb+SMdy0rEdhzzyCm*gRp~UqR&{lWGqG zt_!&bU)lGCoG(lw=Pc&!`<|!@*>I`wp3g%fc=rTvi5k2m_Rw}i$h?>N0;7i8g>cl? z24+76C4oKJk9}RpzNf|2d9MYpG@OZ0VZ2|3?+Pp2t+U$A!I>`XEbCR-ar+UnH-zlr z6xw0u=P!QfmRvt-TSy(QA8dFqJNL9NZU`AeV|U&{_Aui;A$Mr)OYh?kg`9huiOxAF zzb!c#q&b8){x;yZ(En%(>)37b@h$IiKW<;hy<2~u2(1;_{l1WU@c#aqkaO?-4YN9n zG$OmdF05lO{SEB+Mi#Pv<5k&l{tMYZd{y@0e(c{AvWFx3lI#6jLdHGz^+-Q^zx}H0 zqy5;wBV-@6H@+)m++%Ny^|SY*S7jgX$NqgG`=Gt?v5+x*H$A^`IhUXetiYjumi}OH z-idy^KOCGFPhr9}{UagopgsHJmt@3V?eC}lRLHpNSi$Eraoc|;E{X9HBwG{jQ1Ad%>t#+zkbwA&|y6LX!0*5=OlB%D`yiz#koJX32c*E*T zvU3FdGa+##t zq5eRTKm|tn2~S~EouqhVKhQ^cny47#Z>bpKCs7{ZZ>bpIC$S*DPvY(HK2b5cPx3sR zZ`Mr1aRZ{w}dLY+nu1NuI_CKS`n`s~F#JB_O;XaKv~Ewn(BA-zO>r z__s(b2=NmILi|KA8(VOzZ4nj2{3MET{w*TcOcLXfeo$bnpQsq@Co0xSWV;4!gm6Dm zUBfa-v}!{);{(FuErr@1QEli7$jW!)n&_?d=dKO!+Fct#EU9R$<>KYW0n znc$BefEYf-5QUl#p?>(O1Qde1@m@=57;7!Xq+5{Mv`~E1iUl7Jpp)V2K`Y8XA3S$J zZH?>@oyYgO`%kz<LaUcc(yh{LD_gZT;F|_c zSNOE!@Fhl)y6der;MX-S|ELng@6neDqPsi_g=eTB0EVyOz?sE8KL``>vnvnF@N*_V zu;EL};YT5UV&TUC?yYl&m3x=m&En1v-+TE+$#);VwekG|ZSNZ2FbV-*Wh|R+){P3j MWn4Uqq$Pj$|EvLP?f?J) literal 0 HcmV?d00001 diff --git a/__pycache__/cool_tokenizer.cpython-38.pyc b/__pycache__/cool_tokenizer.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..886f1ce2dd4d5dadb50b3b3069624e76e0c23916 GIT binary patch literal 1605 zcmZ`(&2Jk;6rVTy;q`VMg;KSEgk(5W?8QbPK_x5;(GqSJQfPq{Rb=f<(zW+1vunvQ z>r*0{6B0t)<75A&xpL|sz{MAMZ=5)ZT4ptGXJ_8W@BQYzecI{x49743{C4n{&Dh`c zadTMs@iorsAqv3+q%4C7G9GbY!V{LT&mgjdBiu6<*`l@2!uD&_Wg*wj55-jGx?R&N zSxB`PJ9Kn8JbYtJMlq^A6ffCJIOGBZKl2(kVNcj8ES(w});Op9@{}TaxbHS@1Nd$= zw)&>#P3shZH5A_&#em+f2FHbq^Ie?PCnyruu;<++G;q$&;RTf<( z?S1wNbBOHGIFpKeyyBYoKGjg;!b-$kTlp+gl)(CF|3#6>{v?w^s-o&YDdJfs^SbJP zu0;1lj#dA0k(Eh0j*}wqf3J!Y8P}-zSuVPzDkk{VkBcHb*izLiPqaS}NnFQhIV9dH zBFqKO0;Fy6@JjVyV<_i!Z;%%8IIV`gYr{9FASZ^3AufpJB`oey>V`jd!Ovj@KeBy{ zQCm}AJpx8gLnmwnF8dkJe!^Nnf?yQd+DheIJBMj8uA`t<5Qi_KfU9D{9wLWl4@) zD5@^qDNB{)^@iRm^fY{@ZPHZ~Oi>R+!A+GYI85eJTpFmm<)_ChCW$648%)d}_p-Ii$-Q=LZXhWl*{?G3U*%u+d| Mi#N&cTK@h20BnJ1D*ylh literal 0 HcmV?d00001 diff --git a/__pycache__/cool_visitor.cpython-38.pyc b/__pycache__/cool_visitor.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..64fa51000888fc4c8ad33da78236fedcb04ea865 GIT binary patch literal 6776 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 RS=UHxkUwyYO^fS?{sYc^AHXtmjyB-_}#W@eo< zEBA_um#8AaWuAif*jui61JsL%?~Jpy6NfVPoSic}b7tmz-<-3%)6*3LW$w@4{Le~; z@fRth#euScs-8n^8{FXLYgA$UYBx>j7Pq0>!h~)?ceo4P)w&Jc<0a@Ntvk@md;Q9rf+ZJ)E>W?L7XCjdG&7|FlT0w}l>fg)cOoS;0uEm^nWby)9UC<6yt#c;n zFjN(JvTQo0?io9?g|{0t?0tyqXC@Cf9q!=lZa&`$q>AE0KMnSABE3%bSO$?2oShzt zm_7e#Z#DgybrPinJkw63VChj1vm_R@Ki&<=Ng?g0DAb-n-9%OQAyVUavj?1e<{Mz# zvmouB{l+-={;*820DEy7*<6^!2dyYf*}h0mg}~}>J;nk!B3oExQG61#BF+@NC*n}7 zvkOa~p1_IXDD`~+vXc-S%*F0-Xu z991ipZCtpLJT7e#bb9HMAX6jeH7WEOWSX=BMN3l87>Zu561N~9#Exmi9=Bh)F&OyDz2b%2bHE6%=R%e=N6MNb6PhEH z0Y@s0ziH9jd$#p-cXKP7ex}d+u>Z)WcE|~ZHv0q7H;BQR3=C(PwaT))tl-%4^74>o zk^s-%tFdhvwA+DXhtUZpM~cNs$|S|K6;Dp#(Jb{n_^4>C<)y>^q})ChXU%f4zzFaI zUd_XTnt?D(W_p%m5xdxB_Te~u19GjH4N2}Du{R_V*`lyEBog(E5s4_dLBqy~8NHWp$AS=BRW=sv}G1#Rzc3;m+ZA9PTP~=|H zO*`E*uOwtq=cf^7448Hwj#qOKMuoBjvCMPn`QS3UcRR*I#yJhSfSHYV5RaIA4^`2n zzzQW~CHnm%>CG4cEp%?6DzZC_WZXh7vbjz1KVOQI7!mBS+X|#VjNg3%hGd~A)TTS2 zDMlIYIv7OeK4cqgxV_WDR!eWWVG zP2J}5FR+o3q*1xdK7QAU2JXh^#m(&TpNWI+@8`4*xu9%H(i@2X6I;dCiq42Sok$7= g8V)^dWXps2k(a;hf6F}4-xPFpt8TSYovkkZ3++i)ga7~l literal 0 HcmV?d00001 diff --git a/__pycache__/methods.cpython-38.pyc b/__pycache__/methods.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6b056e1e1f64ad2aa6269d387dfc94c4b935d8a1 GIT binary patch literal 2057 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 literal 0 HcmV?d00001 diff --git a/ast_nodes.py b/ast_nodes.py new file mode 100644 index 000000000..fc033fdb0 --- /dev/null +++ b/ast_nodes.py @@ -0,0 +1,182 @@ +class Node: + pass + + +class ProgramNode(Node): + def __init__(self, declarations): + self.declarations = declarations + + +class DeclarationNode(Node): + pass + + +class ExpressionNode(Node): + pass + + +class ClassDeclarationNode(DeclarationNode): + def __init__(self, idx, features, parent=None): + self.id = idx + self.parent = parent + self.features = features + + +class FuncDeclarationNode(DeclarationNode): + def __init__(self, idx, params, return_type, body): + self.id = idx + self.params = params + self.type = return_type + self.body = body + + +class AttrDeclarationNode(DeclarationNode): + def __init__(self, idx, typex, init_exp=None): + self.id = idx + self.type = typex + self.init_exp = init_exp + + +class VarDeclarationNode(ExpressionNode): + def __init__(self, idx, typex, expr=None): + self.id = idx + self.type = typex + self.expr = expr + + +class AssignNode(ExpressionNode): + def __init__(self, idx, expr): + self.id = idx + self.expr = expr + + +class LetNode(ExpressionNode): + def __init__(self, identifiers, body): + self.identifiers = identifiers + self.body = body + + +class IfNode(ExpressionNode): + def __init__(self, if_exp, then_exp, else_exp): + self.if_expr = if_exp + self.then_expr = then_exp + self.else_expr = else_exp + + +class WhileNode(ExpressionNode): + def __init__(self, condition, body): + self.condition = condition + self.body = body + + +class CaseNode(ExpressionNode): + def __init__(self, exp, case_items): + self.expr = exp + self.case_items = case_items + + +class CaseItemNode(ExpressionNode): + def __init__(self, idx, typex, exp): + self.id = idx + self.type = typex + self.expr = exp + + +# #atomic? +# class NotNode(ExpressionNode): +# def __init__(self, exp): +# self.exp = exp + +# method_name=id, args,obj,type +# aaaaaaaaaaaaaaaaaaaaaaaaaaaa que hago con estooooooooooooooooooooooooooo +class CallNode(ExpressionNode): + def __init__(self, idx, args, obj=None, at_type=None): + self.obj = obj + self.id = idx + self.args = args + self.at_type = at_type + + +class BlockNode(ExpressionNode): + def __init__(self, expresion_list): + self.expresion_list = expresion_list + + +class AtomicNode(ExpressionNode): + def __init__(self, lex): + self.lex = lex + + +class UnaryNode(ExpressionNode): + def __init__(self, expr): + self.expr = expr + + +class BinaryNode(ExpressionNode): + def __init__(self, left, right): + self.left = left + self.right = right + + +class ConstantNumNode(AtomicNode): + pass + + +class VariableNode(AtomicNode): + pass + + +class StringNode(AtomicNode): + pass + + +class BooleanTrueNode(AtomicNode): + pass + + +class BooleanFalseNode(AtomicNode): + pass + + +class InstantiateNode(AtomicNode): + pass + + +class NotNode(UnaryNode): + pass + + +class IsvoidNode(UnaryNode): + pass + + +class NegNode(UnaryNode): + pass + + +class PlusNode(BinaryNode): + pass + + +class MinusNode(BinaryNode): + pass + + +class StarNode(BinaryNode): + pass + + +class DivNode(BinaryNode): + pass + + +class LessNode(BinaryNode): + pass + + +class LessEqualNode(BinaryNode): + pass + + +class EqualNode(BinaryNode): + pass diff --git a/cmp/__init__.py b/cmp/__init__.py new file mode 100755 index 000000000..e69de29bb diff --git a/cmp/__pycache__/__init__.cpython-38.pyc b/cmp/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7b8fcc67623ee8c015d8fdbca35ac750ea185340 GIT binary patch literal 174 zcmWIL<>g`kf*{vT(IEOUh(HF6K#l_t7qb9~6oz01O-8?!3`HPe1o10aKO;XkRX-~? zH6^tuzgXWTKe;qFHLs*t-?%76p)xhGNZ&a>w;(eoF*!3oPd}h2zcMws1gOv`FGZoC pC_f9x(@)MV(2tML%*!l^kJl@xyv1RYo1apelWGUD>@yHE008m~EE)g+ literal 0 HcmV?d00001 diff --git a/cmp/__pycache__/automata.cpython-38.pyc b/cmp/__pycache__/automata.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9da1cc09533306e3eb3df4b100f0313a999d15f9 GIT binary patch literal 7952 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 literal 0 HcmV?d00001 diff --git a/cmp/__pycache__/evaluation.cpython-38.pyc b/cmp/__pycache__/evaluation.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ac0186d876671d0227a145d060fc78ea1cdcd724 GIT binary patch literal 1191 zcmZuwJ8u**5VpPE&EDRFhfsJlTo47@+#zTvq6m~60tp2~2*n8$ZPq5Ycl(O%LpkJa zIG{xQ1Sl!_7yJSWw=~cp(NO^7J(M7XrSWUN8P9w(-fp)81moxTS34glLZ9v7??K>j z9YkJ)i6Mqll;I)9c2820IYS5b4x=y7kTQ1*h2B>{q7WNraQ7xGC$>h(6Lp`nY0U3M zLUIv17V&4aVf8@PLF5IDkVc}VF$j^z8QMY$ZsxeMD}j~lp~}&C13ms&QB4&dlL--b zlv8V6?YyPh9lP%!#QjUP-UIy?&|5E__8yUHsq(cqUaA_(XPA)}NH-t_^pc!K8-SW) z`C2s?o#W>iH11hc1uD?~9E(p3?P2XKPE8=e+MGsJQwI#`=A2Y5-TD`?iuS+NaRG** zIa$P}n#{8=>|X+J&KxsmLf&9WRpU8UtwlcLw(897?Kyj^9UBW!ytEkuQHR6U$Wkh; zEW@PH<4%P&W@zF+L_h?wM22|tJqn2-y~~D*Y03o@9M#j0?f$69cz>L6#zi6f8$~?L zc&=pss$kt2k3@gH$jT&*;-tv?_e3${u>#w4KpgO^Y~6YY1@C54sk*zo zTjc4iD`&alDv3GkMoNifcdEGTi5h?6b`EhQpowiLD=RDEF+&r@g|I{!ck9;en-2_y z*p%_2vgA24PRb9AcYm<4y*@C(kx%19X=*w*B($#eHV~o^7M+{M;2`Fuy);20lU%AO zkGTm{G2!`+nw4DG;)LyCQzUyMwMf$h1t@Bgr15I3G%nc2lVRgfW!ze00-zWEPW=cS z@rW6^Td_AvzsKsxp8W6z#{ z1%&*hjt_`4aKB7Wl7O7V%UGNT+s)859jHANJg$2LShiW4Q_}u?D6#$ei`0dz3sBn~ Ywclb_N9wO;kZsD>Y#r-{Y2lXh8~V>X+5i9m literal 0 HcmV?d00001 diff --git a/cmp/__pycache__/pycompiler.cpython-38.pyc b/cmp/__pycache__/pycompiler.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6e42cbe818f5df62da6040132fed2606003cfabb GIT binary patch literal 16544 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 literal 0 HcmV?d00001 diff --git a/cmp/__pycache__/utils.cpython-38.pyc b/cmp/__pycache__/utils.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..29102a04501801bc69c343cd03445c57298e4260 GIT binary patch literal 9713 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 literal 0 HcmV?d00001 diff --git a/cmp/ast.py b/cmp/ast.py new file mode 100755 index 000000000..ec162b83b --- /dev/null +++ b/cmp/ast.py @@ -0,0 +1,62 @@ +import cmp.visitor as visitor + +class Node: + def evaluate(self): + raise NotImplementedError() + +class AtomicNode(Node): + def __init__(self, lex): + self.lex = lex + +class UnaryNode(Node): + def __init__(self, node): + self.node = node + + def evaluate(self): + value = self.node.evaluate() + return self.operate(value) + + @staticmethod + def operate(value): + raise NotImplementedError() + +class BinaryNode(Node): + def __init__(self, left, right): + self.left = left + self.right = right + + def evaluate(self): + lvalue = self.left.evaluate() + rvalue = self.right.evaluate() + return self.operate(lvalue, rvalue) + + @staticmethod + def operate(lvalue, rvalue): + raise NotImplementedError() + +def get_printer(AtomicNode=AtomicNode, UnaryNode=UnaryNode, BinaryNode=BinaryNode, ): + + class PrintVisitor(object): + @visitor.on('node') + def visit(self, node, tabs): + pass + + @visitor.when(UnaryNode) + def visit(self, node, tabs=0): + ans = '\t' * tabs + f'\\__ {node.__class__.__name__}' + child = self.visit(node.node, tabs + 1) + return f'{ans}\n{child}' + + @visitor.when(BinaryNode) + def visit(self, node, tabs=0): + ans = '\t' * tabs + f'\\__ {node.__class__.__name__} ' + left = self.visit(node.left, tabs + 1) + right = self.visit(node.right, tabs + 1) + return f'{ans}\n{left}\n{right}' + + @visitor.when(AtomicNode) + def visit(self, node, tabs=0): + return '\t' * tabs + f'\\__ {node.__class__.__name__}: {node.lex}' + + printer = PrintVisitor() + return (lambda ast: printer.visit(ast)) \ No newline at end of file diff --git a/cmp/automata.py b/cmp/automata.py new file mode 100755 index 000000000..f42b6f00c --- /dev/null +++ b/cmp/automata.py @@ -0,0 +1,207 @@ +try: + import pydot +except: + pass + +class State: + def __init__(self, state, final=False, formatter=lambda x: str(x), shape='circle'): + self.state = state + self.final = final + self.transitions = {} + self.epsilon_transitions = set() + self.tag = None + self.formatter = formatter + self.shape = shape + + # The method name is set this way from compatibility issues. + def set_formatter(self, value, attr='formatter', visited=None): + if visited is None: + visited = set() + elif self in visited: + return + + visited.add(self) + self.__setattr__(attr, value) + for destinations in self.transitions.values(): + for node in destinations: + node.set_formatter(value, attr, visited) + for node in self.epsilon_transitions: + node.set_formatter(value, attr, visited) + return self + + def has_transition(self, symbol): + return symbol in self.transitions + + def add_transition(self, symbol, state): + try: + self.transitions[symbol].append(state) + except: + self.transitions[symbol] = [state] + return self + + def add_epsilon_transition(self, state): + self.epsilon_transitions.add(state) + return self + + def recognize(self, string): + states = self.epsilon_closure + for symbol in string: + states = self.move_by_state(symbol, *states) + states = self.epsilon_closure_by_state(*states) + return any(s.final for s in states) + + def to_deterministic(self, formatter=lambda x: str(x)): + closure = self.epsilon_closure + start = State(tuple(closure), any(s.final for s in closure), formatter) + + closures = [ closure ] + states = [ start ] + pending = [ start ] + + while pending: + state = pending.pop() + symbols = { symbol for s in state.state for symbol in s.transitions } + + for symbol in symbols: + move = self.move_by_state(symbol, *state.state) + closure = self.epsilon_closure_by_state(*move) + + if closure not in closures: + new_state = State(tuple(closure), any(s.final for s in closure), formatter) + closures.append(closure) + states.append(new_state) + pending.append(new_state) + else: + index = closures.index(closure) + new_state = states[index] + + state.add_transition(symbol, new_state) + + return start + + @staticmethod + def from_nfa(nfa, get_states=False): + states = [] + for n in range(nfa.states): + state = State(n, n in nfa.finals) + states.append(state) + + for (origin, symbol), destinations in nfa.map.items(): + origin = states[origin] + origin[symbol] = [ states[d] for d in destinations ] + + if get_states: + return states[nfa.start], states + return states[nfa.start] + + @staticmethod + def move_by_state(symbol, *states): + return { s for state in states if state.has_transition(symbol) for s in state[symbol]} + + @staticmethod + def epsilon_closure_by_state(*states): + closure = { state for state in states } + + l = 0 + while l != len(closure): + l = len(closure) + tmp = [s for s in closure] + for s in tmp: + for epsilon_state in s.epsilon_transitions: + closure.add(epsilon_state) + return closure + + @property + def epsilon_closure(self): + return self.epsilon_closure_by_state(self) + + @property + def name(self): + return self.formatter(self.state) + + def get(self, symbol): + target = self.transitions[symbol] + assert len(target) == 1 + return target[0] + + def __getitem__(self, symbol): + if symbol == '': + return self.epsilon_transitions + try: + return self.transitions[symbol] + except KeyError: + return None + + def __setitem__(self, symbol, value): + if symbol == '': + self.epsilon_transitions = value + else: + self.transitions[symbol] = value + + def __repr__(self): + return str(self) + + def __str__(self): + return str(self.state) + + def __hash__(self): + return hash(self.state) + + def __iter__(self): + yield from self._visit() + + def _visit(self, visited=None): + if visited is None: + visited = set() + elif self in visited: + return + + visited.add(self) + yield self + + for destinations in self.transitions.values(): + for node in destinations: + yield from node._visit(visited) + for node in self.epsilon_transitions: + yield from node._visit(visited) + + def graph(self): + G = pydot.Dot(rankdir='LR', margin=0.1) + G.add_node(pydot.Node('start', shape='plaintext', label='', width=0, height=0)) + + visited = set() + def visit(start): + ids = id(start) + if ids not in visited: + visited.add(ids) + G.add_node(pydot.Node(ids, label=start.name, shape=self.shape, style='bold' if start.final else '')) + for tran, destinations in start.transitions.items(): + for end in destinations: + visit(end) + G.add_edge(pydot.Edge(ids, id(end), label=tran, labeldistance=2)) + for end in start.epsilon_transitions: + visit(end) + G.add_edge(pydot.Edge(ids, id(end), label='ε', labeldistance=2)) + + visit(self) + G.add_edge(pydot.Edge('start', id(self), label='', style='dashed')) + + return G + + def _repr_svg_(self): + try: + return self.graph().create_svg().decode('utf8') + except: + pass + + def write_to(self, fname): + return self.graph().write_svg(fname) + +def multiline_formatter(state): + return '\n'.join(str(item) for item in state) + +def lr0_formatter(state): + try: + return '\n'.join(str(item)[:-4] for item in state) + except TypeError: + return str(state)[:-4] \ No newline at end of file diff --git a/cmp/cil.py b/cmp/cil.py new file mode 100755 index 000000000..de6782c16 --- /dev/null +++ b/cmp/cil.py @@ -0,0 +1,231 @@ +import cmp.visitor as visitor + + +class Node: + pass + +class ProgramNode(Node): + def __init__(self, dottypes, dotdata, dotcode): + self.dottypes = dottypes + self.dotdata = dotdata + self.dotcode = dotcode + +class TypeNode(Node): + def __init__(self, name): + self.name = name + self.attributes = [] + self.methods = [] + +class DataNode(Node): + def __init__(self, vname, value): + self.name = vname + self.value = value + +class FunctionNode(Node): + def __init__(self, fname, params, localvars, instructions): + self.name = fname + self.params = params + self.localvars = localvars + self.instructions = instructions + +class ParamNode(Node): + def __init__(self, name): + self.name = name + +class LocalNode(Node): + def __init__(self, name): + self.name = name + +class InstructionNode(Node): + pass + +class AssignNode(InstructionNode): + def __init__(self, dest, source): + self.dest = dest + self.source = source + +class ArithmeticNode(InstructionNode): + def __init__(self, dest, left, right): + self.dest = dest + self.left = left + self.right = right + +class PlusNode(ArithmeticNode): + pass + +class MinusNode(ArithmeticNode): + pass + +class StarNode(ArithmeticNode): + pass + +class DivNode(ArithmeticNode): + pass + +class GetAttribNode(InstructionNode): + pass + +class SetAttribNode(InstructionNode): + pass + +class GetIndexNode(InstructionNode): + pass + +class SetIndexNode(InstructionNode): + pass + +class AllocateNode(InstructionNode): + def __init__(self, itype, dest): + self.type = itype + self.dest = dest + +class ArrayNode(InstructionNode): + pass + +class TypeOfNode(InstructionNode): + def __init__(self, obj, dest): + self.obj = obj + self.dest = dest + +class LabelNode(InstructionNode): + pass + +class GotoNode(InstructionNode): + pass + +class GotoIfNode(InstructionNode): + pass + +class StaticCallNode(InstructionNode): + def __init__(self, function, dest): + self.function = function + self.dest = dest + +class DynamicCallNode(InstructionNode): + def __init__(self, xtype, method, dest): + self.type = xtype + self.method = method + self.dest = dest + +class ArgNode(InstructionNode): + def __init__(self, name): + self.name = name + +class ReturnNode(InstructionNode): + def __init__(self, value=None): + self.value = value + +class LoadNode(InstructionNode): + def __init__(self, dest, msg): + self.dest = dest + self.msg = msg + +class LengthNode(InstructionNode): + pass + +class ConcatNode(InstructionNode): + pass + +class PrefixNode(InstructionNode): + pass + +class SubstringNode(InstructionNode): + pass + +class ToStrNode(InstructionNode): + def __init__(self, dest, ivalue): + self.dest = dest + self.ivalue = ivalue + +class ReadNode(InstructionNode): + def __init__(self, dest): + self.dest = dest + +class PrintNode(InstructionNode): + def __init__(self, str_addr): + self.str_addr = str_addr + +def get_formatter(): + + class PrintVisitor(object): + @visitor.on('node') + def visit(self, node): + pass + + @visitor.when(ProgramNode) + def visit(self, node): + dottypes = '\n'.join(self.visit(t) for t in node.dottypes) + dotdata = '\n'.join(self.visit(t) for t in node.dotdata) + dotcode = '\n'.join(self.visit(t) for t in node.dotcode) + + return f'.TYPES\n{dottypes}\n\n.DATA\n{dotdata}\n\n.CODE\n{dotcode}' + + @visitor.when(TypeNode) + def visit(self, node): + attributes = '\n\t'.join(f'attribute {x}' for x in node.attributes) + methods = '\n\t'.join(f'method {x}: {y}' for x,y in node.methods) + + return f'type {node.name} {{\n\t{attributes}\n\n\t{methods}\n}}' + + @visitor.when(FunctionNode) + def visit(self, node): + params = '\n\t'.join(self.visit(x) for x in node.params) + localvars = '\n\t'.join(self.visit(x) for x in node.localvars) + instructions = '\n\t'.join(self.visit(x) for x in node.instructions) + + return f'function {node.name} {{\n\t{params}\n\n\t{localvars}\n\n\t{instructions}\n}}' + + @visitor.when(ParamNode) + def visit(self, node): + return f'PARAM {node.name}' + + @visitor.when(LocalNode) + def visit(self, node): + return f'LOCAL {node.name}' + + @visitor.when(AssignNode) + def visit(self, node): + return f'{node.dest} = {node.source}' + + @visitor.when(PlusNode) + def visit(self, node): + return f'{node.dest} = {node.left} + {node.right}' + + @visitor.when(MinusNode) + def visit(self, node): + return f'{node.dest} = {node.left} - {node.right}' + + @visitor.when(StarNode) + def visit(self, node): + return f'{node.dest} = {node.left} * {node.right}' + + @visitor.when(DivNode) + def visit(self, node): + return f'{node.dest} = {node.left} / {node.right}' + + @visitor.when(AllocateNode) + def visit(self, node): + return f'{node.dest} = ALLOCATE {node.type}' + + @visitor.when(TypeOfNode) + def visit(self, node): + return f'{node.dest} = TYPEOF {node.type}' + + @visitor.when(StaticCallNode) + def visit(self, node): + return f'{node.dest} = CALL {node.function}' + + @visitor.when(DynamicCallNode) + def visit(self, node): + return f'{node.dest} = VCALL {node.type} {node.method}' + + @visitor.when(ArgNode) + def visit(self, node): + return f'ARG {node.name}' + + @visitor.when(ReturnNode) + def visit(self, node): + return f'RETURN {node.value if node.value is not None else ""}' + + printer = PrintVisitor() + return (lambda ast: printer.visit(ast)) \ No newline at end of file diff --git a/cmp/evaluation.py b/cmp/evaluation.py new file mode 100755 index 000000000..0581e1841 --- /dev/null +++ b/cmp/evaluation.py @@ -0,0 +1,36 @@ +from cmp.pycompiler import EOF +from shift_reduce_parsers import ShiftReduceParser + + +def evaluate_reverse_parse(right_parse, operations, tokens): + if not right_parse or not operations or not tokens: + return + + right_parse = iter(right_parse) + tokens = iter(tokens) + stack = [] + for operation in operations: + if operation == ShiftReduceParser.SHIFT: + token = next(tokens) + stack.append(token.lex) + elif operation == ShiftReduceParser.REDUCE: + production = next(right_parse) + head, body = production + attributes = production.attributes + assert all( + rule is None for rule in attributes[1:] + ), "There must be only synteticed attributes." + rule = attributes[0] + + if len(body): + synteticed = [None] + stack[-len(body) :] + value = rule(None, synteticed) + stack[-len(body) :] = [value] + else: + stack.append(rule(None, None)) + else: + raise Exception("Invalid action!!!") + + assert len(stack) == 1 + assert isinstance(next(tokens).token_type, EOF) + return stack[0] diff --git a/cmp/languages.py b/cmp/languages.py new file mode 100755 index 000000000..e2c0c33da --- /dev/null +++ b/cmp/languages.py @@ -0,0 +1,228 @@ +from cmp.pycompiler import Sentence, Production +from cmp.utils import ContainerSet, Token, UnknownToken +from cmp.tools.parsing import build_parsing_table, metodo_predictivo_no_recursivo + +class BasicXCool: + def __init__(self, G): + self.G = G + self.fixed_tokens = { lex: Token(lex, G[lex]) for lex in '+ - * / ( )'.split() } + + @property + def firsts(self): + G = self.G + return { + G['+']: ContainerSet(G['+'] , contains_epsilon=False), + G['-']: ContainerSet(G['-'] , contains_epsilon=False), + G['*']: ContainerSet(G['*'] , contains_epsilon=False), + G['/']: ContainerSet(G['/'] , contains_epsilon=False), + G['(']: ContainerSet(G['('] , contains_epsilon=False), + G[')']: ContainerSet(G[')'] , contains_epsilon=False), + G['num']: ContainerSet(G['num'] , contains_epsilon=False), + G['E']: ContainerSet(G['num'], G['('] , contains_epsilon=False), + G['T']: ContainerSet(G['num'], G['('] , contains_epsilon=False), + G['F']: ContainerSet(G['num'], G['('] , contains_epsilon=False), + G['X']: ContainerSet(G['-'], G['+'] , contains_epsilon=True), + G['Y']: ContainerSet(G['/'], G['*'] , contains_epsilon=True), + Sentence(G['T'], G['X']): ContainerSet(G['num'], G['('] , contains_epsilon=False), + Sentence(G['+'], G['T'], G['X']): ContainerSet(G['+'] , contains_epsilon=False), + Sentence(G['-'], G['T'], G['X']): ContainerSet(G['-'] , contains_epsilon=False), + G.Epsilon: ContainerSet( contains_epsilon=True), + Sentence(G['F'], G['Y']): ContainerSet(G['num'], G['('] , contains_epsilon=False), + Sentence(G['*'], G['F'], G['Y']): ContainerSet(G['*'] , contains_epsilon=False), + Sentence(G['/'], G['F'], G['Y']): ContainerSet(G['/'] , contains_epsilon=False), + Sentence(G['num']): ContainerSet(G['num'] , contains_epsilon=False), + Sentence(G['('], G['E'], G[')']): ContainerSet(G['('] , contains_epsilon=False) + } + + @property + def follows(self): + G = self.G + return { + G['E']: ContainerSet(G[')'], G.EOF , contains_epsilon=False), + G['T']: ContainerSet(G[')'], G['-'], G.EOF, G['+'] , contains_epsilon=False), + G['F']: ContainerSet(G['-'], G.EOF, G['*'], G['/'], G[')'], G['+'] , contains_epsilon=False), + G['X']: ContainerSet(G[')'], G.EOF , contains_epsilon=False), + G['Y']: ContainerSet(G[')'], G['-'], G.EOF, G['+'] , contains_epsilon=False) + } + + @property + def table(self): + G = self.G + return { + ( G['E'], G['num'], ): [ Production(G['E'], Sentence(G['T'], G['X'])), ], + ( G['E'], G['('], ): [ Production(G['E'], Sentence(G['T'], G['X'])), ], + ( G['X'], G['+'], ): [ Production(G['X'], Sentence(G['+'], G['T'], G['X'])), ], + ( G['X'], G['-'], ): [ Production(G['X'], Sentence(G['-'], G['T'], G['X'])), ], + ( G['X'], G[')'], ): [ Production(G['X'], G.Epsilon), ], + ( G['X'], G.EOF, ): [ Production(G['X'], G.Epsilon), ], + ( G['T'], G['num'], ): [ Production(G['T'], Sentence(G['F'], G['Y'])), ], + ( G['T'], G['('], ): [ Production(G['T'], Sentence(G['F'], G['Y'])), ], + ( G['Y'], G['*'], ): [ Production(G['Y'], Sentence(G['*'], G['F'], G['Y'])), ], + ( G['Y'], G['/'], ): [ Production(G['Y'], Sentence(G['/'], G['F'], G['Y'])), ], + ( G['Y'], G[')'], ): [ Production(G['Y'], G.Epsilon), ], + ( G['Y'], G['-'], ): [ Production(G['Y'], G.Epsilon), ], + ( G['Y'], G.EOF, ): [ Production(G['Y'], G.Epsilon), ], + ( G['Y'], G['+'], ): [ Production(G['Y'], G.Epsilon), ], + ( G['F'], G['num'], ): [ Production(G['F'], Sentence(G['num'])), ], + ( G['F'], G['('], ): [ Production(G['F'], Sentence(G['('], G['E'], G[')'])), ] + } + + @property + def tokenizer(self): + G = self.G + fixed_tokens = self.fixed_tokens + + def tokenize_text(text): + tokens = [] + for item in text.split(): + try: + float(item) + token = Token(item, G['num']) + except ValueError: + try: + token = fixed_tokens[item] + except: + token = UnknownToken(item) + tokens.append(token) + eof = Token('$', G.EOF) + tokens.append(eof) + return tokens + + return tokenize_text + +class PowXCool: + def __init__(self, G): + self.G = G + + @property + def firsts(self): + G = self.G + return { + G['+']: ContainerSet(G['+'] , contains_epsilon=False), + G['-']: ContainerSet(G['-'] , contains_epsilon=False), + G['*']: ContainerSet(G['*'] , contains_epsilon=False), + G['/']: ContainerSet(G['/'] , contains_epsilon=False), + G['^']: ContainerSet(G['^'] , contains_epsilon=False), + G['(']: ContainerSet(G['('] , contains_epsilon=False), + G[')']: ContainerSet(G[')'] , contains_epsilon=False), + G['num']: ContainerSet(G['num'] , contains_epsilon=False), + G['E']: ContainerSet(G['num'], G['('] , contains_epsilon=False), + G['T']: ContainerSet(G['num'], G['('] , contains_epsilon=False), + G['F']: ContainerSet(G['num'], G['('] , contains_epsilon=False), + G['A']: ContainerSet(G['num'], G['('] , contains_epsilon=False), + G['X']: ContainerSet(G['-'], G['+'] , contains_epsilon=True), + G['Y']: ContainerSet(G['/'], G['*'] , contains_epsilon=True), + G['Z']: ContainerSet(G['^'] , contains_epsilon=True), + Sentence(G['T'], G['X']): ContainerSet(G['num'], G['('] , contains_epsilon=False), + Sentence(G['+'], G['T'], G['X']): ContainerSet(G['+'] , contains_epsilon=False), + Sentence(G['-'], G['T'], G['X']): ContainerSet(G['-'] , contains_epsilon=False), + G.Epsilon: ContainerSet( contains_epsilon=True), + Sentence(G['F'], G['Y']): ContainerSet(G['num'], G['('] , contains_epsilon=False), + Sentence(G['*'], G['F'], G['Y']): ContainerSet(G['*'] , contains_epsilon=False), + Sentence(G['/'], G['F'], G['Y']): ContainerSet(G['/'] , contains_epsilon=False), + Sentence(G['A'], G['Z']): ContainerSet(G['num'], G['('] , contains_epsilon=False), + Sentence(G['^'], G['F']): ContainerSet(G['^'] , contains_epsilon=False), + Sentence(G['num']): ContainerSet(G['num'] , contains_epsilon=False), + Sentence(G['('], G['E'], G[')']): ContainerSet(G['('] , contains_epsilon=False) + } + + @property + def follows(self): + G = self.G + return { + G['E']: ContainerSet(G[')'], G.EOF , contains_epsilon=False), + G['T']: ContainerSet(G['-'], G[')'], G.EOF, G['+'] , contains_epsilon=False), + G['F']: ContainerSet(G['-'], G['*'], G['/'], G[')'], G.EOF, G['+'] , contains_epsilon=False), + G['A']: ContainerSet(G['-'], G['*'], G['/'], G['^'], G[')'], G.EOF, G['+'] , contains_epsilon=False), + G['X']: ContainerSet(G[')'], G.EOF , contains_epsilon=False), + G['Y']: ContainerSet(G['-'], G[')'], G.EOF, G['+'] , contains_epsilon=False), + G['Z']: ContainerSet(G['-'], G['*'], G['/'], G[')'], G.EOF, G['+'] , contains_epsilon=False) + } + +class Regex: + def __init__(self, G): + self.G = G + + @property + def firsts(self): + G = self.G + return { + G['|']: ContainerSet(G['|'] , contains_epsilon=False), + G['*']: ContainerSet(G['*'] , contains_epsilon=False), + G['(']: ContainerSet(G['('] , contains_epsilon=False), + G[')']: ContainerSet(G[')'] , contains_epsilon=False), + G['symbol']: ContainerSet(G['symbol'] , contains_epsilon=False), + G['ε']: ContainerSet(G['ε'] , contains_epsilon=False), + G['E']: ContainerSet(G['symbol'], G['ε'], G['('] , contains_epsilon=False), + G['T']: ContainerSet(G['symbol'], G['ε'], G['('] , contains_epsilon=False), + G['F']: ContainerSet(G['symbol'], G['ε'], G['('] , contains_epsilon=False), + G['A']: ContainerSet(G['ε'], G['symbol'], G['('] , contains_epsilon=False), + G['X']: ContainerSet(G['|'] , contains_epsilon=True), + G['Y']: ContainerSet(G['symbol'], G['ε'], G['('] , contains_epsilon=True), + G['Z']: ContainerSet(G['*'] , contains_epsilon=True), + Sentence(G['T'], G['X']): ContainerSet(G['symbol'], G['ε'], G['('] , contains_epsilon=False), + Sentence(G['|'], G['E']): ContainerSet(G['|'] , contains_epsilon=False), + G.Epsilon: ContainerSet( contains_epsilon=True), + Sentence(G['F'], G['Y']): ContainerSet(G['symbol'], G['ε'], G['('] , contains_epsilon=False), + Sentence(G['T']): ContainerSet(G['symbol'], G['ε'], G['('] , contains_epsilon=False), + Sentence(G['A'], G['Z']): ContainerSet(G['symbol'], G['ε'], G['('] , contains_epsilon=False), + Sentence(G['*']): ContainerSet(G['*'] , contains_epsilon=False), + Sentence(G['symbol']): ContainerSet(G['symbol'] , contains_epsilon=False), + Sentence(G['ε']): ContainerSet(G['ε'] , contains_epsilon=False), + Sentence(G['('], G['E'], G[')']): ContainerSet(G['('] , contains_epsilon=False) + } + + @property + def follows(self): + G = self.G + return { + G['E']: ContainerSet(G[')'], G.EOF , contains_epsilon=False), + G['T']: ContainerSet(G[')'], G.EOF, G['|'] , contains_epsilon=False), + G['F']: ContainerSet(G[')'], G.EOF, G['symbol'], G['|'], G['ε'], G['('] , contains_epsilon=False), + G['A']: ContainerSet(G.EOF, G['|'], G['*'], G['('], G[')'], G['symbol'], G['ε'] , contains_epsilon=False), + G['X']: ContainerSet(G[')'], G.EOF , contains_epsilon=False), + G['Y']: ContainerSet(G[')'], G.EOF, G['|'] , contains_epsilon=False), + G['Z']: ContainerSet(G.EOF, G['|'], G['('], G[')'], G['symbol'], G['ε'] , contains_epsilon=False) + } + + @property + def table(self): + G = self.G + return { + ( G['E'], G['symbol'], ): [ Production(G['E'], Sentence(G['T'], G['X'])), ], + ( G['E'], G['ε'], ): [ Production(G['E'], Sentence(G['T'], G['X'])), ], + ( G['E'], G['('], ): [ Production(G['E'], Sentence(G['T'], G['X'])), ], + ( G['X'], G['|'], ): [ Production(G['X'], Sentence(G['|'], G['E'])), ], + ( G['X'], G[')'], ): [ Production(G['X'], G.Epsilon), ], + ( G['X'], G.EOF, ): [ Production(G['X'], G.Epsilon), ], + ( G['T'], G['symbol'], ): [ Production(G['T'], Sentence(G['F'], G['Y'])), ], + ( G['T'], G['ε'], ): [ Production(G['T'], Sentence(G['F'], G['Y'])), ], + ( G['T'], G['('], ): [ Production(G['T'], Sentence(G['F'], G['Y'])), ], + ( G['Y'], G['symbol'], ): [ Production(G['Y'], Sentence(G['T'])), ], + ( G['Y'], G['ε'], ): [ Production(G['Y'], Sentence(G['T'])), ], + ( G['Y'], G['('], ): [ Production(G['Y'], Sentence(G['T'])), ], + ( G['Y'], G[')'], ): [ Production(G['Y'], G.Epsilon), ], + ( G['Y'], G.EOF, ): [ Production(G['Y'], G.Epsilon), ], + ( G['Y'], G['|'], ): [ Production(G['Y'], G.Epsilon), ], + ( G['F'], G['symbol'], ): [ Production(G['F'], Sentence(G['A'], G['Z'])), ], + ( G['F'], G['ε'], ): [ Production(G['F'], Sentence(G['A'], G['Z'])), ], + ( G['F'], G['('], ): [ Production(G['F'], Sentence(G['A'], G['Z'])), ], + ( G['Z'], G['*'], ): [ Production(G['Z'], Sentence(G['*'])), ], + ( G['Z'], G.EOF, ): [ Production(G['Z'], G.Epsilon), ], + ( G['Z'], G['|'], ): [ Production(G['Z'], G.Epsilon), ], + ( G['Z'], G['('], ): [ Production(G['Z'], G.Epsilon), ], + ( G['Z'], G[')'], ): [ Production(G['Z'], G.Epsilon), ], + ( G['Z'], G['symbol'], ): [ Production(G['Z'], G.Epsilon), ], + ( G['Z'], G['ε'], ): [ Production(G['Z'], G.Epsilon), ], + ( G['A'], G['symbol'], ): [ Production(G['A'], Sentence(G['symbol'])), ], + ( G['A'], G['ε'], ): [ Production(G['A'], Sentence(G['ε'])), ], + ( G['A'], G['('], ): [ Production(G['A'], Sentence(G['('], G['E'], G[')'])), ] + } + + @property + def parser(self): + firsts = self.firsts + follows = self.follows + M = build_parsing_table(self.G, firsts, follows) + parser = metodo_predictivo_no_recursivo(self.G, M) + return parser \ No newline at end of file diff --git a/cmp/nbpackage.py b/cmp/nbpackage.py new file mode 100755 index 000000000..e89c62ad3 --- /dev/null +++ b/cmp/nbpackage.py @@ -0,0 +1,87 @@ +import io, os, sys, types + +from IPython import get_ipython +from nbformat import read +from IPython.core.interactiveshell import InteractiveShell + +def find_notebook(fullname, path=None): + """find a notebook, given its fully qualified name and an optional path + + This turns "foo.bar" into "foo/bar.ipynb" + and tries turning "Foo_Bar" into "Foo Bar" if Foo_Bar + does not exist. + """ + name = fullname.rsplit('.', 1)[-1] + if not path: + path = [''] + for d in path: + nb_path = os.path.join(d, name + ".ipynb") + if os.path.isfile(nb_path): + return nb_path + # let import Notebook_Name find "Notebook Name.ipynb" + nb_path = nb_path.replace("_", " ") + if os.path.isfile(nb_path): + return nb_path + +class NotebookLoader(object): + """Module Loader for Jupyter Notebooks""" + def __init__(self, path=None): + self.shell = InteractiveShell.instance() + self.path = path + + def load_module(self, fullname): + """import a notebook as a module""" + path = find_notebook(fullname, self.path) + + print ("importing Jupyter notebook from %s" % path) + + # load the notebook object + with io.open(path, 'r', encoding='utf-8') as f: + nb = read(f, 4) + + + # create the module and add it to sys.modules + # if name in sys.modules: + # return sys.modules[name] + mod = types.ModuleType(fullname) + mod.__file__ = path + mod.__loader__ = self + mod.__dict__['get_ipython'] = get_ipython + sys.modules[fullname] = mod + + # extra work to ensure that magics that would affect the user_ns + # actually affect the notebook module's ns + save_user_ns = self.shell.user_ns + self.shell.user_ns = mod.__dict__ + + try: + for cell in nb.cells: + if cell.cell_type == 'code': + # transform the input to executable Python + code = self.shell.input_transformer_manager.transform_cell(cell.source) + # run the code in themodule + exec(code, mod.__dict__) + finally: + self.shell.user_ns = save_user_ns + return mod + +class NotebookFinder(object): + """Module finder that locates Jupyter Notebooks""" + def __init__(self): + self.loaders = {} + + def find_module(self, fullname, path=None): + nb_path = find_notebook(fullname, path) + if not nb_path: + return + + key = path + if path: + # lists aren't hashable + key = os.path.sep.join(path) + + if key not in self.loaders: + self.loaders[key] = NotebookLoader(path) + return self.loaders[key] + +sys.meta_path.append(NotebookFinder()) \ No newline at end of file diff --git a/cmp/pycompiler.py b/cmp/pycompiler.py new file mode 100755 index 000000000..3ef02deeb --- /dev/null +++ b/cmp/pycompiler.py @@ -0,0 +1,512 @@ +import json + +class Symbol(object): + + def __init__(self, name, grammar): + self.Name = name + self.Grammar = grammar + + def __str__(self): + return self.Name + + def __repr__(self): + return repr(self.Name) + + def __add__(self, other): + if isinstance(other, Symbol): + return Sentence(self, other) + + raise TypeError(other) + + def __or__(self, other): + + if isinstance(other, (Sentence)): + return SentenceList(Sentence(self), other) + + raise TypeError(other) + + @property + def IsEpsilon(self): + return False + + def __len__(self): + return 1 + +class NonTerminal(Symbol): + + + def __init__(self, name, grammar): + super().__init__(name, grammar) + self.productions = [] + + + def __imod__(self, other): + + if isinstance(other, (Sentence)): + p = Production(self, other) + self.Grammar.Add_Production(p) + return self + + if isinstance(other, tuple): + assert len(other) > 1 + + if len(other) == 2: + other += (None,) * len(other[0]) + + assert len(other) == len(other[0]) + 2, "Debe definirse una, y solo una, regla por cada símbolo de la producción" + # assert len(other) == 2, "Tiene que ser una Tupla de 2 elementos (sentence, attribute)" + + if isinstance(other[0], Symbol) or isinstance(other[0], Sentence): + p = AttributeProduction(self, other[0], other[1:]) + else: + raise Exception("") + + self.Grammar.Add_Production(p) + return self + + if isinstance(other, Symbol): + p = Production(self, Sentence(other)) + self.Grammar.Add_Production(p) + return self + + if isinstance(other, SentenceList): + + for s in other: + p = Production(self, s) + self.Grammar.Add_Production(p) + + return self + + raise TypeError(other) + + @property + def IsTerminal(self): + return False + + @property + def IsNonTerminal(self): + return True + + @property + def IsEpsilon(self): + return False + +class Terminal(Symbol): + + def __init__(self, name, grammar): + super().__init__(name, grammar) + + @property + def IsTerminal(self): + return True + + @property + def IsNonTerminal(self): + return False + + @property + def IsEpsilon(self): + return False + +class EOF(Terminal): + + def __init__(self, Grammar): + super().__init__('$', Grammar) + +class Sentence(object): + + def __init__(self, *args): + self._symbols = tuple(x for x in args if not x.IsEpsilon) + self.hash = hash(self._symbols) + + def __len__(self): + return len(self._symbols) + + def __add__(self, other): + if isinstance(other, Symbol): + return Sentence(*(self._symbols + (other,))) + + if isinstance(other, Sentence): + return Sentence(*(self._symbols + other._symbols)) + + raise TypeError(other) + + def __or__(self, other): + if isinstance(other, Sentence): + return SentenceList(self, other) + + if isinstance(other, Symbol): + return SentenceList(self, Sentence(other)) + + raise TypeError(other) + + def __repr__(self): + return str(self) + + def __str__(self): + return ("%s " * len(self._symbols) % tuple(self._symbols)).strip() + + def __iter__(self): + return iter(self._symbols) + + def __getitem__(self, index): + return self._symbols[index] + + def __eq__(self, other): + return self._symbols == other._symbols + + def __hash__(self): + return self.hash + + @property + def IsEpsilon(self): + return False + +class SentenceList(object): + + def __init__(self, *args): + self._sentences = list(args) + + def Add(self, symbol): + if not symbol and (symbol is None or not symbol.IsEpsilon): + raise ValueError(symbol) + + self._sentences.append(symbol) + + def __iter__(self): + return iter(self._sentences) + + def __or__(self, other): + if isinstance(other, Sentence): + self.Add(other) + return self + + if isinstance(other, Symbol): + return self | Sentence(other) + + +class Epsilon(Terminal, Sentence): + + def __init__(self, grammar): + super().__init__('epsilon', grammar) + + + def __str__(self): + return "e" + + def __repr__(self): + return 'epsilon' + + def __iter__(self): + yield from () + + def __len__(self): + return 0 + + def __add__(self, other): + return other + + def __eq__(self, other): + return isinstance(other, (Epsilon,)) + + def __hash__(self): + return hash("") + + @property + def IsEpsilon(self): + return True + +class Production(object): + + def __init__(self, nonTerminal, sentence): + + self.Left = nonTerminal + self.Right = sentence + + def __str__(self): + + return '%s := %s' % (self.Left, self.Right) + + def __repr__(self): + return '%s -> %s' % (self.Left, self.Right) + + def __iter__(self): + yield self.Left + yield self.Right + + def __eq__(self, other): + return isinstance(other, Production) and self.Left == other.Left and self.Right == other.Right + + def __hash__(self): + return hash((self.Left, self.Right)) + + @property + def IsEpsilon(self): + return self.Right.IsEpsilon + +class AttributeProduction(Production): + + def __init__(self, nonTerminal, sentence, attributes): + if not isinstance(sentence, Sentence) and isinstance(sentence, Symbol): + sentence = Sentence(sentence) + super(AttributeProduction, self).__init__(nonTerminal, sentence) + + self.attributes = attributes + + def __str__(self): + return '%s := %s' % (self.Left, self.Right) + + def __repr__(self): + return '%s -> %s' % (self.Left, self.Right) + + def __iter__(self): + yield self.Left + yield self.Right + + + @property + def IsEpsilon(self): + return self.Right.IsEpsilon + + # sintetizar en ingles??????, pending aggrement + def syntetice(self): + pass + +class Grammar(): + + def __init__(self): + + self.Productions = [] + self.nonTerminals = [] + self.terminals = [] + self.startSymbol = None + # production type + self.pType = None + self.Epsilon = Epsilon(self) + self.EOF = EOF(self) + + self.symbDict = { '$': self.EOF } + + def NonTerminal(self, name, startSymbol = False): + + name = name.strip() + if not name: + raise Exception("Empty name") + + term = NonTerminal(name,self) + + if startSymbol: + + if self.startSymbol is None: + self.startSymbol = term + else: + raise Exception("Cannot define more than one start symbol.") + + self.nonTerminals.append(term) + self.symbDict[name] = term + return term + + def NonTerminals(self, names): + + ans = tuple((self.NonTerminal(x) for x in names.strip().split())) + + return ans + + + def Add_Production(self, production): + + if len(self.Productions) == 0: + self.pType = type(production) + + assert type(production) == self.pType, "The Productions most be of only 1 type." + + production.Left.productions.append(production) + self.Productions.append(production) + + + def Terminal(self, name): + + name = name.strip() + if not name: + raise Exception("Empty name") + + term = Terminal(name, self) + self.terminals.append(term) + self.symbDict[name] = term + return term + + def Terminals(self, names): + + ans = tuple((self.Terminal(x) for x in names.strip().split())) + + return ans + + + def __str__(self): + + mul = '%s, ' + + ans = 'Non-Terminals:\n\t' + + nonterminals = mul * (len(self.nonTerminals)-1) + '%s\n' + + ans += nonterminals % tuple(self.nonTerminals) + + ans += 'Terminals:\n\t' + + terminals = mul * (len(self.terminals)-1) + '%s\n' + + ans += terminals % tuple(self.terminals) + + ans += 'Productions:\n\t' + + ans += str(self.Productions) + + return ans + + def __getitem__(self, name): + try: + return self.symbDict[name] + except KeyError: + return None + + @property + def to_json(self): + + productions = [] + + for p in self.Productions: + head = p.Left.Name + + body = [] + + for s in p.Right: + body.append(s.Name) + + productions.append({'Head':head, 'Body':body}) + + d={'NonTerminals':[symb.Name for symb in self.nonTerminals], 'Terminals': [symb.Name for symb in self.terminals],\ + 'Productions':productions} + + # [{'Head':p.Left.Name, "Body": [s.Name for s in p.Right]} for p in self.Productions] + return json.dumps(d) + + @staticmethod + def from_json(data): + data = json.loads(data) + + G = Grammar() + dic = {'epsilon':G.Epsilon} + + for term in data['Terminals']: + dic[term] = G.Terminal(term) + + for noTerm in data['NonTerminals']: + dic[noTerm] = G.NonTerminal(noTerm) + + for p in data['Productions']: + head = p['Head'] + dic[head] %= Sentence(*[dic[term] for term in p['Body']]) + + return G + + def copy(self): + G = Grammar() + G.Productions = self.Productions.copy() + G.nonTerminals = self.nonTerminals.copy() + G.terminals = self.terminals.copy() + G.pType = self.pType + G.startSymbol = self.startSymbol + G.Epsilon = self.Epsilon + G.EOF = self.EOF + G.symbDict = self.symbDict.copy() + + return G + + @property + def IsAugmentedGrammar(self): + augmented = 0 + for left, right in self.Productions: + if self.startSymbol == left: + augmented += 1 + if augmented <= 1: + return True + else: + return False + + def AugmentedGrammar(self, force=False): + if not self.IsAugmentedGrammar or force: + + G = self.copy() + # S, self.startSymbol, SS = self.startSymbol, None, self.NonTerminal('S\'', True) + S = G.startSymbol + G.startSymbol = None + SS = G.NonTerminal('S\'', True) + if G.pType is AttributeProduction: + SS %= S + G.Epsilon, lambda x : x + else: + SS %= S + G.Epsilon + + return G + else: + return self.copy() + #endchange + +class Item: + + def __init__(self, production, pos, lookaheads=[]): + self.production = production + self.pos = pos + self.lookaheads = frozenset(look for look in lookaheads) + + def __str__(self): + s = str(self.production.Left) + " -> " + if len(self.production.Right) > 0: + for i,c in enumerate(self.production.Right): + if i == self.pos: + s += "." + s += str(self.production.Right[i]) + if self.pos == len(self.production.Right): + s += "." + else: + s += "." + s += ", " + str(self.lookaheads)[10:-1] + return s + + def __repr__(self): + return str(self) + + + def __eq__(self, other): + return ( + (self.pos == other.pos) and + (self.production == other.production) and + (set(self.lookaheads) == set(other.lookaheads)) + ) + + def __hash__(self): + return hash((self.production,self.pos,self.lookaheads)) + + @property + def IsReduceItem(self): + return len(self.production.Right) == self.pos + + @property + def NextSymbol(self): + if self.pos < len(self.production.Right): + return self.production.Right[self.pos] + else: + return None + + def NextItem(self): + if self.pos < len(self.production.Right): + return Item(self.production,self.pos+1,self.lookaheads) + else: + return None + + def Preview(self, skip=1): + unseen = self.production.Right[self.pos+skip:] + return [ unseen + (lookahead,) for lookahead in self.lookaheads ] + + def Center(self): + return Item(self.production, self.pos) \ No newline at end of file diff --git a/cmp/semantic.py b/cmp/semantic.py new file mode 100755 index 000000000..9279bda3c --- /dev/null +++ b/cmp/semantic.py @@ -0,0 +1,214 @@ +import itertools as itt +from collections import OrderedDict + + +class SemanticError(Exception): + @property + def text(self): + return self.args[0] + +class Attribute: + def __init__(self, name, typex): + self.name = name + self.type = typex + + def __str__(self): + return f'[attrib] {self.name} : {self.type.name};' + + def __repr__(self): + return str(self) + +class Method: + def __init__(self, name, param_names, params_types, return_type): + self.name = name + self.param_names = param_names + self.param_types = params_types + self.return_type = return_type + + def __str__(self): + params = ', '.join(f'{n}:{t.name}' for n,t in zip(self.param_names, self.param_types)) + return f'[method] {self.name}({params}): {self.return_type.name};' + + def __eq__(self, other): + return other.name == self.name and \ + other.return_type == self.return_type and \ + other.param_types == self.param_types + +class Type: + def __init__(self, name:str): + self.name = name + self.attributes = [] + self.methods = [] + self.parent = None + + def set_parent(self, parent): + if self.parent is not None: + raise SemanticError(f'Parent type is already set for {self.name}.') + self.parent = parent + + def get_attribute(self, name:str): + try: + return next(attr for attr in self.attributes if attr.name == name) + except StopIteration: + if self.parent is None: + raise SemanticError(f'Attribute "{name}" is not defined in {self.name}.') + try: + return self.parent.get_attribute(name) + except SemanticError: + raise SemanticError(f'Attribute "{name}" is not defined in {self.name}.') + + def define_attribute(self, name:str, typex): + try: + self.get_attribute(name) + except SemanticError: + attribute = Attribute(name, typex) + self.attributes.append(attribute) + return attribute + else: + raise SemanticError(f'Attribute "{name}" is already defined in {self.name}.') + + def get_method(self, name:str): + try: + return next(method for method in self.methods if method.name == name) + except StopIteration: + if self.parent is None: + raise SemanticError(f'Method "{name}" is not defined in {self.name}.') + try: + return self.parent.get_method(name) + except SemanticError: + raise SemanticError(f'Method "{name}" is not defined in {self.name}.') + + def define_method(self, name:str, param_names:list, param_types:list, return_type): + if name in (method.name for method in self.methods): + raise SemanticError(f'Method "{name}" already defined in {self.name}') + + method = Method(name, param_names, param_types, return_type) + self.methods.append(method) + return method + + def all_attributes(self, clean=True): + plain = OrderedDict() if self.parent is None else self.parent.all_attributes(False) + for attr in self.attributes: + plain[attr.name] = (attr, self) + return plain.values() if clean else plain + + def all_methods(self, clean=True): + plain = OrderedDict() if self.parent is None else self.parent.all_methods(False) + for method in self.methods: + plain[method.name] = (method, self) + return plain.values() if clean else plain + + def conforms_to(self, other): + return other.bypass() or self == other or self.parent is not None and self.parent.conforms_to(other) + + def bypass(self): + return False + + def __str__(self): + output = f'type {self.name}' + parent = '' if self.parent is None else f' : {self.parent.name}' + output += parent + output += ' {' + output += '\n\t' if self.attributes or self.methods else '' + output += '\n\t'.join(str(x) for x in self.attributes) + output += '\n\t' if self.attributes else '' + output += '\n\t'.join(str(x) for x in self.methods) + output += '\n' if self.methods else '' + output += '}\n' + return output + + def __repr__(self): + return str(self) + +class ErrorType(Type): + def __init__(self): + Type.__init__(self, '') + + def conforms_to(self, other): + return True + + def bypass(self): + return True + + def __eq__(self, other): + return isinstance(other, Type) + +class VoidType(Type): + def __init__(self): + Type.__init__(self, '') + + def conforms_to(self, other): + raise Exception('Invalid type: void type.') + + def bypass(self): + return True + + def __eq__(self, other): + return isinstance(other, VoidType) + +class IntType(Type): + def __init__(self): + Type.__init__(self, 'int') + + def __eq__(self, other): + return other.name == self.name or isinstance(other, IntType) + +class Context: + def __init__(self): + self.types = {} + + def create_type(self, name:str): + if name in self.types: + raise SemanticError(f'Type with the same name ({name}) already in context.') + typex = self.types[name] = Type(name) + return typex + + def get_type(self, name:str): + try: + return self.types[name] + except KeyError: + raise SemanticError(f'Type "{name}" is not defined.') + + def __str__(self): + return '{\n\t' + '\n\t'.join(y for x in self.types.values() for y in str(x).split('\n')) + '\n}' + + def __repr__(self): + return str(self) + +class VariableInfo: + def __init__(self, name, vtype): + self.name = name + self.type = vtype + +class Scope: + def __init__(self, parent=None): + self.locals = [] + self.parent = parent + self.children = [] + self.index = 0 if parent is None else len(parent) + + def __len__(self): + return len(self.locals) + + def create_child(self): + child = Scope(self) + self.children.append(child) + return child + + def define_variable(self, vname, vtype): + info = VariableInfo(vname, vtype) + self.locals.append(info) + return info + + def find_variable(self, vname, index=None): + locals = self.locals if index is None else itt.islice(self.locals, index) + try: + return next(x for x in locals if x.name == vname) + except StopIteration: + return self.parent.find_variable(vname, self.index) if self.parent is None else None + + def is_defined(self, vname): + return self.find_variable(vname) is not None + + def is_local(self, vname): + return any(True for x in self.locals if x.name == vname) diff --git a/cmp/utils.py b/cmp/utils.py new file mode 100755 index 000000000..a839ff5ee --- /dev/null +++ b/cmp/utils.py @@ -0,0 +1,219 @@ +from cmp.pycompiler import Production, Sentence, Symbol, EOF, Epsilon + +class ContainerSet: + def __init__(self, *values, contains_epsilon=False): + self.set = set(values) + self.contains_epsilon = contains_epsilon + + def add(self, value): + n = len(self.set) + self.set.add(value) + return n != len(self.set) + + def extend(self, values): + change = False + for value in values: + change |= self.add(value) + return change + + def set_epsilon(self, value=True): + last = self.contains_epsilon + self.contains_epsilon = value + return last != self.contains_epsilon + + def update(self, other): + n = len(self.set) + self.set.update(other.set) + return n != len(self.set) + + def epsilon_update(self, other): + return self.set_epsilon(self.contains_epsilon | other.contains_epsilon) + + def hard_update(self, other): + return self.update(other) | self.epsilon_update(other) + + def find_match(self, match): + for item in self.set: + if item == match: + return item + return None + + def __len__(self): + return len(self.set) + int(self.contains_epsilon) + + def __str__(self): + return '%s-%s' % (str(self.set), self.contains_epsilon) + + def __repr__(self): + return str(self) + + def __iter__(self): + return iter(self.set) + + def __nonzero__(self): + return len(self) > 0 + + def __eq__(self, other): + if isinstance(other, set): + return self.set == other + return isinstance(other, ContainerSet) and self.set == other.set and self.contains_epsilon == other.contains_epsilon + + +def inspect(item, grammar_name='G', mapper=None): + try: + return mapper[item] + except (TypeError, KeyError ): + if isinstance(item, dict): + items = ',\n '.join(f'{inspect(key, grammar_name, mapper)}: {inspect(value, grammar_name, mapper)}' for key, value in item.items() ) + return f'{{\n {items} \n}}' + elif isinstance(item, ContainerSet): + args = f'{ ", ".join(inspect(x, grammar_name, mapper) for x in item.set) } ,' if item.set else '' + return f'ContainerSet({args} contains_epsilon={item.contains_epsilon})' + elif isinstance(item, EOF): + return f'{grammar_name}.EOF' + elif isinstance(item, Epsilon): + return f'{grammar_name}.Epsilon' + elif isinstance(item, Symbol): + return f"G['{item.Name}']" + elif isinstance(item, Sentence): + items = ', '.join(inspect(s, grammar_name, mapper) for s in item._symbols) + return f'Sentence({items})' + elif isinstance(item, Production): + left = inspect(item.Left, grammar_name, mapper) + right = inspect(item.Right, grammar_name, mapper) + return f'Production({left}, {right})' + elif isinstance(item, tuple) or isinstance(item, list): + ctor = ('(', ')') if isinstance(item, tuple) else ('[',']') + return f'{ctor[0]} {("%s, " * len(item)) % tuple(inspect(x, grammar_name, mapper) for x in item)}{ctor[1]}' + else: + raise ValueError(f'Invalid: {item}') + +def pprint(item, header=""): + if header: + print(header) + + if isinstance(item, dict): + for key, value in item.items(): + print(f'{key} ---> {value}') + elif isinstance(item, list): + print('[') + for x in item: + print(f' {repr(x)}') + print(']') + else: + print(item) + +class Token: + """ + Basic token class. + + Parameters + ---------- + lex : str + Token's lexeme. + token_type : Enum + Token's type. + """ + + def __init__(self, lex, token_type): + self.lex = lex + self.token_type = token_type + + def __str__(self): + return f'{self.token_type}: {self.lex}' + + def __repr__(self): + return str(self) + + @property + def is_valid(self): + return True + +class UnknownToken(Token): + def __init__(self, lex): + Token.__init__(self, lex, None) + + def transform_to(self, token_type): + return Token(self.lex, token_type) + + @property + def is_valid(self): + return False + +def tokenizer(G, fixed_tokens): + def decorate(func): + def tokenize_text(text): + tokens = [] + for lex in text.split(): + try: + token = fixed_tokens[lex] + except KeyError: + token = UnknownToken(lex) + try: + token = func(token) + except TypeError: + pass + tokens.append(token) + tokens.append(Token('$', G.EOF)) + return tokens + + if hasattr(func, '__call__'): + return tokenize_text + elif isinstance(func, str): + return tokenize_text(func) + else: + raise TypeError('Argument must be "str" or a callable object.') + return decorate + +class DisjointSet: + def __init__(self, *items): + self.nodes = { x: DisjointNode(x) for x in items } + + def merge(self, items): + items = (self.nodes[x] for x in items) + try: + head, *others = items + for other in others: + head.merge(other) + except ValueError: + pass + + @property + def representatives(self): + return { n.representative for n in self.nodes.values() } + + @property + def groups(self): + return [[n for n in self.nodes.values() if n.representative == r] for r in self.representatives] + + def __len__(self): + return len(self.representatives) + + def __getitem__(self, item): + return self.nodes[item] + + def __str__(self): + return str(self.groups) + + def __repr__(self): + return str(self) + +class DisjointNode: + def __init__(self, value): + self.value = value + self.parent = self + + @property + def representative(self): + if self.parent != self: + self.parent = self.parent.representative + return self.parent + + def merge(self, other): + other.representative.parent = self.representative + + def __str__(self): + return str(self.value) + + def __repr__(self): + return str(self) \ No newline at end of file diff --git a/cmp/visitor.py b/cmp/visitor.py new file mode 100755 index 000000000..964842836 --- /dev/null +++ b/cmp/visitor.py @@ -0,0 +1,80 @@ +# The MIT License (MIT) +# +# Copyright (c) 2013 Curtis Schlak +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +import inspect + +__all__ = ['on', 'when'] + +def on(param_name): + def f(fn): + dispatcher = Dispatcher(param_name, fn) + return dispatcher + return f + + +def when(param_type): + def f(fn): + frame = inspect.currentframe().f_back + func_name = fn.func_name if 'func_name' in dir(fn) else fn.__name__ + dispatcher = frame.f_locals[func_name] + if not isinstance(dispatcher, Dispatcher): + dispatcher = dispatcher.dispatcher + dispatcher.add_target(param_type, fn) + def ff(*args, **kw): + return dispatcher(*args, **kw) + ff.dispatcher = dispatcher + return ff + return f + + +class Dispatcher(object): + def __init__(self, param_name, fn): + frame = inspect.currentframe().f_back.f_back + top_level = frame.f_locals == frame.f_globals + self.param_index = self.__argspec(fn).args.index(param_name) + self.param_name = param_name + self.targets = {} + + def __call__(self, *args, **kw): + typ = args[self.param_index].__class__ + d = self.targets.get(typ) + if d is not None: + return d(*args, **kw) + else: + issub = issubclass + t = self.targets + ks = t.keys() + ans = [t[k](*args, **kw) for k in ks if issub(typ, k)] + if len(ans) == 1: + return ans.pop() + return ans + + def add_target(self, typ, target): + self.targets[typ] = target + + @staticmethod + def __argspec(fn): + # Support for Python 3 type hints requires inspect.getfullargspec + if hasattr(inspect, 'getfullargspec'): + return inspect.getfullargspec(fn) + else: + return inspect.getargspec(fn) diff --git a/cool_grammar.py b/cool_grammar.py new file mode 100644 index 000000000..8dbfae440 --- /dev/null +++ b/cool_grammar.py @@ -0,0 +1,184 @@ +from cmp.pycompiler import Grammar +from ast_nodes import ( + ProgramNode, + ClassDeclarationNode, + FuncDeclarationNode, + AttrDeclarationNode, + IfNode, + WhileNode, + LetNode, + CaseNode, + IsvoidNode, + AssignNode, + VarDeclarationNode, + CaseItemNode, + NotNode, + LessNode, + LessEqualNode, + EqualNode, + PlusNode, + MinusNode, + StarNode, + DivNode, + NegNode, + InstantiateNode, + BlockNode, + CallNode, + ConstantNumNode, + VariableNode, + BooleanFalseNode, + BooleanTrueNode, + StringNode, +) + + +def define_cool_grammar(print_grammar=False): + # grammar + G = Grammar() + + # non-terminals + program = G.NonTerminal("", startSymbol=True) + class_list, def_class = G.NonTerminals(" ") + feature_list, def_attr, def_func = G.NonTerminals( + " " + ) + param_list, param = G.NonTerminals(" ") + expr, comp, arith, term, factor, element, atom = G.NonTerminals( + " " + ) + identifiers_list, identifier_init = G.NonTerminals(" ") + block, case_block, case_item = G.NonTerminals(" ") + func_call, arg_list = G.NonTerminals(" ") + + # terminals + classx, inherits, notx, isvoid = G.Terminals("class inherits not isvoid") + let, inx = G.Terminals("let in") + ifx, then, elsex, fi = G.Terminals("if then else fi") + whilex, loop, pool = G.Terminals("while loop pool") + case, of, esac = G.Terminals("case of esac") + semi, colon, comma, dot, opar, cpar, ocur, ccur, at, larrow, rarrow = G.Terminals( + "; : , . ( ) { } @ <- =>" + ) + equal, plus, minus, star, div, less, equal, lesseq, neg = G.Terminals( + "= + - * / < = <= ~" + ) + idx, num, new, string, true, false = G.Terminals("id int new string true false") + + # productions + program %= class_list, lambda h, s: ProgramNode(s[1]) + + class_list %= def_class + class_list, lambda h, s: [s[1]] + s[2] + class_list %= def_class, lambda h, s: [s[1]] + + def_class %= ( + classx + idx + ocur + feature_list + ccur + semi, + lambda h, s: ClassDeclarationNode(s[2], s[4]), + ) + def_class %= ( + classx + idx + inherits + idx + ocur + feature_list + ccur + semi, + lambda h, s: ClassDeclarationNode(s[2], s[6], s[4]), + ) + + feature_list %= def_attr + semi + feature_list, lambda h, s: [s[1]] + s[3] + feature_list %= def_func + semi + feature_list, lambda h, s: [s[1]] + s[3] + feature_list %= G.Epsilon, lambda h, s: [] + + def_attr %= ( + idx + colon + idx + larrow + expr, + lambda h, s: AttrDeclarationNode(s[1], s[3], s[5]), + ) + def_attr %= idx + colon + idx, lambda h, s: AttrDeclarationNode(s[1], s[3]) + + def_func %= ( + idx + opar + param_list + cpar + colon + idx + ocur + expr + ccur, + lambda h, s: FuncDeclarationNode(s[1], s[3], s[6], s[8]), + ) + + param_list %= param + comma + param_list, lambda h, s: [s[1]] + s[3] + param_list %= param, lambda h, s: [s[1]] + param_list %= G.Epsilon, lambda h, s: [] + + param %= idx + colon + idx, lambda h, s: (s[1], s[3]) + + expr %= idx + larrow + expr, lambda h, s: AssignNode(s[1], s[3]) + expr %= let + identifiers_list + inx + expr, lambda h, s: LetNode(s[2], s[4]) + expr %= ( + ifx + expr + then + expr + elsex + expr + fi, + lambda h, s: IfNode(s[2], s[4], s[6]), + ) + expr %= whilex + expr + loop + expr + pool, lambda h, s: WhileNode(s[2], s[4]) + expr %= case + expr + of + case_block + esac, lambda h, s: CaseNode(s[2], s[4]) + expr %= notx + expr, lambda h, s: NotNode(s[2]) + expr %= comp, lambda h, s: s[1] + + identifiers_list %= ( + identifier_init + comma + identifiers_list, + lambda h, s: [s[1]] + s[3], + ) + identifiers_list %= identifier_init, lambda h, s: [s[1]] + + identifier_init %= ( + idx + colon + idx + larrow + expr, + lambda h, s: VarDeclarationNode(s[1], s[3], s[5]), + ) + identifier_init %= idx + colon + idx, lambda h, s: VarDeclarationNode(s[1], s[3]) + + case_block %= case_item + case_block, lambda h, s: [s[1]] + s[2] + case_block %= case_item, lambda h, s: [s[1]] + case_item %= ( + idx + colon + idx + rarrow + expr + semi, + lambda h, s: CaseItemNode(s[1], s[3], s[5]), + ) + + comp %= comp + less + arith, lambda h, s: LessNode(s[1], s[3]) + comp %= comp + equal + arith, lambda h, s: EqualNode(s[1], s[3]) + comp %= comp + lesseq + arith, lambda h, s: LessEqualNode(s[1], s[3]) + comp %= arith, lambda h, s: s[1] + + arith %= arith + plus + term, lambda h, s: PlusNode(s[1], s[3]) + arith %= arith + minus + term, lambda h, s: MinusNode(s[1], s[3]) + arith %= term, lambda h, s: s[1] + + term %= term + star + factor, lambda h, s: StarNode(s[1], s[3]) + term %= term + div + factor, lambda h, s: DivNode(s[1], s[3]) + term %= factor, lambda h, s: s[1] + + factor %= isvoid + element, lambda h, s: IsvoidNode(s[2]) + factor %= neg + element, lambda h, s: NegNode(s[2]) + factor %= new + idx, lambda h, s: InstantiateNode(s[2]) + factor %= element, lambda h, s: s[1] + + element %= opar + expr + cpar, lambda h, s: s[2] + element %= ocur + block + ccur, lambda h, s: BlockNode(s[2]) + element %= ( + element + dot + func_call, + lambda h, s: CallNode(*s[3], obj=s[1]), + ) + element %= ( + element + at + idx + dot + func_call, + lambda h, s: CallNode(*s[5], obj=s[1], at_type=s[3]), + ) + element %= func_call, lambda h, s: CallNode(*s[3]) + element %= atom, lambda h, s: s[1] + + atom %= num, lambda h, s: ConstantNumNode(s[1]) + atom %= idx, lambda h, s: VariableNode(s[1]) + atom %= ( + true, + lambda h, s: BooleanTrueNode(s[1]), + ) # verificar #include en el tokenizer + atom %= false, lambda h, s: BooleanFalseNode(s[1]) # include en el tokenizer + atom %= string, lambda h, s: StringNode(s[1]) # include en el tokenizer + + block %= expr + semi, lambda h, s: [s[1]] + block %= expr + semi + block, lambda h, s: [s[1]] + s[3] + + func_call %= idx + opar + arg_list + cpar, lambda h, s: (s[1], s[3]) + + arg_list %= expr + comma + arg_list, lambda h, s: [s[1]] + s[3] + arg_list %= expr, lambda h, s: [s[1]] + arg_list %= G.Epsilon, lambda h, s: [] + + if print_grammar: + print(G) + return (G, idx, num) diff --git a/cool_tokenizer.py b/cool_tokenizer.py new file mode 100644 index 000000000..55ac0195f --- /dev/null +++ b/cool_tokenizer.py @@ -0,0 +1,43 @@ +from cmp.utils import Token, tokenizer + + +def tokenize_cool_text(G, text, idx, num, print_tokens=False): + fixed_tokens = { + t.Name: Token(t.Name, t) for t in G.terminals if t not in {idx, num} + } + + @tokenizer(G, fixed_tokens) + def tokenize_text(token): + lex = token.lex + try: + float(lex) + return token.transform_to(num) + except ValueError: # verificar los string + return token.transform_to(idx) + + # (do something like if(lex[0] == " and lex[-1] ==")) + tokens = tokenize_text(text) + if print_tokens: + pprint_tokens(tokens) + return tokens + + +# pie co los lex, arreglar como toca +def pprint_tokens(tokens): + indent = 0 + pending = [] + for token in tokens: + pending.append(token) + if token.lex in {"{", "}", ";"}: + if token.lex == "}": + indent -= 1 + print(" " * indent + " ".join(str(t.token_type) for t in pending)) + pending.clear() + if token.lex == "{": + indent += 1 + print(" ".join([str(t.token_type) for t in pending])) + + +# if __name__ == "__main__": +# pprint_tokens(tokens) + diff --git a/cool_visitor.py b/cool_visitor.py new file mode 100644 index 000000000..aba87398b --- /dev/null +++ b/cool_visitor.py @@ -0,0 +1,161 @@ +import cmp.visitor as visitor +from ast_nodes import ( + ProgramNode, + ClassDeclarationNode, + FuncDeclarationNode, + AttrDeclarationNode, + IfNode, + WhileNode, + LetNode, + CaseNode, + AssignNode, + VarDeclarationNode, + CaseItemNode, + InstantiateNode, + BlockNode, + CallNode, + BinaryNode, + AtomicNode, + UnaryNode, +) + + +class FormatVisitor(object): + @visitor.on("node") + def visit(self, node, tabs): + pass + + @visitor.when(ProgramNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__ProgramNode [ ... ]" + statements = "\n".join( + self.visit(child, tabs + 1) for child in node.declarations + ) + return f"{ans}\n{statements}" + + @visitor.when(ClassDeclarationNode) + def visit(self, node, tabs=0): + parent = "" if node.parent is None else f"inherits {node.parent}" + ans = ( + "\t" * tabs + + f"\\__ClassDeclarationNode: class {node.id} {parent} {{ ... }}" + ) + features = "\n".join(self.visit(child, tabs + 1) for child in node.features) + return f"{ans}\n{features}" + + @visitor.when(AttrDeclarationNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__AttrDeclarationNode: {node.id} : {node.type} <- " + exp = "\t" * (tabs + 1) + "__NONE" + if not node.init_exp is None: + exp = "\n".join(self.visit(node.init_exp, tabs + 1)) + return f"{ans}\n{exp}" + + @visitor.when(VarDeclarationNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__VarDeclarationNode: {node.id} : {node.type} <- " + expr = "\t" * (tabs + 1) + "__NONE" + if not node.expr is None: + expr = self.visit(node.expr, tabs + 1) + return f"{ans}\n{expr}" + + @visitor.when(AssignNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__AssignNode: {node.id} <- " + expr = self.visit(node.expr, tabs + 1) + return f"{ans}\n{expr}" + + @visitor.when(FuncDeclarationNode) + def visit(self, node, tabs=0): + params = ", ".join(":".join(param) for param in node.params) + ans = ( + "\t" * tabs + + f"\\__FuncDeclarationNode: {node.id}({params}) : {node.type} -> " + ) + body = self.visit(node.body, tabs + 1) + return f"{ans}\n{body}" + + @visitor.when(BinaryNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__ {node.__class__.__name__} " + left = self.visit(node.left, tabs + 1) + right = self.visit(node.right, tabs + 1) + return f"{ans}\n{left}\n{right}" + + @visitor.when(AtomicNode) + def visit(self, node, tabs=0): + return "\t" * tabs + f"\\__ {node.__class__.__name__}: {node.lex}" + + @visitor.when(UnaryNode) + def visit(self, node, tabs=0): + class_name = node.__class__.__name__.split("Node")[0] + ans = "\t" * tabs + f"\\__ {node.__class__.__name__}: {class_name} " + expr = self.visit(node.expr, tabs + 1) + return f"{ans}\n{expr}" + + @visitor.when(CallNode) + def visit(self, node, tabs=0): + args = "\n".join(self.visit(arg, tabs + 1) for arg in node.args) + if not node.obj is None: + obj = self.visit(node.obj, tabs + 1) + if not node.at_type is None: + ans = ( + "\t" * tabs + + f"\\__CallNode: @{node.at_type}.{node.id}(, ..., )" + ) + else: + ans = ( + "\t" * tabs + f"\\__CallNode: .{node.id}(, ..., )" + ) + return f"{ans}\n{obj}\n{args}" + else: + ans = "\t" * tabs + f"\\__CallNode: {node.id}(, ..., )" + return f"{ans}\n{args}" + + @visitor.when(InstantiateNode) + def visit(self, node, tabs=0): + return "\t" * tabs + f"\\__ InstantiateNode: new {node.lex}()" + + @visitor.when(BlockNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__BlockNode: {{; ... ;}}" + body = "\n".join(self.visit(child, tabs + 1) for child in node.expresion_list) + return f"{ans}\n{body}" + + @visitor.when(IfNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__IfNode: if then else fi" + if_expr = self.visit(node.if_expr, tabs + 1) + then_expr = self.visit(node.then_expr, tabs + 1) + else_expr = self.visit(node.else_expr, tabs + 1) + return f"{ans}\n{if_expr}\n{then_expr}\n{else_expr}" + + @visitor.when(WhileNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__WhileNode: while loop pool" + condition = self.visit(node.condition, tabs + 1) + body = self.visit(node.body, tabs + 1) + return f"{ans}\n{condition}\n{body}" + + @visitor.when(LetNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__LetNode: let in " + ident_list = "\n".join( + self.visit(child, tabs + 1) for child in node.identifiers + ) + body = self.visit(node.body, tabs + 1) + return f"{ans}\n{ident_list}\n{body}" + + @visitor.when(CaseNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__LetNode: case of esac" + case_block = "\n".join(self.visit(child, tabs + 1) for child in node.case_items) + expr = self.visit(node.expr, tabs + 1) + return f"{ans}\n{expr}\n{case_block}" + + @visitor.when(CaseItemNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__CaseItemNode: {node.id} : {node.type} => ;" + expr = self.visit(node.expr, tabs + 1) + return f"{ans}\n{expr}" + diff --git a/errors.py b/errors.py new file mode 100644 index 000000000..945bb486b --- /dev/null +++ b/errors.py @@ -0,0 +1,61 @@ +class Error(Exception): + "Base class for exceptions" + pass + + +class parsing_table_error(Error): + "raised when T[X,t] possess more than one production" + + def __init__(self, production1, production2, invalid_sentence): + Error.__init__( + self, + f"conflict betweeen {production1} and {production2}, invalid sentence: {invalid_sentence}", + ) + + +class shift_reduce_error(Error): + "raised when goto or action table in shift reduce parsers possess more than one production" + + def __init__(self, action1, action2, grammar, key=None): + if action1[0] == action2[0] == "REDUCE": + conflict = "Reduce-Reduce" + else: + conflict = "Shift-Reduce" + + Error.__init__( + self, + f"When analizing {key}, {conflict} conflict!!! betweeen {action1} and {action2}. Grammar given is not {grammar}", + ) + + +class invalid_sentence_error(Error): + "raised when w is not in G" + + def __init__( + self, + w, + pos, + actual_token, + expected_token=None, + message="", + output=None, + operations=None, + ): + if expected_token != None: + Error.__init__( + self, + f"Invalid sentence {w}. Expected {expected_token} at position {pos} but received {actual_token} instead. {message}", + ) + else: + Error.__init__( + self, + f"Unexpected token {actual_token} at position {pos}. Invalid sentence {w}. {message}. Secuencia de derivaciones: {output}. Operaciones: {operations}", + ) + + +class non_regular_production_error(Error): + def __init__(self, production): + Error.__init__( + self, + f"production {production} most be of the form: A -> a, A -> e or A -> aX", + ) diff --git a/main.py b/main.py new file mode 100644 index 000000000..c47493bb8 --- /dev/null +++ b/main.py @@ -0,0 +1,98 @@ +from cool_tokenizer import tokenize_cool_text +from cool_grammar import define_cool_grammar +from cool_visitor import FormatVisitor + +from shift_reduce_parsers import LR1Parser, DerivationTree +from errors import parsing_table_error, Error + +from cmp.evaluation import evaluate_reverse_parse + +text = """ +class Cons inherits List { + xcar : Int ; + xcdr : List ; + + isNill ( ) : Bool { + false + } ; + + init ( hd : Int , tl : List ) : Cons { + { + xcar <- hd ; + xcdr <- tl ; + self ; + } + } ; +} ; +""" + +# text = """ +# class Cons inherits List { +# xcar : Int ; +# xcdr : List ; + +# isNill ( ) : Bool { +# false +# } ; +# } ; +# """ + +# text = """ +# class Cons inherits List { +# xcar : Int ; +# xcdr : List ; +# } ; +# """ + + +def run_pipeline(text): + # define grammar + grammar, idx, num = define_cool_grammar() + + # tokenize text + tokens = tokenize_cool_text(grammar, text, idx, num) + + # try: + parser = LR1Parser(grammar) + parse, operations = parser([t.token_type for t in tokens]) + # print("\n".join(repr(x) for x in parse)) + # print(operations) + + ast = evaluate_reverse_parse(parse, operations, tokens) + formatter = FormatVisitor() + tree = formatter.visit(ast) + print(tree) + # derivation_list = parser(text) + # derivation_tree_aut = DerivationTree(derivation_list[0], G) + + # except Error as err: + # print(err) + + +# def run_pipeline_cmp_tools(text): +# # only for testing +# # define grammar +# grammar, idx, num = define_cool_grammar() + +# # tokenizer +# tokens = tokenize_cool_text(grammar, text, idx, num) + +# # lexical an +# from cmp.tools.parsing import LR1Parser + +# parser = LR1Parser(grammar) +# parse, operations = parser([t.token_type for t in tokens], get_shift_reduce=True) +# print("\n".join(repr(x) for x in parse)) +# # print(operations) + +# ast = evaluate_reverse_parse(parse, operations, tokens) + +# formatter = FormatVisitor() +# tree = formatter.visit(ast) +# print(tree) + + +run_pipeline(text) + +# run_pipeline_cmp_tools(text) + diff --git a/methods.py b/methods.py new file mode 100644 index 000000000..504d50086 --- /dev/null +++ b/methods.py @@ -0,0 +1,150 @@ +from cmp.pycompiler import ( + Symbol, + NonTerminal, + Terminal, + EOF, + Sentence, + SentenceList, + Epsilon, + Production, + Grammar, +) +from cmp.utils import ContainerSet +from errors import parsing_table_error, invalid_sentence_error +from itertools import islice +from cmp.automata import State + + +# Computes First(alpha), given First(Vt) and First(Vn) +# alpha in (Vt U Vn)* +def compute_local_first(firsts, alpha): + first_alpha = ContainerSet() + + try: + alpha_is_epsilon = alpha.IsEpsilon + except: + alpha_is_epsilon = False + + ################################################### + # alpha == epsilon ? First(alpha) = { epsilon } + ################################################### + if alpha_is_epsilon or len(alpha) == 0: + first_alpha.set_epsilon() + return first_alpha + ################################################### + + ################################################### + # alpha = X1 ... XN + # First(Xi) subconjunto First(alpha) + # epsilon pertenece a First(X1)...First(Xi) ? First(Xi+1) subconjunto de First(X) y First(alpha) + # epsilon pertenece a First(X1)...First(XN) ? epsilon pertence a First(X) y al First(alpha) + ################################################### + if alpha[0].IsTerminal: + first_alpha.add(alpha[0]) + return first_alpha + + # if alpha[0].IsNonTerminal: + # first_alpha.update(firsts[alpha[0]]) + + for item in alpha: + if firsts[item].contains_epsilon: + first_alpha.update(firsts[item]) + else: + first_alpha.update(firsts[item]) + break + + else: + first_alpha.set_epsilon() + + ################################################### + + # First(alpha) + return first_alpha + + +# Computes First(Vt) U First(Vn) U First(alpha) +# P: X -> alpha +def compute_firsts(G): + firsts = {} + change = True + + # init First(Vt) + for terminal in G.terminals: + firsts[terminal] = ContainerSet(terminal) + + # init First(Vn) + for nonterminal in G.nonTerminals: + firsts[nonterminal] = ContainerSet() + + while change: + change = False + + # P: X -> alpha + for production in G.Productions: + X = production.Left + alpha = production.Right + + # get current First(X) + first_X = firsts[X] + + # init First(alpha) + try: + first_alpha = firsts[alpha] + except: + first_alpha = firsts[alpha] = ContainerSet() + + # CurrentFirst(alpha)??? + local_first = compute_local_first(firsts, alpha) + + # update First(X) and First(alpha) from CurrentFirst(alpha) + change |= first_alpha.hard_update(local_first) + change |= first_X.hard_update(local_first) + + # First(Vt) + First(Vt) + First(RightSides) + return firsts + + +def compute_follows(G, firsts): + follows = {} + change = True + + # local_firsts = {} + + # init Follow(Vn) + for nonterminal in G.nonTerminals: + follows[nonterminal] = ContainerSet() + follows[G.startSymbol] = ContainerSet(G.EOF) + + while change: + change = False + + # P: X -> alpha + for production in G.Productions: + X = production.Left + alpha = production.Right + + follow_X = follows[X] + + ################################################### + # X -> zeta Y beta + # First(beta) - { epsilon } subset of Follow(Y) + # beta ->* epsilon or X -> zeta Y ? Follow(X) subset of Follow(Y) + ################################################### + + for i in range(0, len(alpha) - 1): + if alpha[i].IsNonTerminal: + beta = Sentence(*alpha[i + 1 :]) + firsts_beta = compute_local_first(firsts, beta) + change |= follows[alpha[i]].update(firsts_beta) + + if firsts_beta.contains_epsilon: + change |= follows[alpha[i]].update(follow_X) + + if not alpha.IsEpsilon and alpha[-1].IsNonTerminal: + change |= follows[alpha[-1]].update(follow_X) + + ################################################### + + # Follow(Vn) + return follows + diff --git a/parser_automatons.py b/parser_automatons.py new file mode 100644 index 000000000..9a84b7395 --- /dev/null +++ b/parser_automatons.py @@ -0,0 +1,225 @@ +from cmp.pycompiler import Item +from cmp.automata import State, lr0_formatter, multiline_formatter +from cmp.utils import ContainerSet +from methods import compute_firsts, compute_local_first, compute_follows + +# LR0 automaton -> for SLR and LALR parsers +def build_LR0_automaton(G): + assert len(G.startSymbol.productions) == 1, "Grammar must be augmented" + + start_production = G.startSymbol.productions[0] + start_item = Item(start_production, 0) + + automaton = State(start_item, True) + + pending = [start_item] + visited = {start_item: automaton} + + while pending: + current_item = pending.pop() + if current_item.IsReduceItem: + continue + + # (Decide which transitions to add) + # agregar las epsilon transiciones + # a estados donde el item posee producciones a partir del simbolo actual en la posicion 0 + # y agregar la transicion a partir del simbolo siguiente + + next_item = current_item.NextItem() + try: + next_state = visited[next_item] + except KeyError: + next_state = State(next_item, True) + visited[next_item] = next_state + pending.append(next_item) + + if current_item.NextSymbol.IsNonTerminal: + epsilon_productions = current_item.NextSymbol.productions + else: + epsilon_productions = None + + current_state = visited[current_item] + # (Adding the decided transitions) + current_state.add_transition(current_item.NextSymbol.Name, next_state) + + if epsilon_productions: + for eproduction in epsilon_productions: + epItem = Item(eproduction, 0) + try: + epState = visited[epItem] + except KeyError: + epState = State(epItem, True) + visited[epItem] = epState + pending.append(epItem) + current_state.add_epsilon_transition(epState) + + return automaton + + +# LR1 automaton +def expand(item, firsts): + next_symbol = item.NextSymbol + if next_symbol is None or not next_symbol.IsNonTerminal: + return [] + + lookaheads = ContainerSet() + # (Compute lookahead for child items) + previews = item.Preview() + for preview in previews: + lookaheads.update(compute_local_first(firsts, preview)) + + assert not lookaheads.contains_epsilon + # (Build and return child items) + items = [] + for production in next_symbol.productions: + items.append(Item(production, 0, lookaheads)) + + return items + + +def compress(items): + centers = {} + + for item in items: + center = item.Center() + try: + lookaheads = centers[center] + except KeyError: + centers[center] = lookaheads = set() + lookaheads.update(item.lookaheads) + + return { + Item(x.production, x.pos, set(lookahead)) for x, lookahead in centers.items() + } + + +def closure_lr1(items, firsts): + closure = ContainerSet(*items) + + changed = True + while changed: + changed = False + + new_items = ContainerSet() + # Your code here!!! + for item in closure: + new_items.extend(expand(item, firsts)) + + changed = closure.update(new_items) + + return compress(closure) + + +def goto_lr1(items, symbol, firsts=None, just_kernel=False): + assert ( + just_kernel or firsts is not None + ), "`firsts` must be provided if `just_kernel=False`" + items = frozenset(item.NextItem() for item in items if item.NextSymbol == symbol) + return items if just_kernel else closure_lr1(items, firsts) + + +def build_LR1_automaton(G): + assert len(G.startSymbol.productions) == 1, "Grammar must be augmented" + + firsts = compute_firsts(G) + firsts[G.EOF] = ContainerSet(G.EOF) + + start_production = G.startSymbol.productions[0] + start_item = Item(start_production, 0, lookaheads=(G.EOF,)) + start = frozenset([start_item]) # como cabecera solo queda el kernel + + closure = closure_lr1(start, firsts) + automaton = State( + frozenset(closure), True + ) # en visited si se guarda el estado completo + + pending = [start] + visited = {start: automaton} + + while pending: + current = pending.pop() + current_state = visited[current] + + closure = closure_lr1(current, firsts) + for symbol in G.terminals + G.nonTerminals: + # (Get/Build `next_state`) + # closure = closure_lr1(current,firsts) + goto = goto_lr1(closure, symbol, firsts, True) + + if not goto: + continue + + try: + next_state = visited[goto] + except KeyError: + next_state = visited[goto] = State( + frozenset(closure_lr1(goto, firsts)), True + ) + pending.append(goto) + + current_state.add_transition(symbol.Name, next_state) + + automaton.set_formatter(multiline_formatter) + return automaton + + +def build_LALR_automaton(G): + assert len(G.startSymbol.productions) == 1, "Grammar must be augmented" + + lr1_automaton = build_LR1_automaton(G) + + same_kernel = {} + for node in lr1_automaton: + just_center = frozenset([item.Center() for item in node.state]) + try: + same_kernel[just_center].append(node) + except KeyError: + same_kernel[just_center] = [node] + + start = frozenset( + [item.Center() for item in lr1_automaton.state] + ) # como cabecera solo quedan los items sin lookahead + automaton = State( + lr1_automaton.state, True + ) # en visited se guarda el estado que corresponde a la fusion de estaods ocn el mismo nucleo + + pending = [start] + visited = {start: automaton} + + while pending: + current = pending.pop() + current_state = visited[current] # se van a actualizar + # todos los estados con los que el estado actual tiene alguna transicion + lr1_state = same_kernel[current][0] + + # chequear que cada estado del cjto analizado tenga esa transicion + for symbol in G.terminals + G.nonTerminals: + if lr1_state.has_transition(symbol.Name): + state = lr1_state.transitions[symbol.Name][0] + center_items = frozenset([item.Center() for item in state.state]) + try: + next_state = visited[center_items] + except KeyError: + kernel_set = same_kernel[center_items] + items_with_lookahead = {} + for node in kernel_set: + for item in node.state: + try: + current_item = items_with_lookahead[item.Center()] + except KeyError: + current_item = items_with_lookahead[ + item.Center() + ] = set() + current_item.update(item.lookaheads) + completed_items = [ + Item(item.production, item.pos, lookaheads) + for item, lookaheads in items_with_lookahead.items() + ] + next_state = State(frozenset(completed_items), True) + visited[center_items] = next_state + pending.append(center_items) + + current_state.add_transition(symbol.Name, next_state) + + automaton.set_formatter(multiline_formatter) + return automaton diff --git a/shift_reduce_parsers.py b/shift_reduce_parsers.py new file mode 100644 index 000000000..7440d6104 --- /dev/null +++ b/shift_reduce_parsers.py @@ -0,0 +1,273 @@ +from parser_automatons import ( + build_LR0_automaton, + build_LR1_automaton, + build_LALR_automaton, +) +from methods import compute_firsts, compute_local_first, compute_follows +from cmp.automata import State +from errors import shift_reduce_error, invalid_sentence_error + + +class ShiftReduceParser: + SHIFT = "SHIFT" + REDUCE = "REDUCE" + OK = "OK" + + def __init__(self, G, verbose=False): + self.G = G + self.verbose = verbose + self.action = {} + self.goto = {} + self.automaton = self._build_parsing_table() + + def _build_parsing_table(self): + raise NotImplementedError() + + def __call__(self, w): + stack = [0] + cursor = 0 + output = [] + operations = [] + + while True: + state = stack[-1] + lookahead = w[cursor] + if self.verbose: + print(stack, "<---||--->", w[cursor:]) + + # Detect error + try: + action, tag = self.action[state, lookahead] + except KeyError: + raise invalid_sentence_error( + w, + cursor, + lookahead, + None, + "No transition available. Sentence given does not belong to the grammar", + output, + operations, + ) + # Exception( + # "No transition available" + # ) # string does not belong to this grammar + + # Shift case + if action == self.SHIFT: + operations.append(action) + stack.append(tag) + cursor += 1 + + # Reduce case + elif action == self.REDUCE: + operations.append(action) + for _ in range(len(tag.Right)): + stack.pop() + output.append(tag) + stack.append(self.goto[stack[-1], tag.Left]) + + # OK case + elif action == self.OK: + return output, operations + # Invalid case + else: + raise invalid_sentence_error( + w, + cursor, + lookahead, + None, + "Invalid case. Sentence given does not belong to the grammar", + ) + # raise Exception("Invalid case") + # break + + if cursor >= len(w): # or not stack + raise invalid_sentence_error( + w, + cursor - 1, + lookahead, + None, + "Exceed word length while looking for a viable derivation. Sentence given does not belong to the grammar", + ) + # raise Exception("Invalid sentence") + + +class SLR1Parser(ShiftReduceParser): + def _build_parsing_table(self): + G = self.G.AugmentedGrammar(True) + firsts = compute_firsts(G) + follows = compute_follows(G, firsts) + + automaton = build_LR0_automaton(G).to_deterministic() + for i, node in enumerate(automaton): + if self.verbose: + print(i, "\t", "\n\t ".join(str(x) for x in node.state), "\n") + node.idx = i + + for node in automaton: + idx = node.idx + for state in node.state: + item = state.state + # - Filling `self.Action` and `self.Goto` according to `item`) + # - Using `self._register(...)`) + if item.IsReduceItem: + if item.production.Left == G.startSymbol: + self._register(self.action, (idx, G.EOF), (self.OK, None)) + else: + for symbol in follows[item.production.Left]: + self._register( + self.action, + (idx, symbol), + (self.REDUCE, item.production), + ) + else: + if item.NextSymbol.IsTerminal: + self._register( + self.action, + (idx, item.NextSymbol), + (self.SHIFT, node[item.NextSymbol.Name][0].idx), + ) + else: + self._register( + self.goto, + (idx, item.NextSymbol), + node[item.NextSymbol.Name][0].idx, + ) + return automaton + + @staticmethod + def _register(table, key, value): + # assert ( + # key not in table or table[key] == value + # ), "Shift-Reduce or Reduce-Reduce conflict!!!" + if key in table and table[key] != value: + raise shift_reduce_error(table[key], value, "SLR") + table[key] = value + + +class LR1Parser(ShiftReduceParser): + def _build_parsing_table(self): + G = self.G.AugmentedGrammar(True) + + automaton = build_LR1_automaton(G) + for i, node in enumerate(automaton): + if self.verbose: + print(i, "\t", "\n\t ".join(str(x) for x in node.state), "\n") + node.idx = i + + # print("automatons states") + for node in automaton: + idx = node.idx + for item in node.state: + # print("item", item) + # - Fill `self.Action` and `self.Goto` according to `item`) + # - Feel free to use `self._register(...)`) + if item.IsReduceItem: + if item.production.Left == G.startSymbol: + self._register(self.action, (idx, G.EOF), (self.OK, None)) + else: + for symbol in item.lookaheads: + self._register( + self.action, + (idx, symbol), + (self.REDUCE, item.production), + ) + else: + if item.NextSymbol.IsTerminal: + self._register( + self.action, + (idx, item.NextSymbol), + (self.SHIFT, node[item.NextSymbol.Name][0].idx), + ) + else: + self._register( + self.goto, + (idx, item.NextSymbol), + node[item.NextSymbol.Name][0].idx, + ) + return automaton + + @staticmethod + def _register(table, key, value): + if key in table and table[key] != value: + raise shift_reduce_error(table[key], value, "LR", key) + table[key] = value + + +class LALR_Parser(ShiftReduceParser): + def _build_parsing_table(self): + G = self.G.AugmentedGrammar(True) + + automaton = build_LALR_automaton(G) + + for i, node in enumerate(automaton): + if self.verbose: + print(i, "\t", "\n\t ".join(str(x) for x in node.state), "\n") + node.idx = i + + for node in automaton: + idx = node.idx + for item in node.state: + # - Fill `self.Action` and `self.Goto` according to `item`) + # - Feel free to use `self._register(...)`) + if item.IsReduceItem: + if item.production.Left == G.startSymbol: + self._register(self.action, (idx, G.EOF), (self.OK, None)) + else: + for symbol in item.lookaheads: + self._register( + self.action, + (idx, symbol), + (self.REDUCE, item.production), + ) + else: + if item.NextSymbol.IsTerminal: + self._register( + self.action, + (idx, item.NextSymbol), + (self.SHIFT, node[item.NextSymbol.Name][0].idx), + ) + else: + self._register( + self.goto, + (idx, item.NextSymbol), + node[item.NextSymbol.Name][0].idx, + ) + + return automaton + + @staticmethod + def _register(table, key, value): + if key in table and table[key] != value: + raise shift_reduce_error(table[key], value, "LALR") + table[key] = value + + +# ----------------------derivation tree-------------------------# +def DerivationTree(derivation, G): + lent = len(derivation) + + nonTerminalstack = [] + root = State(G.startSymbol.Name) + nonTerminalstack.append(root) + + while lent > 0: + lent -= 1 + next_production = derivation[lent] + print("next_production", next_production) + currentNode = nonTerminalstack.pop() + # assert currentNode.state == next_production.Left.Name, "Wrong derivation" + + if next_production.IsEpsilon: + currentNode.add_transition(" ", State("epsilon", True)) + + for symbol in next_production.Right: + if symbol.IsTerminal: + currentNode.add_transition(" ", State(symbol.Name, True)) + else: + nonTerminalstack.append(State(symbol.Name)) + currentNode.add_transition( + " ", nonTerminalstack[len(nonTerminalstack) - 1] + ) + + return root From f00e0451bb913b81dfdb08348f5c7eb5c7846438 Mon Sep 17 00:00:00 2001 From: Gaby Date: Wed, 14 Oct 2020 11:00:46 -0400 Subject: [PATCH 002/162] Added notes.txt --- notes.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 notes.txt diff --git a/notes.txt b/notes.txt new file mode 100644 index 000000000..0b5838984 --- /dev/null +++ b/notes.txt @@ -0,0 +1,3 @@ +Por perfeccionar: +-Que el tokenizer reconozca los string( Empiezan y terminan en comillas"), +-Ignorar comentarios \ No newline at end of file From e314314ae9a885b29eb9c28c3fc46f589db5cc45 Mon Sep 17 00:00:00 2001 From: Gaby Date: Fri, 23 Oct 2020 07:48:36 -0400 Subject: [PATCH 003/162] Added gitignore file --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..8ce41bc1b --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +cmp/__pycache__/ +__pycache__/ From 597d6ddad6acc16c1b6adcac8cccba06a9f267fa Mon Sep 17 00:00:00 2001 From: Gaby Date: Fri, 23 Oct 2020 08:02:04 -0400 Subject: [PATCH 004/162] Removed unnecessary folder __pychache__ --- __pycache__/ast_nodes.cpython-38.pyc | Bin 7167 -> 0 bytes __pycache__/cool_grammar.cpython-38.pyc | Bin 9477 -> 0 bytes __pycache__/cool_tokenizer.cpython-38.pyc | Bin 1605 -> 0 bytes __pycache__/cool_visitor.cpython-38.pyc | Bin 6776 -> 0 bytes __pycache__/errors.cpython-38.pyc | Bin 2507 -> 0 bytes __pycache__/methods.cpython-38.pyc | Bin 2057 -> 0 bytes __pycache__/parser_automatons.cpython-38.pyc | Bin 5068 -> 0 bytes __pycache__/shift_reduce_parsers.cpython-38.pyc | Bin 6070 -> 0 bytes cmp/__pycache__/__init__.cpython-38.pyc | Bin 174 -> 0 bytes cmp/__pycache__/automata.cpython-38.pyc | Bin 7952 -> 0 bytes cmp/__pycache__/evaluation.cpython-38.pyc | Bin 1191 -> 0 bytes cmp/__pycache__/pycompiler.cpython-38.pyc | Bin 16544 -> 0 bytes cmp/__pycache__/utils.cpython-38.pyc | Bin 9713 -> 0 bytes cmp/__pycache__/visitor.cpython-38.pyc | Bin 2375 -> 0 bytes 14 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 __pycache__/ast_nodes.cpython-38.pyc delete mode 100644 __pycache__/cool_grammar.cpython-38.pyc delete mode 100644 __pycache__/cool_tokenizer.cpython-38.pyc delete mode 100644 __pycache__/cool_visitor.cpython-38.pyc delete mode 100644 __pycache__/errors.cpython-38.pyc delete mode 100644 __pycache__/methods.cpython-38.pyc delete mode 100644 __pycache__/parser_automatons.cpython-38.pyc delete mode 100644 __pycache__/shift_reduce_parsers.cpython-38.pyc delete mode 100644 cmp/__pycache__/__init__.cpython-38.pyc delete mode 100644 cmp/__pycache__/automata.cpython-38.pyc delete mode 100644 cmp/__pycache__/evaluation.cpython-38.pyc delete mode 100644 cmp/__pycache__/pycompiler.cpython-38.pyc delete mode 100644 cmp/__pycache__/utils.cpython-38.pyc delete mode 100644 cmp/__pycache__/visitor.cpython-38.pyc diff --git a/__pycache__/ast_nodes.cpython-38.pyc b/__pycache__/ast_nodes.cpython-38.pyc deleted file mode 100644 index 84bd791eb3de643d82e4a274335e429dd3806838..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7167 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 MWn4Uqq$Pj$|EvLP?f?J) diff --git a/__pycache__/cool_tokenizer.cpython-38.pyc b/__pycache__/cool_tokenizer.cpython-38.pyc deleted file mode 100644 index 886f1ce2dd4d5dadb50b3b3069624e76e0c23916..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1605 zcmZ`(&2Jk;6rVTy;q`VMg;KSEgk(5W?8QbPK_x5;(GqSJQfPq{Rb=f<(zW+1vunvQ z>r*0{6B0t)<75A&xpL|sz{MAMZ=5)ZT4ptGXJ_8W@BQYzecI{x49743{C4n{&Dh`c zadTMs@iorsAqv3+q%4C7G9GbY!V{LT&mgjdBiu6<*`l@2!uD&_Wg*wj55-jGx?R&N zSxB`PJ9Kn8JbYtJMlq^A6ffCJIOGBZKl2(kVNcj8ES(w});Op9@{}TaxbHS@1Nd$= zw)&>#P3shZH5A_&#em+f2FHbq^Ie?PCnyruu;<++G;q$&;RTf<( z?S1wNbBOHGIFpKeyyBYoKGjg;!b-$kTlp+gl)(CF|3#6>{v?w^s-o&YDdJfs^SbJP zu0;1lj#dA0k(Eh0j*}wqf3J!Y8P}-zSuVPzDkk{VkBcHb*izLiPqaS}NnFQhIV9dH zBFqKO0;Fy6@JjVyV<_i!Z;%%8IIV`gYr{9FASZ^3AufpJB`oey>V`jd!Ovj@KeBy{ zQCm}AJpx8gLnmwnF8dkJe!^Nnf?yQd+DheIJBMj8uA`t<5Qi_KfU9D{9wLWl4@) zD5@^qDNB{)^@iRm^fY{@ZPHZ~Oi>R+!A+GYI85eJTpFmm<)_ChCW$648%)d}_p-Ii$-Q=LZXhWl*{?G3U*%u+d| Mi#N&cTK@h20BnJ1D*ylh diff --git a/__pycache__/cool_visitor.cpython-38.pyc b/__pycache__/cool_visitor.cpython-38.pyc deleted file mode 100644 index 64fa51000888fc4c8ad33da78236fedcb04ea865..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6776 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 RS=UHxkUwyYO^fS?{sYc^AHXtmjyB-_}#W@eo< zEBA_um#8AaWuAif*jui61JsL%?~Jpy6NfVPoSic}b7tmz-<-3%)6*3LW$w@4{Le~; z@fRth#euScs-8n^8{FXLYgA$UYBx>j7Pq0>!h~)?ceo4P)w&Jc<0a@Ntvk@md;Q9rf+ZJ)E>W?L7XCjdG&7|FlT0w}l>fg)cOoS;0uEm^nWby)9UC<6yt#c;n zFjN(JvTQo0?io9?g|{0t?0tyqXC@Cf9q!=lZa&`$q>AE0KMnSABE3%bSO$?2oShzt zm_7e#Z#DgybrPinJkw63VChj1vm_R@Ki&<=Ng?g0DAb-n-9%OQAyVUavj?1e<{Mz# zvmouB{l+-={;*820DEy7*<6^!2dyYf*}h0mg}~}>J;nk!B3oExQG61#BF+@NC*n}7 zvkOa~p1_IXDD`~+vXc-S%*F0-Xu z991ipZCtpLJT7e#bb9HMAX6jeH7WEOWSX=BMN3l87>Zu561N~9#Exmi9=Bh)F&OyDz2b%2bHE6%=R%e=N6MNb6PhEH z0Y@s0ziH9jd$#p-cXKP7ex}d+u>Z)WcE|~ZHv0q7H;BQR3=C(PwaT))tl-%4^74>o zk^s-%tFdhvwA+DXhtUZpM~cNs$|S|K6;Dp#(Jb{n_^4>C<)y>^q})ChXU%f4zzFaI zUd_XTnt?D(W_p%m5xdxB_Te~u19GjH4N2}Du{R_V*`lyEBog(E5s4_dLBqy~8NHWp$AS=BRW=sv}G1#Rzc3;m+ZA9PTP~=|H zO*`E*uOwtq=cf^7448Hwj#qOKMuoBjvCMPn`QS3UcRR*I#yJhSfSHYV5RaIA4^`2n zzzQW~CHnm%>CG4cEp%?6DzZC_WZXh7vbjz1KVOQI7!mBS+X|#VjNg3%hGd~A)TTS2 zDMlIYIv7OeK4cqgxV_WDR!eWWVG zP2J}5FR+o3q*1xdK7QAU2JXh^#m(&TpNWI+@8`4*xu9%H(i@2X6I;dCiq42Sok$7= g8V)^dWXps2k(a;hf6F}4-xPFpt8TSYovkkZ3++i)ga7~l diff --git a/__pycache__/methods.cpython-38.pyc b/__pycache__/methods.cpython-38.pyc deleted file mode 100644 index 6b056e1e1f64ad2aa6269d387dfc94c4b935d8a1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2057 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 diff --git a/cmp/__pycache__/__init__.cpython-38.pyc b/cmp/__pycache__/__init__.cpython-38.pyc deleted file mode 100644 index 7b8fcc67623ee8c015d8fdbca35ac750ea185340..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 174 zcmWIL<>g`kf*{vT(IEOUh(HF6K#l_t7qb9~6oz01O-8?!3`HPe1o10aKO;XkRX-~? zH6^tuzgXWTKe;qFHLs*t-?%76p)xhGNZ&a>w;(eoF*!3oPd}h2zcMws1gOv`FGZoC pC_f9x(@)MV(2tML%*!l^kJl@xyv1RYo1apelWGUD>@yHE008m~EE)g+ diff --git a/cmp/__pycache__/automata.cpython-38.pyc b/cmp/__pycache__/automata.cpython-38.pyc deleted file mode 100644 index 9da1cc09533306e3eb3df4b100f0313a999d15f9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7952 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 diff --git a/cmp/__pycache__/evaluation.cpython-38.pyc b/cmp/__pycache__/evaluation.cpython-38.pyc deleted file mode 100644 index ac0186d876671d0227a145d060fc78ea1cdcd724..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1191 zcmZuwJ8u**5VpPE&EDRFhfsJlTo47@+#zTvq6m~60tp2~2*n8$ZPq5Ycl(O%LpkJa zIG{xQ1Sl!_7yJSWw=~cp(NO^7J(M7XrSWUN8P9w(-fp)81moxTS34glLZ9v7??K>j z9YkJ)i6Mqll;I)9c2820IYS5b4x=y7kTQ1*h2B>{q7WNraQ7xGC$>h(6Lp`nY0U3M zLUIv17V&4aVf8@PLF5IDkVc}VF$j^z8QMY$ZsxeMD}j~lp~}&C13ms&QB4&dlL--b zlv8V6?YyPh9lP%!#QjUP-UIy?&|5E__8yUHsq(cqUaA_(XPA)}NH-t_^pc!K8-SW) z`C2s?o#W>iH11hc1uD?~9E(p3?P2XKPE8=e+MGsJQwI#`=A2Y5-TD`?iuS+NaRG** zIa$P}n#{8=>|X+J&KxsmLf&9WRpU8UtwlcLw(897?Kyj^9UBW!ytEkuQHR6U$Wkh; zEW@PH<4%P&W@zF+L_h?wM22|tJqn2-y~~D*Y03o@9M#j0?f$69cz>L6#zi6f8$~?L zc&=pss$kt2k3@gH$jT&*;-tv?_e3${u>#w4KpgO^Y~6YY1@C54sk*zo zTjc4iD`&alDv3GkMoNifcdEGTi5h?6b`EhQpowiLD=RDEF+&r@g|I{!ck9;en-2_y z*p%_2vgA24PRb9AcYm<4y*@C(kx%19X=*w*B($#eHV~o^7M+{M;2`Fuy);20lU%AO zkGTm{G2!`+nw4DG;)LyCQzUyMwMf$h1t@Bgr15I3G%nc2lVRgfW!ze00-zWEPW=cS z@rW6^Td_AvzsKsxp8W6z#{ z1%&*hjt_`4aKB7Wl7O7V%UGNT+s)859jHANJg$2LShiW4Q_}u?D6#$ei`0dz3sBn~ Ywclb_N9wO;kZsD>Y#r-{Y2lXh8~V>X+5i9m diff --git a/cmp/__pycache__/pycompiler.cpython-38.pyc b/cmp/__pycache__/pycompiler.cpython-38.pyc deleted file mode 100644 index 6e42cbe818f5df62da6040132fed2606003cfabb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16544 zcmc&*eT*E*RqwBv>6x8fkJsz1^z)Oe-I%+M3In?kQ$H>NT5R^LJ9~G z6dk|ctNxnV9@~jP%x>3IcU9MW_3FJ>@4b5S-r3ojfzS8vgdck1O@{H0yvct`xH*R_ z_(K$);hF13%XrrCEYH4Wc(!lu+ARzBj#t8c$+vKCYjPoSUUU)@HbYvEb|{5H|KB#&!O;*mgyNS%QHRemeI03 z+jH=Zxp`%Lm%NJS;=Alsy&AqNzU$3+^;^cS*{XW8-W;CQynTSyh{~6@Hm(lVyBt6H zux{Zxk1J@P*fzI~wy|xY1l-HUU2|p0iky|sh96a)Rh^BEj=F0{PT;SvMowQIUyC0b ziVOF{_nx{w*ziyFHhj-lgW%LNgYM>r-w%URZ&6-z%kQXD=LZ|Zwe?PSZO}jU9yQqV zyCFKB?t9Il8uV~?s=F~fHQee-KVK~mw<5RQUhA)g?Kamxa8MX#*&OZDvszACyCz%W z59_>SdSz6$jUFbYIPJTp;vo2{;7d@~#SCtvO1m9|s@<;QCLo0jb2OKNlBPY7QbLjp zAz_)jSZIMpA}W8V1g4rphe?Q-A3L<$bu=a*v)SpkuAqVr{IJfM$n2V^0Hzt5yOvrA zv4GpCT{c1+-{z-eF*PPmR9g$y`a#&~cYVb{BKI=Z$H#3{y|Oj*FDNxocP$}IR2qcW zeKm2z}&78AFv*{wTb7Oi?IxG)UX z)(8D#gd?kCjT$kGwDEz!yh7O1L4o4ye!tyrrhxJsDNQR&GZYg_WxE~K+U<>jx4F)G zz1_aK*;&^uiX5i6a%w+|LoAMdJUhwjzvaRsZlzFX~=n^GF;1bTpNF7 zw_=$!TUxtl9s965KVw?$GsdbZn$68Ln_tqp4H~SBy6895E2xW(L*4z1;TWwdwAxHG zvoh#k@zus!zq41haS;X2!>EMDu5lY2wr$<9Oye5lvu#nuX{oTIQm~1+3vr?u5W?H+ zhEPy}B75I8qbk^Cy%PkG(~J@%)P>d_1gpC29ta%>JRfYXx6R@2E$9Kde%ZuoWeA$gfx!*WR)EZdmime7g`& zjHLdZbAeO?*IjGMd}em7FPZ8M+vYRIi^q0snY}&P`%C6cM<`IwG}%&RMZFf}dxdnB z1yq!t%}Xer@vr(#&tJuEp#s0T+3%ceZZ(6!`asu}e{H?f91c{o+wnTh;5)y|ZE=8C zntUz`-(CC8xB8K>G@H{qwfCevp|}S{b5B77W)GuMxH(++BO9`awjh8Yfqz7qYBhV{ zsW4P)S2sgH_g3}7OI?4+o{C&53T?^Jo6;h|n8U~na$+d^6L&*Mcf0*YbO~T4VLN~V zHtVK??}k-37p$gz%sgtjsPoyJwAC#ay&9Hd?O{|I?*5ue9R;lEYN~cANW}34q86*f z#k^ExUG5JK`uECoXtS4s+`#Y40X&j>zC70J{xI)7MbV9|9H@iipyCZ-sis~}N;O&h z6bn(iZ(;2?i?_1)X%9I%uf*%#h@agUu?z)c?Z67JmMmRKu4G*76X!RSlcP8F40#7;NS zCt;^LK&70tR4OFQR3bcqfd-l8~pbKW5k@vvCNW86f&YvX#B$WZ7)n6vaDx!Gb%rk`hW!=;mw zm_keT%AP?uP{513)3)(qV+ZTd14*~d_d)n>=4>caG}&D%vXZS(bG;K>Py7_8 zqpnSElcH!oN?_zC!(1>&`}cqvn=!QsXM7%4K)nQeXxxuekK?I&iba7(AU5-eFLM+) zjg1^UG1B+2I#)@+okK;;JepodWo_WRt(u37FC+$_g_gG_Ej>GKaWcb58?z;Cwh#s3 z42|wIS4kXz9rTq6(~)b44Kap$u{%ey3hvYbDeigq6Z{s!q*Et}bz%;}oSlXC0kJC!Rx0%H($#e}$`FP$A`sc|C<~XBj?xziE?(9=8^x|U zStt3ho~|o(phq)X7-_*sq;Ao;ZQsGlE?Fxh`{AGot1sg%Vf7NwSsNB2v=4)R8CQZ( zp3i==@WfgO?`IlcOZWvH+U?)S0nJl^ufv29`k)Ixtf%CrFo6Q#ha-v8h1d(>#Tq;+ zt@S;BkJgxJx3BpjM&D?+zk=S$gcouPopzWGp2n93--GuPueka-Je?Lj@Nc%;U(W%| za~9k7=nXEq2m>`6VWoVfo+g|EbwRRHiM89`$U(}JRku!uMF|wE=O{slB~<`N6!V=F zgf*H^sh0*RR+jb^Zio^ENMi&#WI*mybhgyc-#406FT;7RoP4<}I!SjSM4<@8#d@9}0_HbsZ9v;KH+h%YS9=37A4d!KcJ*riu z_}A8LYy*q~WVkunXQ;iev%aarb?O%|OjPa+hkoCSC8|}{JLLq%kqyW7o5YxmYMAq; z%a~O>Nx>Q&#t25%Cc%Wgxu}UYi&-218Lbv1iuhc3<@eBIDv^q{M@ppA8m10!9^N)? z!~7Tvjc|`yPIj25A$oaY(IwFv;T6_6lOm~?AlSFim~ATJI*$&F5l3$#OFpdg z65dPH9rnz~^r!1PDyTokm4MinfhgV`_drmLCQJuFgWykc0CIDfVh?b#UA{quxg8(7mbDT%zf!EaV1on%ebI$2Pbg_oVE=;> zQ(a#Y_>TyF0R{Yj9q*5KY}vEfgUmhl;p&~kH5T*#ah+j5KF5Tjicc~Xcg!vaPd==t zYgcrPDQ*!QQ|EbqHH=CxtX;bv!k?_*y=bPNoghSRve)P2QFJyL@b7SGPtwB4ZQ*^6uV4;+J2G+?`p0WMZ& z4+Qt|v-gBcw)v+N?&O50XgR8cE?*+6aJmcf$JU09w zg@5Bk^ILv|5YMhlF!>U>#Lo&x;tz%txtk6ba z!`QWMmy&bFZ5zS0a?1EH8Z%>*@~lpJWmQo)kztW=;0 zqH3^(tdMZ6>o-!M=BN;8+VjEm0+qCm5?p0%s@*}c_)lEPxkE)_1SK4JIa*NBHuj;A zp2HQ~LXo&jsm1YH$q6%&Jtetd$exlMFl0|j?pLd#bG{IOms~GoP)UYYs|IIDa=Yj( zA^0wNU8v9LoUYbBv>*14NI<^fz0N!8z2=tL+V35MMtQv)Ozc?;uAnUc)2K);f-cP@ zF9BM^_Mp1kPFRx67^7Xn89sAls847~l-F3V$VxtmVV2xzCR5fyRL>bUK~#mCAXySY zG=tn973w6Fs5E5CkD>u5M;b7J5MF;~ts55dAl1!5vIAAM0Xs-jW|UtRW%pK z>@+eSmq=z#|7zR3ZQMbQ0^%PFAu=kV<9oDqlP(aq?Q0{nx5vzxp6>_&)-M4RFIT8Kwt zewVmJL1cH3X(PLus3O9P>N%^4);|iWfp=~h9oUs%#&fXtdYl(aCmK)<(mj$vOWKe=yrzm;3LDDL+0Hg z%F$v%6~ymynJHs*Ax%=c(4M)c436g^@eY;^q>Oxqpv4;AUn=Khh65^}MJ6tKp_PbB zk4+P^;XBWAHeC5sP>`+y0ZA3gl_baO|64j_hSQ|uO2VWf9Ve3INRTfQ4RwPg*gtnmK+J;RP|FC`2`0Tsp{q2if4P?=B;=^2z~A2t?{A$`c8lHHcXE1m-{ zGGPo##4E|S?r%e6vi?X(+jisx3(wR3W&IwF-yV|6^c`5FvNCcW4o)^l4T$pN>3p83 zRV96k$6mEjJ^y?(my;&+19v@6+ITEZvJmdN$Qp$Sr}&~q?2XNJHNb-wx4kgg>vZo4 zhTDg3A0SETqZ-i24#a03I$4)IMNCK>rvZ;i5IK;{EChZOl~Enjh8!I+-Vfd2;F$A9 zO+oeZ?*n3K{bFWsLA*}a1c+=EZNW8*27vuERJW2dz3Am6amlZ?ZgO=txNJFerIFY6~Y zonX%e=5CYTm3hY;!I$lwa#*?TZkO*cYF3iO@#p-G7dcN4ysa?=NkSVJm4rl;Y4*HW z)2Ri&Zrwy?h?a&~bO3?Q;;ZFwlb%o>QSA&5X_zQ}_EsV#Wo}ImB}*6%+Pz@V&+SU- z8}Pt~7+D1@gqy1Jr8P2zNIT1-%Y*~Te38TPqLR0{F$`caklN~D7H^i;>zH%Pxr#Zf z(|llhlSo%$oHmKEmymr;aFZ#C|iJ2+w9 z#ey?F-?P`u&w;ic5;w8T^V9-5t@N`{;%AJT$I)iTZ3vHOg9>dn+Rma4sh@c7G#CZR zVMmOe652{71L>k=F+^xdyJ&OSZ`b^S@gxw!yDf%;m#Qo3{lH8USV&DOtB;}>n+y4Y z3P#BnL@L<;d|mVJ9-56)ali{(x#sSU~*}yNM`&oHa3K zswwQxr>hQg5QZ~MK_+bSa?M8(+}(ri9$JxJ=Wzuz9hht<;%(9t+&0@3bvv%pFm~d) zXlJy;p`fwchC9)Nfzz(w+r_tw?`qt)nuhanfXXdJ1S4{~gW;A|#-fMCh!Gn(bs)5j z9A{;Hl5b8ZwOu^>Ez&^LFC2)v{JEGt|LWGLo=||$#wJfDv2n@dpFqXK<_5IMq(?u5 zO%59xf?eCphOR*?S=frqn^L=Bs?#340}skYY`BuP;bbSeauGb$#du=S#}*IeBtQ~fNyCJE!7S?_FI^*U$2jrV_m z4#w!QgaDHi%j;+T5=8OS9CVk3@YqAF3Cl^qj4T)L|E<#MK;h>spTwicyxg)bU!Fv! zF$wVxxJH@>YuNnh$kOIKY|X(S7#*I5=*p6Lk^l3B5l}%+*`;8xrj{8ijVw~Xk> z0jN9G8} z@6a4bW4Y|7evQQ!S!ByAuo+zWbHXm8!k@R{m}zzl`j}7>Lo&m8T){U`XcxDK@Q8=3 zLHzVXlwr@Ixpu=*FENw^(+~Ghm&>ubq*GUhy1WQ=X;WP$enJnbfj=V=6?&4rvhmRW zmy`Z|>>bIQo+CI^01>I={JF>>`4Ng(1M~)(ICK)%IWm_=*2(58B*81M;sY1?BI-g) zZGeg4|3N&9s(v58AyggM^(pa^FwALoFxMh8wgEChp~!uYsPuYSG>l8&nFrUIF zdlP=12Er)I4ANkh+Up&rEz5MVYdNFmE% zsHU#-IrAH-qj>3jTt{Oxfn^bbwH5!RI5PWvq9=;LnwQL0K{0FJgJ8N=j9%_R@KJHj zxpJ_X4zazoOKT`Wlv%29wuPG}5dBp&X}&5#*(FNE?LSh4Azq94sbz{VD`IAi**FRJ zQv!m=Vw}PAa%KygMSgAexqQ46tIlnpSp9SQ;y+N@#ebO7{sS|pr+5&pYO12)N0c|A zw*9^q98t)0C4R(dad2@f^=9xM<$rX||5$D>$b3q@8ED5*s7XzaEr)I*eApXE=oNAJ z8t%1gP>F~8?*x)zE+(2OZrZchsoLO@WP+LH#@I@hEfdM2wJV>eb*o+_U{OqFtPb>Z zm^!j-_f0N&7w1CJR>xWVCX27I_$rI9vv`?BrVKKTKs5i92pmQQaq*HnhvQ!y^}u}L zRd&lb?qM$+&x&tW9$e**#C0CuLmXF}Gr9vh%a0@J6AiMJK3(NTsYz0RMC6{)zm+`; fL=sFI&Bl|B{f$!N&5c9zuWuY{9Gm-u@wWc~{_Kr; diff --git a/cmp/__pycache__/utils.cpython-38.pyc b/cmp/__pycache__/utils.cpython-38.pyc deleted file mode 100644 index 29102a04501801bc69c343cd03445c57298e4260..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9713 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 From 2bec81fac0f0fdd58c716f0358791c99101828e8 Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Wed, 25 Nov 2020 23:34:03 -0500 Subject: [PATCH 005/162] Check Semantics Still needs a tokenizer. Strings have'nt been tested since current tokenizer doesnt recognizes it --- conftest.py | 0 src/__init__.py | 0 src/ast_nodes.py | 182 +++++++ src/cmp/__init__.py | 0 src/cmp/ast.py | 69 +++ src/cmp/automata.py | 224 ++++++++ src/cmp/cil.py | 267 +++++++++ src/cmp/evaluation.py | 36 ++ src/cmp/nbpackage.py | 87 +++ src/cmp/pycompiler.py | 512 ++++++++++++++++++ src/cmp/semantic.py | 276 ++++++++++ .../.ipynb_checkpoints/__init__-checkpoint.py | 0 .../.ipynb_checkpoints/automata-checkpoint.py | 3 + .../evaluation-checkpoint.py | 3 + .../.ipynb_checkpoints/parsing-checkpoint.py | 10 + src/cmp/tools/__init__.py | 0 src/cmp/tools/automata.py | 3 + src/cmp/tools/evaluation.py | 3 + src/cmp/tools/parsing.py | 16 + src/cmp/tools/regex.py | 3 + src/cmp/utils.py | 282 ++++++++++ src/cmp/visitor.py | 80 +++ src/cool_grammar.py | 180 ++++++ src/cool_tokenizer.py | 43 ++ src/cool_visitor.py | 161 ++++++ src/errors.py | 61 +++ src/main.py | 61 +++ src/methods.py | 149 +++++ src/notes.txt | 3 + src/parser_automatons.py | 225 ++++++++ src/shift_reduce_parsers.py | 273 ++++++++++ src/tset_builder.py | 91 ++++ src/type_builder.py | 76 +++ src/type_checker.py | 439 +++++++++++++++ src/type_collector.py | 52 ++ test/run_pipeline.py | 28 + test/test_parser1.py | 37 ++ test/test_parser2.py | 37 ++ test/test_parser3.py | 31 ++ test/test_parser4.py | 29 + test/test_parser5.py | 24 + test/test_parser6.py | 28 + test/test_type_builder.py | 39 ++ test/test_type_checker.py | 75 +++ test/test_type_collector.py | 30 + 45 files changed, 4228 insertions(+) create mode 100644 conftest.py create mode 100644 src/__init__.py create mode 100644 src/ast_nodes.py create mode 100644 src/cmp/__init__.py create mode 100644 src/cmp/ast.py create mode 100644 src/cmp/automata.py create mode 100644 src/cmp/cil.py create mode 100644 src/cmp/evaluation.py create mode 100644 src/cmp/nbpackage.py create mode 100644 src/cmp/pycompiler.py create mode 100644 src/cmp/semantic.py create mode 100644 src/cmp/tools/.ipynb_checkpoints/__init__-checkpoint.py create mode 100644 src/cmp/tools/.ipynb_checkpoints/automata-checkpoint.py create mode 100644 src/cmp/tools/.ipynb_checkpoints/evaluation-checkpoint.py create mode 100644 src/cmp/tools/.ipynb_checkpoints/parsing-checkpoint.py create mode 100644 src/cmp/tools/__init__.py create mode 100644 src/cmp/tools/automata.py create mode 100644 src/cmp/tools/evaluation.py create mode 100644 src/cmp/tools/parsing.py create mode 100644 src/cmp/tools/regex.py create mode 100644 src/cmp/utils.py create mode 100644 src/cmp/visitor.py create mode 100644 src/cool_grammar.py create mode 100644 src/cool_tokenizer.py create mode 100644 src/cool_visitor.py create mode 100644 src/errors.py create mode 100644 src/main.py create mode 100644 src/methods.py create mode 100644 src/notes.txt create mode 100644 src/parser_automatons.py create mode 100644 src/shift_reduce_parsers.py create mode 100644 src/tset_builder.py create mode 100644 src/type_builder.py create mode 100644 src/type_checker.py create mode 100644 src/type_collector.py create mode 100644 test/run_pipeline.py create mode 100644 test/test_parser1.py create mode 100644 test/test_parser2.py create mode 100644 test/test_parser3.py create mode 100644 test/test_parser4.py create mode 100644 test/test_parser5.py create mode 100644 test/test_parser6.py create mode 100644 test/test_type_builder.py create mode 100644 test/test_type_checker.py create mode 100644 test/test_type_collector.py diff --git a/conftest.py b/conftest.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/ast_nodes.py b/src/ast_nodes.py new file mode 100644 index 000000000..61c295125 --- /dev/null +++ b/src/ast_nodes.py @@ -0,0 +1,182 @@ +class Node: + pass + + +class ProgramNode(Node): + def __init__(self, declarations): + self.declarations = declarations + + +class ExpressionNode(Node): + pass + + +class ClassDeclarationNode: + def __init__(self, idx, features, parent=None): + self.id = idx + self.parent = parent + self.features = features + + +class FuncDeclarationNode: + def __init__(self, idx, params, return_type, body): + self.id = idx + self.params = params + self.type = return_type + self.body = body + + +class AttrDeclarationNode: + def __init__(self, idx, typex, init_exp=None): + self.id = idx + self.type = typex + self.init_exp = init_exp + + +class VarDeclarationNode: + def __init__(self, idx, typex, expr=None): + self.id = idx + self.type = typex + self.expr = expr + + +class AssignNode(ExpressionNode): + def __init__(self, idx, expr): + self.id = idx + self.expr = expr + + +class LetNode(ExpressionNode): + def __init__(self, identifiers, body): + self.identifiers = identifiers + self.body = body + + +class IfNode(ExpressionNode): + def __init__(self, if_exp, then_exp, else_exp): + self.if_expr = if_exp + self.then_expr = then_exp + self.else_expr = else_exp + + +class WhileNode(ExpressionNode): + def __init__(self, condition, body): + self.condition = condition + self.body = body + + +class CaseNode(ExpressionNode): + def __init__(self, exp, case_items): + self.expr = exp + self.case_items = case_items + + +class CaseItemNode(ExpressionNode): + def __init__(self, idx, typex, exp): + self.id = idx + self.type = typex + self.expr = exp + + +# #atomic? +# class NotNode(ExpressionNode): +# def __init__(self, exp): +# self.exp = exp + +# method_name=id, args,obj,type +# aaaaaaaaaaaaaaaaaaaaaaaaaaaa que hago con estooooooooooooooooooooooooooo +class CallNode(ExpressionNode): + def __init__(self, idx, args, obj=None, at_type=None): + self.obj = obj + self.id = idx + self.args = args + self.at_type = at_type + + +class BlockNode(ExpressionNode): + def __init__(self, expression_list): + self.expression_list = expression_list + + +class AtomicNode(ExpressionNode): + def __init__(self, lex): + self.lex = lex + + +class UnaryNode(ExpressionNode): + def __init__(self, expr): + self.expr = expr + + +class BinaryNode(ExpressionNode): + def __init__(self, left, right): + self.left = left + self.right = right + + +class ArithmeticOperation(BinaryNode): + pass + + +class ComparisonOperation(BinaryNode): + pass + + +class ConstantNumNode(AtomicNode): + pass + + +class VariableNode(AtomicNode): + pass + + +class StringNode(AtomicNode): + pass + + +class BooleanNode(AtomicNode): + pass + + +class InstantiateNode(AtomicNode): + pass + + +class NotNode(UnaryNode): + pass + + +class IsvoidNode(UnaryNode): + pass + + +class NegNode(UnaryNode): + pass + + +class PlusNode(ArithmeticOperation): + pass + + +class MinusNode(ArithmeticOperation): + pass + + +class StarNode(ArithmeticOperation): + pass + + +class DivNode(ArithmeticOperation): + pass + + +class LessNode(ComparisonOperation): + pass + + +class LessEqualNode(ComparisonOperation): + pass + + +class EqualNode(ComparisonOperation): + pass diff --git a/src/cmp/__init__.py b/src/cmp/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/cmp/ast.py b/src/cmp/ast.py new file mode 100644 index 000000000..c0f73e1b2 --- /dev/null +++ b/src/cmp/ast.py @@ -0,0 +1,69 @@ +import src.cmp.visitor as visitor + + +class Node: + def evaluate(self): + raise NotImplementedError() + + +class AtomicNode(Node): + def __init__(self, lex): + self.lex = lex + + +class UnaryNode(Node): + def __init__(self, node): + self.node = node + + def evaluate(self): + value = self.node.evaluate() + return self.operate(value) + + @staticmethod + def operate(value): + raise NotImplementedError() + + +class BinaryNode(Node): + def __init__(self, left, right): + self.left = left + self.right = right + + def evaluate(self): + lvalue = self.left.evaluate() + rvalue = self.right.evaluate() + return self.operate(lvalue, rvalue) + + @staticmethod + def operate(lvalue, rvalue): + raise NotImplementedError() + + +def get_printer( + AtomicNode=AtomicNode, UnaryNode=UnaryNode, BinaryNode=BinaryNode, +): + class PrintVisitor(object): + @visitor.on("node") + def visit(self, node, tabs): + pass + + @visitor.when(UnaryNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__ {node.__class__.__name__}" + child = self.visit(node.node, tabs + 1) + return f"{ans}\n{child}" + + @visitor.when(BinaryNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__ {node.__class__.__name__} " + left = self.visit(node.left, tabs + 1) + right = self.visit(node.right, tabs + 1) + return f"{ans}\n{left}\n{right}" + + @visitor.when(AtomicNode) + def visit(self, node, tabs=0): + return "\t" * tabs + f"\\__ {node.__class__.__name__}: {node.lex}" + + printer = PrintVisitor() + return lambda ast: printer.visit(ast) + diff --git a/src/cmp/automata.py b/src/cmp/automata.py new file mode 100644 index 000000000..4d2619364 --- /dev/null +++ b/src/cmp/automata.py @@ -0,0 +1,224 @@ +try: + import pydot +except: + pass + + +class State: + def __init__(self, state, final=False, formatter=lambda x: str(x), shape="circle"): + self.state = state + self.final = final + self.transitions = {} + self.epsilon_transitions = set() + self.tag = None + self.formatter = formatter + self.shape = shape + + # The method name is set this way from compatibility issues. + def set_formatter(self, value, attr="formatter", visited=None): + if visited is None: + visited = set() + elif self in visited: + return + + visited.add(self) + self.__setattr__(attr, value) + for destinations in self.transitions.values(): + for node in destinations: + node.set_formatter(value, attr, visited) + for node in self.epsilon_transitions: + node.set_formatter(value, attr, visited) + return self + + def has_transition(self, symbol): + return symbol in self.transitions + + def add_transition(self, symbol, state): + try: + self.transitions[symbol].append(state) + except: + self.transitions[symbol] = [state] + return self + + def add_epsilon_transition(self, state): + self.epsilon_transitions.add(state) + return self + + def recognize(self, string): + states = self.epsilon_closure + for symbol in string: + states = self.move_by_state(symbol, *states) + states = self.epsilon_closure_by_state(*states) + return any(s.final for s in states) + + def to_deterministic(self, formatter=lambda x: str(x)): + closure = self.epsilon_closure + start = State(tuple(closure), any(s.final for s in closure), formatter) + + closures = [closure] + states = [start] + pending = [start] + + while pending: + state = pending.pop() + symbols = {symbol for s in state.state for symbol in s.transitions} + + for symbol in symbols: + move = self.move_by_state(symbol, *state.state) + closure = self.epsilon_closure_by_state(*move) + + if closure not in closures: + new_state = State( + tuple(closure), any(s.final for s in closure), formatter + ) + closures.append(closure) + states.append(new_state) + pending.append(new_state) + else: + index = closures.index(closure) + new_state = states[index] + + state.add_transition(symbol, new_state) + + return start + + @staticmethod + def from_nfa(nfa, get_states=False): + states = [] + for n in range(nfa.states): + state = State(n, n in nfa.finals) + states.append(state) + + for (origin, symbol), destinations in nfa.map.items(): + origin = states[origin] + origin[symbol] = [states[d] for d in destinations] + + if get_states: + return states[nfa.start], states + return states[nfa.start] + + @staticmethod + def move_by_state(symbol, *states): + return { + s for state in states if state.has_transition(symbol) for s in state[symbol] + } + + @staticmethod + def epsilon_closure_by_state(*states): + closure = {state for state in states} + + l = 0 + while l != len(closure): + l = len(closure) + tmp = [s for s in closure] + for s in tmp: + for epsilon_state in s.epsilon_transitions: + closure.add(epsilon_state) + return closure + + @property + def epsilon_closure(self): + return self.epsilon_closure_by_state(self) + + @property + def name(self): + return self.formatter(self.state) + + def get(self, symbol): + target = self.transitions[symbol] + assert len(target) == 1 + return target[0] + + def __getitem__(self, symbol): + if symbol == "": + return self.epsilon_transitions + try: + return self.transitions[symbol] + except KeyError: + return None + + def __setitem__(self, symbol, value): + if symbol == "": + self.epsilon_transitions = value + else: + self.transitions[symbol] = value + + def __repr__(self): + return str(self) + + def __str__(self): + return str(self.state) + + def __hash__(self): + return hash(self.state) + + def __iter__(self): + yield from self._visit() + + def _visit(self, visited=None): + if visited is None: + visited = set() + elif self in visited: + return + + visited.add(self) + yield self + + for destinations in self.transitions.values(): + for node in destinations: + yield from node._visit(visited) + for node in self.epsilon_transitions: + yield from node._visit(visited) + + def graph(self): + G = pydot.Dot(rankdir="LR", margin=0.1) + G.add_node(pydot.Node("start", shape="plaintext", label="", width=0, height=0)) + + visited = set() + + def visit(start): + ids = id(start) + if ids not in visited: + visited.add(ids) + G.add_node( + pydot.Node( + ids, + label=start.name, + shape=self.shape, + style="bold" if start.final else "", + ) + ) + for tran, destinations in start.transitions.items(): + for end in destinations: + visit(end) + G.add_edge( + pydot.Edge(ids, id(end), label=tran, labeldistance=2) + ) + for end in start.epsilon_transitions: + visit(end) + G.add_edge(pydot.Edge(ids, id(end), label="ε", labeldistance=2)) + + visit(self) + G.add_edge(pydot.Edge("start", id(self), label="", style="dashed")) + + return G + + def _repr_svg_(self): + try: + return self.graph().create_svg().decode("utf8") + except: + pass + + def write_to(self, fname): + return self.graph().write_svg(fname) + + +def multiline_formatter(state): + return "\n".join(str(item) for item in state) + + +def lr0_formatter(state): + try: + return "\n".join(str(item)[:-4] for item in state) + except TypeError: + return str(state)[:-4] diff --git a/src/cmp/cil.py b/src/cmp/cil.py new file mode 100644 index 000000000..5864ccdd0 --- /dev/null +++ b/src/cmp/cil.py @@ -0,0 +1,267 @@ +import src.cmp.visitor as visitor + + +class Node: + pass + + +class ProgramNode(Node): + def __init__(self, dottypes, dotdata, dotcode): + self.dottypes = dottypes + self.dotdata = dotdata + self.dotcode = dotcode + + +class TypeNode(Node): + def __init__(self, name): + self.name = name + self.attributes = [] + self.methods = [] + + +class DataNode(Node): + def __init__(self, vname, value): + self.name = vname + self.value = value + + +class FunctionNode(Node): + def __init__(self, fname, params, localvars, instructions): + self.name = fname + self.params = params + self.localvars = localvars + self.instructions = instructions + + +class ParamNode(Node): + def __init__(self, name): + self.name = name + + +class LocalNode(Node): + def __init__(self, name): + self.name = name + + +class InstructionNode(Node): + pass + + +class AssignNode(InstructionNode): + def __init__(self, dest, source): + self.dest = dest + self.source = source + + +class ArithmeticNode(InstructionNode): + def __init__(self, dest, left, right): + self.dest = dest + self.left = left + self.right = right + + +class PlusNode(ArithmeticNode): + pass + + +class MinusNode(ArithmeticNode): + pass + + +class StarNode(ArithmeticNode): + pass + + +class DivNode(ArithmeticNode): + pass + + +class GetAttribNode(InstructionNode): + pass + + +class SetAttribNode(InstructionNode): + pass + + +class GetIndexNode(InstructionNode): + pass + + +class SetIndexNode(InstructionNode): + pass + + +class AllocateNode(InstructionNode): + def __init__(self, itype, dest): + self.type = itype + self.dest = dest + + +class ArrayNode(InstructionNode): + pass + + +class TypeOfNode(InstructionNode): + def __init__(self, obj, dest): + self.obj = obj + self.dest = dest + + +class LabelNode(InstructionNode): + pass + + +class GotoNode(InstructionNode): + pass + + +class GotoIfNode(InstructionNode): + pass + + +class StaticCallNode(InstructionNode): + def __init__(self, function, dest): + self.function = function + self.dest = dest + + +class DynamicCallNode(InstructionNode): + def __init__(self, xtype, method, dest): + self.type = xtype + self.method = method + self.dest = dest + + +class ArgNode(InstructionNode): + def __init__(self, name): + self.name = name + + +class ReturnNode(InstructionNode): + def __init__(self, value=None): + self.value = value + + +class LoadNode(InstructionNode): + def __init__(self, dest, msg): + self.dest = dest + self.msg = msg + + +class LengthNode(InstructionNode): + pass + + +class ConcatNode(InstructionNode): + pass + + +class PrefixNode(InstructionNode): + pass + + +class SubstringNode(InstructionNode): + pass + + +class ToStrNode(InstructionNode): + def __init__(self, dest, ivalue): + self.dest = dest + self.ivalue = ivalue + + +class ReadNode(InstructionNode): + def __init__(self, dest): + self.dest = dest + + +class PrintNode(InstructionNode): + def __init__(self, str_addr): + self.str_addr = str_addr + + +def get_formatter(): + class PrintVisitor(object): + @visitor.on("node") + def visit(self, node): + pass + + @visitor.when(ProgramNode) + def visit(self, node): + dottypes = "\n".join(self.visit(t) for t in node.dottypes) + dotdata = "\n".join(self.visit(t) for t in node.dotdata) + dotcode = "\n".join(self.visit(t) for t in node.dotcode) + + return f".TYPES\n{dottypes}\n\n.DATA\n{dotdata}\n\n.CODE\n{dotcode}" + + @visitor.when(TypeNode) + def visit(self, node): + attributes = "\n\t".join(f"attribute {x}" for x in node.attributes) + methods = "\n\t".join(f"method {x}: {y}" for x, y in node.methods) + + return f"type {node.name} {{\n\t{attributes}\n\n\t{methods}\n}}" + + @visitor.when(FunctionNode) + def visit(self, node): + params = "\n\t".join(self.visit(x) for x in node.params) + localvars = "\n\t".join(self.visit(x) for x in node.localvars) + instructions = "\n\t".join(self.visit(x) for x in node.instructions) + + return f"function {node.name} {{\n\t{params}\n\n\t{localvars}\n\n\t{instructions}\n}}" + + @visitor.when(ParamNode) + def visit(self, node): + return f"PARAM {node.name}" + + @visitor.when(LocalNode) + def visit(self, node): + return f"LOCAL {node.name}" + + @visitor.when(AssignNode) + def visit(self, node): + return f"{node.dest} = {node.source}" + + @visitor.when(PlusNode) + def visit(self, node): + return f"{node.dest} = {node.left} + {node.right}" + + @visitor.when(MinusNode) + def visit(self, node): + return f"{node.dest} = {node.left} - {node.right}" + + @visitor.when(StarNode) + def visit(self, node): + return f"{node.dest} = {node.left} * {node.right}" + + @visitor.when(DivNode) + def visit(self, node): + return f"{node.dest} = {node.left} / {node.right}" + + @visitor.when(AllocateNode) + def visit(self, node): + return f"{node.dest} = ALLOCATE {node.type}" + + @visitor.when(TypeOfNode) + def visit(self, node): + return f"{node.dest} = TYPEOF {node.type}" + + @visitor.when(StaticCallNode) + def visit(self, node): + return f"{node.dest} = CALL {node.function}" + + @visitor.when(DynamicCallNode) + def visit(self, node): + return f"{node.dest} = VCALL {node.type} {node.method}" + + @visitor.when(ArgNode) + def visit(self, node): + return f"ARG {node.name}" + + @visitor.when(ReturnNode) + def visit(self, node): + return f'RETURN {node.value if node.value is not None else ""}' + + printer = PrintVisitor() + return lambda ast: printer.visit(ast) + diff --git a/src/cmp/evaluation.py b/src/cmp/evaluation.py new file mode 100644 index 000000000..830703efe --- /dev/null +++ b/src/cmp/evaluation.py @@ -0,0 +1,36 @@ +from src.cmp.pycompiler import EOF +from src.shift_reduce_parsers import ShiftReduceParser + + +def evaluate_reverse_parse(right_parse, operations, tokens): + if not right_parse or not operations or not tokens: + return + + right_parse = iter(right_parse) + tokens = iter(tokens) + stack = [] + for operation in operations: + if operation == ShiftReduceParser.SHIFT: + token = next(tokens) + stack.append(token.lex) + elif operation == ShiftReduceParser.REDUCE: + production = next(right_parse) + head, body = production + attributes = production.attributes + assert all( + rule is None for rule in attributes[1:] + ), "There must be only synteticed attributes." + rule = attributes[0] + + if len(body): + synteticed = [None] + stack[-len(body) :] + value = rule(None, synteticed) + stack[-len(body) :] = [value] + else: + stack.append(rule(None, None)) + else: + raise Exception("Invalid action!!!") + + assert len(stack) == 1 + assert isinstance(next(tokens).token_type, EOF) + return stack[0] diff --git a/src/cmp/nbpackage.py b/src/cmp/nbpackage.py new file mode 100644 index 000000000..5458e63b9 --- /dev/null +++ b/src/cmp/nbpackage.py @@ -0,0 +1,87 @@ +import io, os, sys, types + +from IPython import get_ipython +from nbformat import read +from IPython.core.interactiveshell import InteractiveShell + +def find_notebook(fullname, path=None): + """find a notebook, given its fully qualified name and an optional path + + This turns "foo.bar" into "foo/bar.ipynb" + and tries turning "Foo_Bar" into "Foo Bar" if Foo_Bar + does not exist. + """ + name = fullname.rsplit('.', 1)[-1] + if not path: + path = [''] + for d in path: + nb_path = os.path.join(d, name + ".ipynb") + if os.path.isfile(nb_path): + return nb_path + # let import Notebook_Name find "Notebook Name.ipynb" + nb_path = nb_path.replace("_", " ") + if os.path.isfile(nb_path): + return nb_path + +class NotebookLoader(object): + """Module Loader for Jupyter Notebooks""" + def __init__(self, path=None): + self.shell = InteractiveShell.instance() + self.path = path + + def load_module(self, fullname): + """import a notebook as a module""" + path = find_notebook(fullname, self.path) + + print ("importing Jupyter notebook from %s" % path) + + # load the notebook object + with io.open(path, 'r', encoding='utf-8') as f: + nb = read(f, 4) + + + # create the module and add it to sys.modules + # if name in sys.modules: + # return sys.modules[name] + mod = types.ModuleType(fullname) + mod.__file__ = path + mod.__loader__ = self + mod.__dict__['get_ipython'] = get_ipython + sys.modules[fullname] = mod + + # extra work to ensure that magics that would affect the user_ns + # actually affect the notebook module's ns + save_user_ns = self.shell.user_ns + self.shell.user_ns = mod.__dict__ + + try: + for cell in nb.cells: + if cell.cell_type == 'code': + # transform the input to executable Python + code = self.shell.input_transformer_manager.transform_cell(cell.source) + # run the code in themodule + exec(code, mod.__dict__) + finally: + self.shell.user_ns = save_user_ns + return mod + +class NotebookFinder(object): + """Module finder that locates Jupyter Notebooks""" + def __init__(self): + self.loaders = {} + + def find_module(self, fullname, path=None): + nb_path = find_notebook(fullname, path) + if not nb_path: + return + + key = path + if path: + # lists aren't hashable + key = os.path.sep.join(path) + + if key not in self.loaders: + self.loaders[key] = NotebookLoader(path) + return self.loaders[key] + +sys.meta_path.append(NotebookFinder()) \ No newline at end of file diff --git a/src/cmp/pycompiler.py b/src/cmp/pycompiler.py new file mode 100644 index 000000000..b78f03f70 --- /dev/null +++ b/src/cmp/pycompiler.py @@ -0,0 +1,512 @@ +import json + +class Symbol(object): + + def __init__(self, name, grammar): + self.Name = name + self.Grammar = grammar + + def __str__(self): + return self.Name + + def __repr__(self): + return repr(self.Name) + + def __add__(self, other): + if isinstance(other, Symbol): + return Sentence(self, other) + + raise TypeError(other) + + def __or__(self, other): + + if isinstance(other, (Sentence)): + return SentenceList(Sentence(self), other) + + raise TypeError(other) + + @property + def IsEpsilon(self): + return False + + def __len__(self): + return 1 + +class NonTerminal(Symbol): + + + def __init__(self, name, grammar): + super().__init__(name, grammar) + self.productions = [] + + + def __imod__(self, other): + + if isinstance(other, (Sentence)): + p = Production(self, other) + self.Grammar.Add_Production(p) + return self + + if isinstance(other, tuple): + assert len(other) > 1 + + if len(other) == 2: + other += (None,) * len(other[0]) + + assert len(other) == len(other[0]) + 2, "Debe definirse una, y solo una, regla por cada símbolo de la producción" + # assert len(other) == 2, "Tiene que ser una Tupla de 2 elementos (sentence, attribute)" + + if isinstance(other[0], Symbol) or isinstance(other[0], Sentence): + p = AttributeProduction(self, other[0], other[1:]) + else: + raise Exception("") + + self.Grammar.Add_Production(p) + return self + + if isinstance(other, Symbol): + p = Production(self, Sentence(other)) + self.Grammar.Add_Production(p) + return self + + if isinstance(other, SentenceList): + + for s in other: + p = Production(self, s) + self.Grammar.Add_Production(p) + + return self + + raise TypeError(other) + + @property + def IsTerminal(self): + return False + + @property + def IsNonTerminal(self): + return True + + @property + def IsEpsilon(self): + return False + +class Terminal(Symbol): + + def __init__(self, name, grammar): + super().__init__(name, grammar) + + @property + def IsTerminal(self): + return True + + @property + def IsNonTerminal(self): + return False + + @property + def IsEpsilon(self): + return False + +class EOF(Terminal): + + def __init__(self, Grammar): + super().__init__('$', Grammar) + +class Sentence(object): + + def __init__(self, *args): + self._symbols = tuple(x for x in args if not x.IsEpsilon) + self.hash = hash(self._symbols) + + def __len__(self): + return len(self._symbols) + + def __add__(self, other): + if isinstance(other, Symbol): + return Sentence(*(self._symbols + (other,))) + + if isinstance(other, Sentence): + return Sentence(*(self._symbols + other._symbols)) + + raise TypeError(other) + + def __or__(self, other): + if isinstance(other, Sentence): + return SentenceList(self, other) + + if isinstance(other, Symbol): + return SentenceList(self, Sentence(other)) + + raise TypeError(other) + + def __repr__(self): + return str(self) + + def __str__(self): + return ("%s " * len(self._symbols) % tuple(self._symbols)).strip() + + def __iter__(self): + return iter(self._symbols) + + def __getitem__(self, index): + return self._symbols[index] + + def __eq__(self, other): + return self._symbols == other._symbols + + def __hash__(self): + return self.hash + + @property + def IsEpsilon(self): + return False + +class SentenceList(object): + + def __init__(self, *args): + self._sentences = list(args) + + def Add(self, symbol): + if not symbol and (symbol is None or not symbol.IsEpsilon): + raise ValueError(symbol) + + self._sentences.append(symbol) + + def __iter__(self): + return iter(self._sentences) + + def __or__(self, other): + if isinstance(other, Sentence): + self.Add(other) + return self + + if isinstance(other, Symbol): + return self | Sentence(other) + + +class Epsilon(Terminal, Sentence): + + def __init__(self, grammar): + super().__init__('epsilon', grammar) + + + def __str__(self): + return "e" + + def __repr__(self): + return 'epsilon' + + def __iter__(self): + yield from () + + def __len__(self): + return 0 + + def __add__(self, other): + return other + + def __eq__(self, other): + return isinstance(other, (Epsilon,)) + + def __hash__(self): + return hash("") + + @property + def IsEpsilon(self): + return True + +class Production(object): + + def __init__(self, nonTerminal, sentence): + + self.Left = nonTerminal + self.Right = sentence + + def __str__(self): + + return '%s := %s' % (self.Left, self.Right) + + def __repr__(self): + return '%s -> %s' % (self.Left, self.Right) + + def __iter__(self): + yield self.Left + yield self.Right + + def __eq__(self, other): + return isinstance(other, Production) and self.Left == other.Left and self.Right == other.Right + + def __hash__(self): + return hash((self.Left, self.Right)) + + @property + def IsEpsilon(self): + return self.Right.IsEpsilon + +class AttributeProduction(Production): + + def __init__(self, nonTerminal, sentence, attributes): + if not isinstance(sentence, Sentence) and isinstance(sentence, Symbol): + sentence = Sentence(sentence) + super(AttributeProduction, self).__init__(nonTerminal, sentence) + + self.attributes = attributes + + def __str__(self): + return '%s := %s' % (self.Left, self.Right) + + def __repr__(self): + return '%s -> %s' % (self.Left, self.Right) + + def __iter__(self): + yield self.Left + yield self.Right + + + @property + def IsEpsilon(self): + return self.Right.IsEpsilon + + # sintetizar en ingles??????, pending aggrement + def syntetice(self): + pass + +class Grammar(): + + def __init__(self): + + self.Productions = [] + self.nonTerminals = [] + self.terminals = [] + self.startSymbol = None + # production type + self.pType = None + self.Epsilon = Epsilon(self) + self.EOF = EOF(self) + + self.symbDict = { '$': self.EOF } + + def NonTerminal(self, name, startSymbol = False): + + name = name.strip() + if not name: + raise Exception("Empty name") + + term = NonTerminal(name,self) + + if startSymbol: + + if self.startSymbol is None: + self.startSymbol = term + else: + raise Exception("Cannot define more than one start symbol.") + + self.nonTerminals.append(term) + self.symbDict[name] = term + return term + + def NonTerminals(self, names): + + ans = tuple((self.NonTerminal(x) for x in names.strip().split())) + + return ans + + + def Add_Production(self, production): + + if len(self.Productions) == 0: + self.pType = type(production) + + assert type(production) == self.pType, "The Productions most be of only 1 type." + + production.Left.productions.append(production) + self.Productions.append(production) + + + def Terminal(self, name): + + name = name.strip() + if not name: + raise Exception("Empty name") + + term = Terminal(name, self) + self.terminals.append(term) + self.symbDict[name] = term + return term + + def Terminals(self, names): + + ans = tuple((self.Terminal(x) for x in names.strip().split())) + + return ans + + + def __str__(self): + + mul = '%s, ' + + ans = 'Non-Terminals:\n\t' + + nonterminals = mul * (len(self.nonTerminals)-1) + '%s\n' + + ans += nonterminals % tuple(self.nonTerminals) + + ans += 'Terminals:\n\t' + + terminals = mul * (len(self.terminals)-1) + '%s\n' + + ans += terminals % tuple(self.terminals) + + ans += 'Productions:\n\t' + + ans += str(self.Productions) + + return ans + + def __getitem__(self, name): + try: + return self.symbDict[name] + except KeyError: + return None + + @property + def to_json(self): + + productions = [] + + for p in self.Productions: + head = p.Left.Name + + body = [] + + for s in p.Right: + body.append(s.Name) + + productions.append({'Head':head, 'Body':body}) + + d={'NonTerminals':[symb.Name for symb in self.nonTerminals], 'Terminals': [symb.Name for symb in self.terminals],\ + 'Productions':productions} + + # [{'Head':p.Left.Name, "Body": [s.Name for s in p.Right]} for p in self.Productions] + return json.dumps(d) + + @staticmethod + def from_json(data): + data = json.loads(data) + + G = Grammar() + dic = {'epsilon':G.Epsilon} + + for term in data['Terminals']: + dic[term] = G.Terminal(term) + + for noTerm in data['NonTerminals']: + dic[noTerm] = G.NonTerminal(noTerm) + + for p in data['Productions']: + head = p['Head'] + dic[head] %= Sentence(*[dic[term] for term in p['Body']]) + + return G + + def copy(self): + G = Grammar() + G.Productions = self.Productions.copy() + G.nonTerminals = self.nonTerminals.copy() + G.terminals = self.terminals.copy() + G.pType = self.pType + G.startSymbol = self.startSymbol + G.Epsilon = self.Epsilon + G.EOF = self.EOF + G.symbDict = self.symbDict.copy() + + return G + + @property + def IsAugmentedGrammar(self): + augmented = 0 + for left, right in self.Productions: + if self.startSymbol == left: + augmented += 1 + if augmented <= 1: + return True + else: + return False + + def AugmentedGrammar(self, force=False): + if not self.IsAugmentedGrammar or force: + + G = self.copy() + # S, self.startSymbol, SS = self.startSymbol, None, self.NonTerminal('S\'', True) + S = G.startSymbol + G.startSymbol = None + SS = G.NonTerminal('S\'', True) + if G.pType is AttributeProduction: + SS %= S + G.Epsilon, lambda x : x + else: + SS %= S + G.Epsilon + + return G + else: + return self.copy() + #endchange + +class Item: + + def __init__(self, production, pos, lookaheads=[]): + self.production = production + self.pos = pos + self.lookaheads = frozenset(look for look in lookaheads) + + def __str__(self): + s = str(self.production.Left) + " -> " + if len(self.production.Right) > 0: + for i,c in enumerate(self.production.Right): + if i == self.pos: + s += "." + s += str(self.production.Right[i]) + if self.pos == len(self.production.Right): + s += "." + else: + s += "." + s += ", " + str(self.lookaheads)[10:-1] + return s + + def __repr__(self): + return str(self) + + + def __eq__(self, other): + return ( + (self.pos == other.pos) and + (self.production == other.production) and + (set(self.lookaheads) == set(other.lookaheads)) + ) + + def __hash__(self): + return hash((self.production,self.pos,self.lookaheads)) + + @property + def IsReduceItem(self): + return len(self.production.Right) == self.pos + + @property + def NextSymbol(self): + if self.pos < len(self.production.Right): + return self.production.Right[self.pos] + else: + return None + + def NextItem(self): + if self.pos < len(self.production.Right): + return Item(self.production,self.pos+1,self.lookaheads) + else: + return None + + def Preview(self, skip=1): + unseen = self.production.Right[self.pos+skip:] + return [ unseen + (lookahead,) for lookahead in self.lookaheads ] + + def Center(self): + return Item(self.production, self.pos) \ No newline at end of file diff --git a/src/cmp/semantic.py b/src/cmp/semantic.py new file mode 100644 index 000000000..787a53a4a --- /dev/null +++ b/src/cmp/semantic.py @@ -0,0 +1,276 @@ +import itertools as itt +from collections import OrderedDict + + +class SemanticError(Exception): + @property + def text(self): + return self.args[0] + + +class Attribute: + def __init__(self, name, typex): + self.name = name + self.type = typex + + def __str__(self): + return f"[attrib] {self.name} : {self.type.name};" + + def __repr__(self): + return str(self) + + +class Method: + def __init__(self, name, param_names, params_types, return_type): + self.name = name + self.param_names = param_names + self.param_types = params_types + self.return_type = return_type + + def __str__(self): + params = ", ".join( + f"{n}:{t.name}" for n, t in zip(self.param_names, self.param_types) + ) + return f"[method] {self.name}({params}): {self.return_type.name};" + + def __eq__(self, other): + return ( + other.name == self.name + and other.return_type == self.return_type + and other.param_types == self.param_types + ) + + +class Type: + def __init__(self, name: str): + self.name = name + self.attributes = [] + self.methods = [] + self.parent = None + + def set_parent(self, parent): + if self.parent is not None: + raise SemanticError(f"Parent type is already set for {self.name}.") + self.parent = parent + + def get_attribute(self, name: str): + try: + return next(attr for attr in self.attributes if attr.name == name) + except StopIteration: + if self.parent is None: + raise SemanticError( + f'Attribute "{name}" is not defined in {self.name}.' + ) + try: + return self.parent.get_attribute(name) + except SemanticError: + raise SemanticError( + f'Attribute "{name}" is not defined in {self.name}.' + ) + + def define_attribute(self, name: str, typex): + try: + self.get_attribute(name) + except SemanticError: + attribute = Attribute(name, typex) + self.attributes.append(attribute) + return attribute + else: + raise SemanticError( + f'Attribute "{name}" is already defined in {self.name}.' + ) + + def get_method(self, name: str): + try: + return next(method for method in self.methods if method.name == name) + except StopIteration: + if self.parent is None: + raise SemanticError(f'Method "{name}" is not defined in {self.name}.') + try: + return self.parent.get_method(name) + except SemanticError: + raise SemanticError(f'Method "{name}" is not defined in {self.name}.') + + def define_method( + self, name: str, param_names: list, param_types: list, return_type + ): + if name in (method.name for method in self.methods): + raise SemanticError(f'Method "{name}" already defined in {self.name}') + + method = Method(name, param_names, param_types, return_type) + self.methods.append(method) + return method + + def all_attributes(self, clean=True): + plain = ( + OrderedDict() if self.parent is None else self.parent.all_attributes(False) + ) + for attr in self.attributes: + plain[attr.name] = (attr, self) + return plain.values() if clean else plain + + def all_methods(self, clean=True): + plain = OrderedDict() if self.parent is None else self.parent.all_methods(False) + for method in self.methods: + plain[method.name] = (method, self) + return plain.values() if clean else plain + + def conforms_to(self, other): + + return ( + other.bypass() + or self == other + or self.name == "AUTO_TYPE" + or other.name == "AUTO_TYPE" + or self.parent is not None + and self.parent.conforms_to(other) + ) + + def bypass(self): + return False + + def __str__(self): + output = f"type {self.name}" + parent = "" if self.parent is None else f" : {self.parent.name}" + output += parent + output += " {" + output += "\n\t" if self.attributes or self.methods else "" + output += "\n\t".join(str(x) for x in self.attributes) + output += "\n\t" if self.attributes else "" + output += "\n\t".join(str(x) for x in self.methods) + output += "\n" if self.methods else "" + output += "}\n" + return output + + def __repr__(self): + return str(self) + + +class ErrorType(Type): + def __init__(self): + Type.__init__(self, "") + + def conforms_to(self, other): + return True + + def bypass(self): + return True + + def __eq__(self, other): + return isinstance(other, Type) + + +class VoidType(Type): + def __init__(self): + Type.__init__(self, "Void") + + def conforms_to(self, other): + raise Exception("Invalid type at 'conforms_to' : void type.") + + def bypass(self): + return True + + def __eq__(self, other): + return isinstance(other, VoidType) + + +class IntType(Type): + def __init__(self): + Type.__init__(self, "Int") + + def __eq__(self, other): + return other.name == self.name or isinstance(other, IntType) + + +class StringType(Type): + def __init__(self): + Type.__init__(self, "String") + + +class BoolType(Type): + def __init__(self): + Type.__init__(self, "Bool") + + +class AutoType(Type): + def __init__(self): + Type.__init__(self, "AUTO_TYPE") + + +class ObjectType(Type): + def __init__(self): + Type.__init__(self, "Object") + + +class SelfType(Type): + def __init__(self): + Type.__init__(self, "SELF_TYPE") + + +class Context: + def __init__(self): + self.types = {} + + def create_type(self, name: str): + if name in self.types: + raise SemanticError(f"Type with the same name ({name}) already in context.") + typex = self.types[name] = Type(name) + return typex + + def get_type(self, name: str): + try: + return self.types[name] + except KeyError: + raise SemanticError(f'Type "{name}" is not defined.') + + def __str__(self): + return ( + "{\n\t" + + "\n\t".join(y for x in self.types.values() for y in str(x).split("\n")) + + "\n}" + ) + + def __repr__(self): + return str(self) + + +class VariableInfo: + def __init__(self, name, vtype): + self.name = name + self.type = vtype + + +class Scope: + def __init__(self, parent=None): + self.locals = [] + self.parent = parent + self.children = [] + self.index = 0 if parent is None else len(parent) + + def __len__(self): + return len(self.locals) + + def create_child(self): + child = Scope(self) + self.children.append(child) + return child + + def define_variable(self, vname, vtype): + info = VariableInfo(vname, vtype) + self.locals.append(info) + return info + + def find_variable(self, vname, index=None): + locals = self.locals if index is None else itt.islice(self.locals, index) + try: + return next(x for x in locals if x.name == vname) + except StopIteration: + if self.parent is not None: + return self.parent.find_variable(vname, self.index) + return None + + def is_defined(self, vname): + return self.find_variable(vname) is not None + + def is_local(self, vname): + return any(True for x in self.locals if x.name == vname) diff --git a/src/cmp/tools/.ipynb_checkpoints/__init__-checkpoint.py b/src/cmp/tools/.ipynb_checkpoints/__init__-checkpoint.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/cmp/tools/.ipynb_checkpoints/automata-checkpoint.py b/src/cmp/tools/.ipynb_checkpoints/automata-checkpoint.py new file mode 100644 index 000000000..59643cc5b --- /dev/null +++ b/src/cmp/tools/.ipynb_checkpoints/automata-checkpoint.py @@ -0,0 +1,3 @@ +import zlib, base64 +exec(zlib.decompress(base64.b64decode('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'))) +# Created by pyminifier (https://github.com/liftoff/pyminifier) diff --git a/src/cmp/tools/.ipynb_checkpoints/evaluation-checkpoint.py b/src/cmp/tools/.ipynb_checkpoints/evaluation-checkpoint.py new file mode 100644 index 000000000..d49df0ce5 --- /dev/null +++ b/src/cmp/tools/.ipynb_checkpoints/evaluation-checkpoint.py @@ -0,0 +1,3 @@ +import zlib, base64 +exec(zlib.decompress(base64.b64decode('eJxdUMFuwjAMvecrfGy3qoLrJN86YGViCO2GECrF1SLSpErcqf37OUWwsZPtZ/v5+TXetVC3Xd6NtWs7bciDbjvnGV4/FmqJmsmrE1oaWFnUQdvAla1JFbhxltQaDVm1QLJ9S75iUmdqgL4r00tx7CofKGmyMn1RoBuwjqEB56ekFAw8ce+tggaXSZMqKCWWEge8kSQnaWSRQ0EVAok2K1iZ5uwuZI88dpSJWmlfyWB4EJF03p37mrWzkSXT9ou8/HU+xgHCImrbZAZ/5xSMf6q8Yvb61DMFBYz74vCUrBOTPs/l5OV/vZ8d8N8J+U5e1tkOtIVFYrJ5PBn92OVv4ZN8q21lInR78LLXBx2giBBLjtO/hgYByASaZld4miy7b+0QV/k7NRyxLY6yGDO5swVhi54X0+bEj9vkknF6P3H3azXZFEekGWlmh7u1150HxkmQSP0BhJm25Q=='))) +# Created by pyminifier (https://github.com/liftoff/pyminifier) diff --git a/src/cmp/tools/.ipynb_checkpoints/parsing-checkpoint.py b/src/cmp/tools/.ipynb_checkpoints/parsing-checkpoint.py new file mode 100644 index 000000000..02d672f4b --- /dev/null +++ b/src/cmp/tools/.ipynb_checkpoints/parsing-checkpoint.py @@ -0,0 +1,10 @@ +import zlib, base64 +exec(zlib.decompress(base64.b64decode('eJytVVtr2zAUfvevEH2yqWfa14AeypKGlXlNL5SCMUZO5FTMlhRZbpZu++87ujiOm3QwGJRU56pzvu8cuVKiQUxTpYWoW8QaKZRGrK3ZkgaVMS4bmXSaDcbPgmvCOFUPVAcrWqGlaGSnaVGLJamLiqlWh/a3jUktX0g0CVCFnSZAEltlgKb4MFMYBUirHbiiBZbJl3YmW1YLHiD6Y0mldoZrUrc0QKxCC6OYJi3VBXWeJgMFszFUQqE5YhxJI6EUV9k8N6dp0skV0TRMIyNCIi40SpOlK6Xtk9kwVCpKvsOpT3t8oaK6UxxNR0C4VsO5a/zn7wDN8KPqoHBTV2nqmieAecM49GPrzcp8DEcZOW/tvLngj+MAnR/ht31hNUUzY5/1UNkkty7JQolVt9RMcJsDPePb5CuttDlLON+z9YsVrgCvZ4uXpwQ6B5W0qoGPXntUCEI3+ORUxNJaZ7/wNHkhalV4Nm569dWR2iNcjREWdS22AHHssB6P2GaEObXSX7DcnMJyk82TVhOlH3ZNKep3DvNkdnv9PxG/xxuPuIlmcbszCSjvGqoMEjJygMPAtjvYjm9DD86A7iBDu8udsKcN8pWYZjJm3nLI3oHxA7rcQxCCx/llDHfSKHKRQNVdv0pV6ZVQXFV+sErjkPuB2I0ltuxYvSokUS3j60KTsqZ7cmPP9pjkCo5OH8B+9xSTk7g/Y9LDvoBjj7oJoCagyhb5ZDTuafYc0zwhUlK+Ckn0fvCdHWfEwGr6hgynOx8uMTvlogd6Tt0z5ujwJg9ZaiFrqBYrUUhFVwxafRUFF4Wiyw4wfBWAXooNYx5Ef3aIWcHCyQY8xYAnNJTCRwAZt4lvkB0qTODRa+cdxdhR4FNLa5xT/BHrUCc42CbDrZ38J5zZnYvHWwmWpsEX8O8NZ0ZyC2kW396+xk+JFNK9SQRvs6bJ/bu/hi0ar5BRYkwm+2EGyV7aT3D/OUAHXwRkKjjHl8E7rVSM6/BsppRQCboq4csJPSZJcuaXxXNpgApGocNwLHCarWOSZxd+ee3bYGZJEb6mYU15uHDTHH26jO1f1Ff11A+V98hY7m9+21tOjNs/1u2lt/1sNsEfuhaMXQ=='))) +# Created by pyminifier (https://github.com/liftoff/pyminifier) + +deprecated_metodo_predictivo_no_recursivo = metodo_predictivo_no_recursivo +def metodo_predictivo_no_recursivo(G, M=None, firsts=None, follows=None): + parser = deprecated_metodo_predictivo_no_recursivo(G, M, firsts, follows) + def updated(tokens): + return parser([t.token_type for t in tokens]) + return updated \ No newline at end of file diff --git a/src/cmp/tools/__init__.py b/src/cmp/tools/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/cmp/tools/automata.py b/src/cmp/tools/automata.py new file mode 100644 index 000000000..59643cc5b --- /dev/null +++ b/src/cmp/tools/automata.py @@ -0,0 +1,3 @@ +import zlib, base64 +exec(zlib.decompress(base64.b64decode('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'))) +# Created by pyminifier (https://github.com/liftoff/pyminifier) diff --git a/src/cmp/tools/evaluation.py b/src/cmp/tools/evaluation.py new file mode 100644 index 000000000..d49df0ce5 --- /dev/null +++ b/src/cmp/tools/evaluation.py @@ -0,0 +1,3 @@ +import zlib, base64 +exec(zlib.decompress(base64.b64decode('eJxdUMFuwjAMvecrfGy3qoLrJN86YGViCO2GECrF1SLSpErcqf37OUWwsZPtZ/v5+TXetVC3Xd6NtWs7bciDbjvnGV4/FmqJmsmrE1oaWFnUQdvAla1JFbhxltQaDVm1QLJ9S75iUmdqgL4r00tx7CofKGmyMn1RoBuwjqEB56ekFAw8ce+tggaXSZMqKCWWEge8kSQnaWSRQ0EVAok2K1iZ5uwuZI88dpSJWmlfyWB4EJF03p37mrWzkSXT9ou8/HU+xgHCImrbZAZ/5xSMf6q8Yvb61DMFBYz74vCUrBOTPs/l5OV/vZ8d8N8J+U5e1tkOtIVFYrJ5PBn92OVv4ZN8q21lInR78LLXBx2giBBLjtO/hgYByASaZld4miy7b+0QV/k7NRyxLY6yGDO5swVhi54X0+bEj9vkknF6P3H3azXZFEekGWlmh7u1150HxkmQSP0BhJm25Q=='))) +# Created by pyminifier (https://github.com/liftoff/pyminifier) diff --git a/src/cmp/tools/parsing.py b/src/cmp/tools/parsing.py new file mode 100644 index 000000000..d0275cbcb --- /dev/null +++ b/src/cmp/tools/parsing.py @@ -0,0 +1,16 @@ +import zlib, base64 +exec(zlib.decompress(base64.b64decode('eJytVVtr2zAUfvevEH2yqWfa14AeypKGlXlNL5SCMUZO5FTMlhRZbpZu++87ujiOm3QwGJRU56pzvu8cuVKiQUxTpYWoW8QaKZRGrK3ZkgaVMS4bmXSaDcbPgmvCOFUPVAcrWqGlaGSnaVGLJamLiqlWh/a3jUktX0g0CVCFnSZAEltlgKb4MFMYBUirHbiiBZbJl3YmW1YLHiD6Y0mldoZrUrc0QKxCC6OYJi3VBXWeJgMFszFUQqE5YhxJI6EUV9k8N6dp0skV0TRMIyNCIi40SpOlK6Xtk9kwVCpKvsOpT3t8oaK6UxxNR0C4VsO5a/zn7wDN8KPqoHBTV2nqmieAecM49GPrzcp8DEcZOW/tvLngj+MAnR/ht31hNUUzY5/1UNkkty7JQolVt9RMcJsDPePb5CuttDlLON+z9YsVrgCvZ4uXpwQ6B5W0qoGPXntUCEI3+ORUxNJaZ7/wNHkhalV4Nm569dWR2iNcjREWdS22AHHssB6P2GaEObXSX7DcnMJyk82TVhOlH3ZNKep3DvNkdnv9PxG/xxuPuIlmcbszCSjvGqoMEjJygMPAtjvYjm9DD86A7iBDu8udsKcN8pWYZjJm3nLI3oHxA7rcQxCCx/llDHfSKHKRQNVdv0pV6ZVQXFV+sErjkPuB2I0ltuxYvSokUS3j60KTsqZ7cmPP9pjkCo5OH8B+9xSTk7g/Y9LDvoBjj7oJoCagyhb5ZDTuafYc0zwhUlK+Ckn0fvCdHWfEwGr6hgynOx8uMTvlogd6Tt0z5ujwJg9ZaiFrqBYrUUhFVwxafRUFF4Wiyw4wfBWAXooNYx5Ef3aIWcHCyQY8xYAnNJTCRwAZt4lvkB0qTODRa+cdxdhR4FNLa5xT/BHrUCc42CbDrZ38J5zZnYvHWwmWpsEX8O8NZ0ZyC2kW396+xk+JFNK9SQRvs6bJ/bu/hi0ar5BRYkwm+2EGyV7aT3D/OUAHXwRkKjjHl8E7rVSM6/BsppRQCboq4csJPSZJcuaXxXNpgApGocNwLHCarWOSZxd+ee3bYGZJEb6mYU15uHDTHH26jO1f1Ff11A+V98hY7m9+21tOjNs/1u2lt/1sNsEfuhaMXQ=='))) +# Created by pyminifier (https://github.com/liftoff/pyminifier) + +deprecated_metodo_predictivo_no_recursivo = metodo_predictivo_no_recursivo +def metodo_predictivo_no_recursivo(G, M=None, firsts=None, follows=None): + parser = deprecated_metodo_predictivo_no_recursivo(G, M, firsts, follows) + def updated(tokens): + return parser([t.token_type for t in tokens]) + return updated + +exec(zlib.decompress(base64.b64decode('eJx9U8GO2jAQvfMVZi9JtCFarqiuVLUsRUilWranCEUmGcBaY0e2s3TV7b/X9iQhpaiXxJ4Zv3nzZqYUzBiyOfK9fYKqKeE70wb0bEQ2X5ePzzQKv2hEnuZffnye0wj/zrBe0Wi9cocK9qQouOS2KGIDYp8u0lfQO2WAPjJhIHFoxDuyBV10xy6i/XdmVlquJP31uzMclFWDa7FruKiK2rHk8lBYthMQJy2JWz7/KhDQjBsg35RdnmoBJ5AWqrnWSvfPi5IJ0dVwTg9gC+OFKXRQZliMZeULzR+27lw22ihNH9xRNbZuLM29WdWgma/F4P185ALIs27AA3gECzTg5JOpDyBCqRd2BFbRc46gwcz3fwk2qzWXNg4v0+jDZDJ5f3efj1HavZptE3wXhyRpj5tIZQmXQ6EDF4KQ/4QnA+ddkCojn3ZKW6dulmV36NdgGy2dsNI3kSBuatmBDvLkV9hdZW27MTSMGjK6qJexugZZxZcITBsEuKd5D+lTBti2I/d06m8grtPgBP83D4ZgImxq53ZJ0BxS7lT1Rp0pWPZKE/N22inhRdbgGmagin1MgtmQdFarOkYQ4pYPtB3aHcmA0RV5PSUkLES/Gq2wvaa9LoGfj9jeVmG9mo1uUbrJKOxu5mzabi7s2lABEsfRRU6HI4HK+Tb7wbteJ8fJQIwx6aUPCdI1uCbt1s5/llB7dxwt5SsTvGqLGY/HUTL6AyImjec='))) +# Created by pyminifier (https://github.com/liftoff/pyminifier) + +exec(zlib.decompress(base64.b64decode('eJyFVltP4zoQfu+v8D41OcfHWl6RLJ0KekEgqLg+dKtiGrf1ktiR7RS6iP9+ZuykSYE9ywOKLzPzzTffjLuypiDLomSVV7kjqiiN9eTEaC+UlvZG+t6queKNyR0rhXVKr5urS1OUlZeLlbLOO9osc7MUedxsHZQ7PFa5tI31mZdFL5MrIl9LobMkozo97pEdz9ilfPU3u+LJ5D2iVmRHlCOXRktiLNHGkx07c7C+lbZQWuRgRaz0ldWzeY/c824KSdojKzAbEqVJxqZWbpV8STASeeZfQE40HYINuWdVmQkvk2dYCeckQMbY92wZ3buFLJ3Kje41wTGjpLQmo9/pfYpRcYGBdwy/qqVXRrt5yBpDW+lcMkAsOX97j0DD/QHCWwETJ1J7aTEJ4u0OdyG/fLaCPIG3pSw9OZe7obXGhkM84vfcxcTbJDKWG/MsNlJkLm0AvwXArx1sFBbGUTR/TkMGr/QZAeVMwV2XpO8RfG5cZYE3e5QMYt0mh7T/NYAwV/zWVrJHXjZQeHKFCK/4SOQO9oj4VKc2/0lIRjDQgQRpdBSSBh+TJi+xT6YldJIGjGvjTQ1wSqNEOYqI/qycXzxLq2UewSD8usKdMxRbNEP5YemDdf8xbj6SAu6SJ4lF3qpMZijVx0/OH/s9MuDQB7+kRl6jugPzaVtvtO3qnvNpm1k47SKT4PdDDSKotG04UXlTCC+adrvxwBctqhyaHThfQGw4BnEFsp4qlWeLi+ujRW1ndDLu8JJLWDPnha0BdgWdcn5E+2MrikLYPS2iWheo3gwI0PxwVoBv2JyN2fBqND/UQdiD0zP+23iz7yB/wwOHZ9BrrbR5NKcoE98hfWbmKUq0y5kHNQHFPBCTtHcnKUXVwtmWzzxE2vA3f2zfGxlvUZsXfAudUgbV3vHN7GJey3eK5RwzX48m9/eY6XZSuaDrQxwXAQcha75X7AQU2xVSjYegDlCI6+CG4CBSGhusnQ7kBdCsEc2X8+FD7HUdu7b6Hy7gb8tEWWI7rsP6joksW3grtFNYlmTKLkUh6QuyysC6lVjyhexaeds/PDM3G7Xy1xKqL6dwAopd5iBLAmqN6+TTDVQuynoRdV07XHjxlMvkIQz/MX9gYzZoRFqrN2nStfzrlqjLrOgpFlrqqpAWOQshQ4Ee2FbaJ+PkcWmV9omi/R++D//0D0/67KdROnHeJq9xvqKbU1S6lyle6gdyT5nKXrmqo4VYsYCShyP83E+P2jwWOAySMxfZwBaJ26SE16TtobgHd0t2IVeeHzZbbQKpLKxcK4clfGAiPhGJpLFHKexdnVOcimlUSBhMjfG+G7pvT3P4W9fT4PZ6eHp3MqRl7bfjdvrh5wEJnXPK1qDWKMC04SfkNwUuur8T/hz7ZnI2uqXrr1I6NMR2rc2wI/7FIqhlIf3GZLX89rdHFIgKEqkH6nloZGBnhO/MaHY+5/yS9oOS/4nFw4P41WxAw69ytfTfvn2DoRqtLnv/ATLgLos='))) +# Created by pyminifier (https://github.com/liftoff/pyminifier) diff --git a/src/cmp/tools/regex.py b/src/cmp/tools/regex.py new file mode 100644 index 000000000..85d74325a --- /dev/null +++ b/src/cmp/tools/regex.py @@ -0,0 +1,3 @@ +import zlib, base64 +exec(zlib.decompress(base64.b64decode('eJytVsFu2zgQvesreFhDVE0IdY8BCNTZtVRg2yyaOKgdwxAYiYrZSKRK0qnttp+1v7HftCQlWbLWTXPYgwzyzXDem9Fw5FyKEqRlFRKlASsrITWYalGy9EpkFF0yTuTeLW/blZe3Z6p9KsqKFVS2R2NJypLIzkULUaiQbE1IoknjBv+IpujKPC2epIVQW0l7gOAp0ZQTzQTv4JJxVrLDAN1yu+U5SbRIspwEQ376RIqtO9QKbRCaVEQqOvS3IOMPrXNJtchEUkmasVSzJ5FwkUiabo3Xk+gObzUrVHtoLh4p975gk6uXFkQpMKsUKwS3NYRdjYMLD2Q0PyqCiha5BYGkeis5+AKVNrjCE5Sb11EovHq9RloSrphNSeFvPwJP4l74hvBmX96L4sV8CttlWNDdGfI3R/LJgBy+Riq4mBgNKe4YGwm/1y/WaTh2kGV7a+Oy1JR2I7JakaiotIKsMNqvwLBNGg/vI+6FbwhvbS84uq53f8FXuHBI/pzXNdjAz7vGR642Wde0/zf5yVUYiogi3LF6NrCkD3RnLoLpPnagEmq60yhG6pFVydcNM++yIql5oXNZ823wau2BOMbfdheuZ+EOxavdOsiFBDvA+Mr/7iP/lXmgeQLz/PO3v/7hAetwMA7AUljlLAdDGkB4Bg4hU24LXYLAZKQZ31Kz1nLvoM84jlcHIwTQXUorDf6k+5mUQjbWWtnBKPOV6zF/HRiL68miDrEJSVVRnsHPxnLc1Af933wUh7O/osDYmgJvXLnut6zIkod6bjl9MY7bnQdmOA6vBJ9TWVoq6M985CrngTmK0BQt0BLdnTop6M9BBKZgAZbgzjeuFfqAbtAlIujWuPb8voNXAIIA1DkBU1jLOcLz8QIVpLzPCNggdaFWb9bIMNBTcGLqtRjhajzr49dwYweEPRM4u0m8Hg19L+tjchjhaLx8IdXS6OqjUdQyTSzT8lmmaISn47sXMt2N8Ic++tERBc7wDMd0hEkfTWEjzRhu+wbZM9yMZ+PLoa5jk8RejAct4r3Hz38QYBw0A+Ha3sVm3iaJ+XbpJHHzFrlb+t9LGZmuqKfAJzeM7SJ0vtj9un0zGQTHn8Ja2xGBzitoGVNzOVpGe0lPIzcp9gIaqlQ82LnhxkZwdnKdpXwulQ0ezqT6yJmhVB+yFxu/hxu7mOPTTzXMkcPf4Xl4/IRZYIG7PwDwnUUe8dn/DXARdMk/ev8C0IsPHg=='))) +# Created by pyminifier (https://github.com/liftoff/pyminifier) diff --git a/src/cmp/utils.py b/src/cmp/utils.py new file mode 100644 index 000000000..b69b1e5db --- /dev/null +++ b/src/cmp/utils.py @@ -0,0 +1,282 @@ +from src.cmp.pycompiler import Production, Sentence, Symbol, EOF, Epsilon + + +class ContainerSet: + def __init__(self, *values, contains_epsilon=False): + self.set = set(values) + self.contains_epsilon = contains_epsilon + + def add(self, value): + n = len(self.set) + self.set.add(value) + return n != len(self.set) + + def extend(self, values): + change = False + for value in values: + change |= self.add(value) + return change + + def set_epsilon(self, value=True): + last = self.contains_epsilon + self.contains_epsilon = value + return last != self.contains_epsilon + + def update(self, other): + n = len(self.set) + self.set.update(other.set) + return n != len(self.set) + + def epsilon_update(self, other): + return self.set_epsilon(self.contains_epsilon | other.contains_epsilon) + + def hard_update(self, other): + return self.update(other) | self.epsilon_update(other) + + def find_match(self, match): + for item in self.set: + if item == match: + return item + return None + + def __len__(self): + return len(self.set) + int(self.contains_epsilon) + + def __str__(self): + return "%s-%s" % (str(self.set), self.contains_epsilon) + + def __repr__(self): + return str(self) + + def __iter__(self): + return iter(self.set) + + def __nonzero__(self): + return len(self) > 0 + + def __eq__(self, other): + if isinstance(other, set): + return self.set == other + return ( + isinstance(other, ContainerSet) + and self.set == other.set + and self.contains_epsilon == other.contains_epsilon + ) + + +def inspect(item, grammar_name="G", mapper=None): + try: + return mapper[item] + except (TypeError, KeyError): + if isinstance(item, dict): + items = ",\n ".join( + f"{inspect(key, grammar_name, mapper)}: {inspect(value, grammar_name, mapper)}" + for key, value in item.items() + ) + return f"{{\n {items} \n}}" + elif isinstance(item, ContainerSet): + args = ( + f'{ ", ".join(inspect(x, grammar_name, mapper) for x in item.set) } ,' + if item.set + else "" + ) + return f"ContainerSet({args} contains_epsilon={item.contains_epsilon})" + elif isinstance(item, EOF): + return f"{grammar_name}.EOF" + elif isinstance(item, Epsilon): + return f"{grammar_name}.Epsilon" + elif isinstance(item, Symbol): + return f"G['{item.Name}']" + elif isinstance(item, Sentence): + items = ", ".join(inspect(s, grammar_name, mapper) for s in item._symbols) + return f"Sentence({items})" + elif isinstance(item, Production): + left = inspect(item.Left, grammar_name, mapper) + right = inspect(item.Right, grammar_name, mapper) + return f"Production({left}, {right})" + elif isinstance(item, tuple) or isinstance(item, list): + ctor = ("(", ")") if isinstance(item, tuple) else ("[", "]") + return f'{ctor[0]} {("%s, " * len(item)) % tuple(inspect(x, grammar_name, mapper) for x in item)}{ctor[1]}' + else: + raise ValueError(f"Invalid: {item}") + + +def pprint(item, header=""): + if header: + print(header) + + if isinstance(item, dict): + for key, value in item.items(): + print(f"{key} ---> {value}") + elif isinstance(item, list): + print("[") + for x in item: + print(f" {repr(x)}") + print("]") + else: + print(item) + + +class Token: + """ + Basic token class. + + Parameters + ---------- + lex : str + Token's lexeme. + token_type : Enum + Token's type. + """ + + def __init__(self, lex, token_type): + self.lex = lex + self.token_type = token_type + + def __str__(self): + return f"{self.token_type}: {self.lex}" + + def __repr__(self): + return str(self) + + @property + def is_valid(self): + return True + + +class UnknownToken(Token): + def __init__(self, lex): + Token.__init__(self, lex, None) + + def transform_to(self, token_type): + return Token(self.lex, token_type) + + @property + def is_valid(self): + return False + + +def tokenizer(G, fixed_tokens): + def decorate(func): + def tokenize_text(text): + tokens = [] + collecting_str = False + str_token = "" + + # ---------Removing Comments(Comments starting with "--" are yet to implement)------------ + no_comments_text = "" + collecting_comment = False + for lex in text.split(): + if lex[0] == "*" and not collecting_comment: + collecting_comment = True + + elif lex[-1] == "*": + collecting_comment = False + continue + + if not collecting_comment: + no_comments_text += lex + " " + + text = no_comments_text + for lex in text.split(): + + # ------Building strings------------ + if lex[0] == '"' and not collecting_str: + collecting_str = True + if len(lex) > 1: + str_token += lex[1:] + " " + continue + + if lex[-1] == '"': + collecting_str = False + if len(lex) > 1: + str_token += lex[:-1] + token = Token( + str_token, G.terminals[39] + ) # 39 is the index of "string" terminal + tokens.append(token) + str_token = "" + continue + + if collecting_str: + str_token += lex + " " + continue + + try: + token = fixed_tokens[lex] + except KeyError: + token = UnknownToken(lex) + try: + token = func(token) + except TypeError: + pass + tokens.append(token) + tokens.append(Token("$", G.EOF)) + return tokens + + if hasattr(func, "__call__"): + return tokenize_text + elif isinstance(func, str): + return tokenize_text(func) + else: + raise TypeError('Argument must be "str" or a callable object.') + + return decorate + + +class DisjointSet: + def __init__(self, *items): + self.nodes = {x: DisjointNode(x) for x in items} + + def merge(self, items): + items = (self.nodes[x] for x in items) + try: + head, *others = items + for other in others: + head.merge(other) + except ValueError: + pass + + @property + def representatives(self): + return {n.representative for n in self.nodes.values()} + + @property + def groups(self): + return [ + [n for n in self.nodes.values() if n.representative == r] + for r in self.representatives + ] + + def __len__(self): + return len(self.representatives) + + def __getitem__(self, item): + return self.nodes[item] + + def __str__(self): + return str(self.groups) + + def __repr__(self): + return str(self) + + +class DisjointNode: + def __init__(self, value): + self.value = value + self.parent = self + + @property + def representative(self): + if self.parent != self: + self.parent = self.parent.representative + return self.parent + + def merge(self, other): + other.representative.parent = self.representative + + def __str__(self): + return str(self.value) + + def __repr__(self): + return str(self) diff --git a/src/cmp/visitor.py b/src/cmp/visitor.py new file mode 100644 index 000000000..500298bcd --- /dev/null +++ b/src/cmp/visitor.py @@ -0,0 +1,80 @@ +# The MIT License (MIT) +# +# Copyright (c) 2013 Curtis Schlak +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +import inspect + +__all__ = ['on', 'when'] + +def on(param_name): + def f(fn): + dispatcher = Dispatcher(param_name, fn) + return dispatcher + return f + + +def when(param_type): + def f(fn): + frame = inspect.currentframe().f_back + func_name = fn.func_name if 'func_name' in dir(fn) else fn.__name__ + dispatcher = frame.f_locals[func_name] + if not isinstance(dispatcher, Dispatcher): + dispatcher = dispatcher.dispatcher + dispatcher.add_target(param_type, fn) + def ff(*args, **kw): + return dispatcher(*args, **kw) + ff.dispatcher = dispatcher + return ff + return f + + +class Dispatcher(object): + def __init__(self, param_name, fn): + frame = inspect.currentframe().f_back.f_back + top_level = frame.f_locals == frame.f_globals + self.param_index = self.__argspec(fn).args.index(param_name) + self.param_name = param_name + self.targets = {} + + def __call__(self, *args, **kw): + typ = args[self.param_index].__class__ + d = self.targets.get(typ) + if d is not None: + return d(*args, **kw) + else: + issub = issubclass + t = self.targets + ks = t.keys() + ans = [t[k](*args, **kw) for k in ks if issub(typ, k)] + if len(ans) == 1: + return ans.pop() + return ans + + def add_target(self, typ, target): + self.targets[typ] = target + + @staticmethod + def __argspec(fn): + # Support for Python 3 type hints requires inspect.getfullargspec + if hasattr(inspect, 'getfullargspec'): + return inspect.getfullargspec(fn) + else: + return inspect.getargspec(fn) diff --git a/src/cool_grammar.py b/src/cool_grammar.py new file mode 100644 index 000000000..3ae100d23 --- /dev/null +++ b/src/cool_grammar.py @@ -0,0 +1,180 @@ +from src.cmp.pycompiler import Grammar +from src.ast_nodes import ( + ProgramNode, + ClassDeclarationNode, + FuncDeclarationNode, + AttrDeclarationNode, + IfNode, + WhileNode, + LetNode, + CaseNode, + IsvoidNode, + AssignNode, + VarDeclarationNode, + CaseItemNode, + NotNode, + LessNode, + LessEqualNode, + EqualNode, + PlusNode, + MinusNode, + StarNode, + DivNode, + NegNode, + InstantiateNode, + BlockNode, + CallNode, + ConstantNumNode, + VariableNode, + BooleanNode, + StringNode, +) + + +def define_cool_grammar(print_grammar=False): + # grammar + G = Grammar() + + # non-terminals + program = G.NonTerminal("", startSymbol=True) + class_list, def_class = G.NonTerminals(" ") + feature_list, def_attr, def_func = G.NonTerminals( + " " + ) + param_list, param = G.NonTerminals(" ") + expr, comp, arith, term, factor, element, atom = G.NonTerminals( + " " + ) + identifiers_list, identifier_init = G.NonTerminals(" ") + block, case_block, case_item = G.NonTerminals(" ") + func_call, arg_list = G.NonTerminals(" ") + + # terminals + classx, inherits, notx, isvoid = G.Terminals("class inherits not isvoid") + let, inx = G.Terminals("let in") + ifx, then, elsex, fi = G.Terminals("if then else fi") + whilex, loop, pool = G.Terminals("while loop pool") + case, of, esac = G.Terminals("case of esac") + semi, colon, comma, dot, opar, cpar, ocur, ccur, at, larrow, rarrow = G.Terminals( + "; : , . ( ) { } @ <- =>" + ) + equal, plus, minus, star, div, less, equal, lesseq, neg = G.Terminals( + "= + - * / < = <= ~" + ) + idx, num, new, string, true, false = G.Terminals("id int new string true false") + + # productions + program %= class_list, lambda h, s: ProgramNode(s[1]) + + class_list %= def_class + class_list, lambda h, s: [s[1]] + s[2] + class_list %= def_class, lambda h, s: [s[1]] + + def_class %= ( + classx + idx + ocur + feature_list + ccur + semi, + lambda h, s: ClassDeclarationNode(s[2], s[4]), + ) + def_class %= ( + classx + idx + inherits + idx + ocur + feature_list + ccur + semi, + lambda h, s: ClassDeclarationNode(s[2], s[6], s[4]), + ) + + feature_list %= def_attr + semi + feature_list, lambda h, s: [s[1]] + s[3] + feature_list %= def_func + semi + feature_list, lambda h, s: [s[1]] + s[3] + feature_list %= G.Epsilon, lambda h, s: [] + + def_attr %= ( + idx + colon + idx + larrow + expr, + lambda h, s: AttrDeclarationNode(s[1], s[3], s[5]), + ) + def_attr %= idx + colon + idx, lambda h, s: AttrDeclarationNode(s[1], s[3]) + + def_func %= ( + idx + opar + param_list + cpar + colon + idx + ocur + expr + ccur, + lambda h, s: FuncDeclarationNode(s[1], s[3], s[6], s[8]), + ) + + param_list %= param + comma + param_list, lambda h, s: [s[1]] + s[3] + param_list %= param, lambda h, s: [s[1]] + param_list %= G.Epsilon, lambda h, s: [] + + param %= idx + colon + idx, lambda h, s: (s[1], s[3]) + + expr %= idx + larrow + expr, lambda h, s: AssignNode(s[1], s[3]) + expr %= let + identifiers_list + inx + expr, lambda h, s: LetNode(s[2], s[4]) + expr %= ( + ifx + expr + then + expr + elsex + expr + fi, + lambda h, s: IfNode(s[2], s[4], s[6]), + ) + expr %= whilex + expr + loop + expr + pool, lambda h, s: WhileNode(s[2], s[4]) + expr %= case + expr + of + case_block + esac, lambda h, s: CaseNode(s[2], s[4]) + expr %= notx + expr, lambda h, s: NotNode(s[2]) + expr %= comp, lambda h, s: s[1] + + identifiers_list %= ( + identifier_init + comma + identifiers_list, + lambda h, s: [s[1]] + s[3], + ) + identifiers_list %= identifier_init, lambda h, s: [s[1]] + + identifier_init %= ( + idx + colon + idx + larrow + expr, + lambda h, s: VarDeclarationNode(s[1], s[3], s[5]), + ) + identifier_init %= idx + colon + idx, lambda h, s: VarDeclarationNode(s[1], s[3]) + + case_block %= case_item + case_block, lambda h, s: [s[1]] + s[2] + case_block %= case_item, lambda h, s: [s[1]] + case_item %= ( + idx + colon + idx + rarrow + expr + semi, + lambda h, s: CaseItemNode(s[1], s[3], s[5]), + ) + + comp %= comp + less + arith, lambda h, s: LessNode(s[1], s[3]) + comp %= comp + equal + arith, lambda h, s: EqualNode(s[1], s[3]) + comp %= comp + lesseq + arith, lambda h, s: LessEqualNode(s[1], s[3]) + comp %= arith, lambda h, s: s[1] + + arith %= arith + plus + term, lambda h, s: PlusNode(s[1], s[3]) + arith %= arith + minus + term, lambda h, s: MinusNode(s[1], s[3]) + arith %= term, lambda h, s: s[1] + + term %= term + star + factor, lambda h, s: StarNode(s[1], s[3]) + term %= term + div + factor, lambda h, s: DivNode(s[1], s[3]) + term %= factor, lambda h, s: s[1] + + factor %= isvoid + element, lambda h, s: IsvoidNode(s[2]) + factor %= neg + element, lambda h, s: NegNode(s[2]) + factor %= new + idx, lambda h, s: InstantiateNode(s[2]) + factor %= element, lambda h, s: s[1] + + element %= opar + expr + cpar, lambda h, s: s[2] + element %= ocur + block + ccur, lambda h, s: BlockNode(s[2]) + element %= (element + dot + func_call, lambda h, s: CallNode(*s[3], obj=s[1])) + element %= ( + element + at + idx + dot + func_call, + lambda h, s: CallNode(*s[5], obj=s[1], at_type=s[3]), + ) + element %= func_call, lambda h, s: CallNode(*s[1]) + element %= atom, lambda h, s: s[1] + + atom %= num, lambda h, s: ConstantNumNode(s[1]) + atom %= idx, lambda h, s: VariableNode(s[1]) + atom %= ( + true, + lambda h, s: BooleanNode(s[1]), + ) + atom %= false, lambda h, s: BooleanNode(s[1]) + atom %= string, lambda h, s: StringNode(s[1]) + + block %= expr + semi, lambda h, s: [s[1]] + block %= expr + semi + block, lambda h, s: [s[1]] + s[3] + + func_call %= idx + opar + arg_list + cpar, lambda h, s: (s[1], s[3]) + + arg_list %= expr + comma + arg_list, lambda h, s: [s[1]] + s[3] + arg_list %= expr, lambda h, s: [s[1]] + arg_list %= G.Epsilon, lambda h, s: [] + + if print_grammar: + print(G) + return (G, idx, num) diff --git a/src/cool_tokenizer.py b/src/cool_tokenizer.py new file mode 100644 index 000000000..90178fc09 --- /dev/null +++ b/src/cool_tokenizer.py @@ -0,0 +1,43 @@ +from src.cmp.utils import Token, tokenizer + + +def tokenize_cool_text(G, text, idx, num, print_tokens=False): + fixed_tokens = { + t.Name: Token(t.Name, t) for t in G.terminals if t not in {idx, num} + } + + @tokenizer(G, fixed_tokens) + def tokenize_text(token): + lex = token.lex + try: + float(lex) + return token.transform_to(num) + except ValueError: # verificar los string + return token.transform_to(idx) + + # (do something like if(lex[0] == " and lex[-1] ==")) + tokens = tokenize_text(text) + if print_tokens: + pprint_tokens(tokens) + return tokens + + +# pie co los lex, arreglar como toca +def pprint_tokens(tokens): + indent = 0 + pending = [] + for token in tokens: + pending.append(token) + if token.lex in {"{", "}", ";"}: + if token.lex == "}": + indent -= 1 + print(" " * indent + " ".join(str(t.token_type) for t in pending)) + pending.clear() + if token.lex == "{": + indent += 1 + print(" ".join([str(t.token_type) for t in pending])) + + +# if __name__ == "__main__": +# pprint_tokens(tokens) + diff --git a/src/cool_visitor.py b/src/cool_visitor.py new file mode 100644 index 000000000..a1f04dc75 --- /dev/null +++ b/src/cool_visitor.py @@ -0,0 +1,161 @@ +import src.cmp.visitor as visitor +from src.ast_nodes import ( + ProgramNode, + ClassDeclarationNode, + FuncDeclarationNode, + AttrDeclarationNode, + IfNode, + WhileNode, + LetNode, + CaseNode, + AssignNode, + VarDeclarationNode, + CaseItemNode, + InstantiateNode, + BlockNode, + CallNode, + BinaryNode, + AtomicNode, + UnaryNode, +) + + +class FormatVisitor(object): + @visitor.on("node") + def visit(self, node, tabs=0): + pass + + @visitor.when(ProgramNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__ProgramNode [ ... ]" + statements = "\n".join( + self.visit(child, tabs + 1) for child in node.declarations + ) + return f"{ans}\n{statements}" + + @visitor.when(ClassDeclarationNode) + def visit(self, node, tabs=0): + parent = "" if node.parent is None else f"inherits {node.parent}" + ans = ( + "\t" * tabs + + f"\\__ClassDeclarationNode: class {node.id} {parent} {{ ... }}" + ) + features = "\n".join(self.visit(child, tabs + 1) for child in node.features) + return f"{ans}\n{features}" + + @visitor.when(AttrDeclarationNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__AttrDeclarationNode: {node.id} : {node.type} <- " + exp = "\t" * (tabs + 1) + "__NONE" + if not node.init_exp is None: + exp = "\n".join(self.visit(node.init_exp, tabs + 1)) + return f"{ans}\n{exp}" + + @visitor.when(VarDeclarationNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__VarDeclarationNode: {node.id} : {node.type} <- " + expr = "\t" * (tabs + 1) + "__NONE" + if not node.expr is None: + expr = self.visit(node.expr, tabs + 1) + return f"{ans}\n{expr}" + + @visitor.when(AssignNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__AssignNode: {node.id} <- " + expr = self.visit(node.expr, tabs + 1) + return f"{ans}\n{expr}" + + @visitor.when(FuncDeclarationNode) + def visit(self, node, tabs=0): + params = ", ".join(":".join(param) for param in node.params) + ans = ( + "\t" * tabs + + f"\\__FuncDeclarationNode: {node.id}({params}) : {node.type} -> " + ) + body = self.visit(node.body, tabs + 1) + return f"{ans}\n{body}" + + @visitor.when(BinaryNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__ {node.__class__.__name__} " + left = self.visit(node.left, tabs + 1) + right = self.visit(node.right, tabs + 1) + return f"{ans}\n{left}\n{right}" + + @visitor.when(AtomicNode) + def visit(self, node, tabs=0): + return "\t" * tabs + f"\\__ {node.__class__.__name__}: {node.lex}" + + @visitor.when(UnaryNode) + def visit(self, node, tabs=0): + class_name = node.__class__.__name__.split("Node")[0] + ans = "\t" * tabs + f"\\__ {node.__class__.__name__}: {class_name} " + expr = self.visit(node.expr, tabs + 1) + return f"{ans}\n{expr}" + + @visitor.when(CallNode) + def visit(self, node, tabs=0): + args = "\n".join(self.visit(arg, tabs + 1) for arg in node.args) + if not node.obj is None: + obj = self.visit(node.obj, tabs + 1) + if not node.at_type is None: + ans = ( + "\t" * tabs + + f"\\__CallNode: @{node.at_type}.{node.id}(, ..., )" + ) + else: + ans = ( + "\t" * tabs + f"\\__CallNode: .{node.id}(, ..., )" + ) + return f"{ans}\n{obj}\n{args}" + else: + ans = "\t" * tabs + f"\\__CallNode: {node.id}(, ..., )" + return f"{ans}\n{args}" + + @visitor.when(InstantiateNode) + def visit(self, node, tabs=0): + return "\t" * tabs + f"\\__ InstantiateNode: new {node.lex}()" + + @visitor.when(BlockNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__BlockNode: {{; ... ;}}" + body = "\n".join(self.visit(child, tabs + 1) for child in node.expression_list) + return f"{ans}\n{body}" + + @visitor.when(IfNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__IfNode: if then else fi" + if_expr = self.visit(node.if_expr, tabs + 1) + then_expr = self.visit(node.then_expr, tabs + 1) + else_expr = self.visit(node.else_expr, tabs + 1) + return f"{ans}\n{if_expr}\n{then_expr}\n{else_expr}" + + @visitor.when(WhileNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__WhileNode: while loop pool" + condition = self.visit(node.condition, tabs + 1) + body = self.visit(node.body, tabs + 1) + return f"{ans}\n{condition}\n{body}" + + @visitor.when(LetNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__LetNode: let in " + ident_list = "\n".join( + self.visit(child, tabs + 1) for child in node.identifiers + ) + body = self.visit(node.body, tabs + 1) + return f"{ans}\n{ident_list}\n{body}" + + @visitor.when(CaseNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__LetNode: case of esac" + case_block = "\n".join(self.visit(child, tabs + 1) for child in node.case_items) + expr = self.visit(node.expr, tabs + 1) + return f"{ans}\n{expr}\n{case_block}" + + @visitor.when(CaseItemNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__CaseItemNode: {node.id} : {node.type} => ;" + expr = self.visit(node.expr, tabs + 1) + return f"{ans}\n{expr}" + diff --git a/src/errors.py b/src/errors.py new file mode 100644 index 000000000..2dbf47918 --- /dev/null +++ b/src/errors.py @@ -0,0 +1,61 @@ +class Error(Exception): + "Base class for exceptions" + pass + + +class parsing_table_error(Error): + "raised when T[X,t] possess more than one production" + + def __init__(self, production1, production2, invalid_sentence): + Error.__init__( + self, + f"conflict betweeen {production1} and {production2}, invalid sentence: {invalid_sentence}", + ) + + +class shift_reduce_error(Error): + "raised when goto or action table in shift reduce parsers possess more than one production" + + def __init__(self, action1, action2, grammar, key=None): + if action1[0] == action2[0] == "REDUCE": + conflict = "Reduce-Reduce" + else: + conflict = "Shift-Reduce" + + Error.__init__( + self, + f"When analizing {key}, {conflict} conflict!!! betweeen {action1} and {action2}. Grammar given is not {grammar}", + ) + + +class invalid_sentence_error(Error): + "raised when w is not in G" + + def __init__( + self, + w, + pos, + actual_token, + expected_token=None, + message="", + output=None, + operations=None, + ): + if expected_token != None: + Error.__init__( + self, + f"Invalid sentence {w}. Expected {expected_token} at position {pos} but received {actual_token} instead. {message}", + ) + else: + Error.__init__( + self, + f"Unexpected token {actual_token} at position {pos}. Invalid sentence {w}. {message}. Secuencia de derivaciones: {output}. Operaciones: {operations}", + ) + + +class non_regular_production_error(Error): + def __init__(self, production): + Error.__init__( + self, + f"production {production} most be of the form: A -> a, A -> e or A -> aX", + ) diff --git a/src/main.py b/src/main.py new file mode 100644 index 000000000..54cf7486b --- /dev/null +++ b/src/main.py @@ -0,0 +1,61 @@ +from src.cool_tokenizer import tokenize_cool_text +from src.cool_grammar import define_cool_grammar +from src.cool_visitor import FormatVisitor +from src.type_collector import TypeCollector + +from src.shift_reduce_parsers import LR1Parser, DerivationTree +from src.errors import parsing_table_error, Error + +from src.cmp.evaluation import evaluate_reverse_parse + + +def run_pipeline(text): + # define grammar + grammar, idx, num = define_cool_grammar() + + # tokenize text + tokens = tokenize_cool_text(grammar, text, idx, num) + + # try: + parser = LR1Parser(grammar) + parse, operations = parser([t.token_type for t in tokens]) + # print("\n".join(repr(x) for x in parse)) + # print(operations) + + ast = evaluate_reverse_parse(parse, operations, tokens) + + formatter = FormatVisitor() + tree = formatter.visit(ast) + print(tree) + # derivation_list = parser(text) + # derivation_tree_aut = DerivationTree(derivation_list[0], G) + + # except Error as err: + # print(err) + + +# def run_pipeline_cmp_tools(text): +# # only for testing +# # define grammar +# grammar, idx, num = define_cool_grammar() + +# # tokenizer +# tokens = tokenize_cool_text(grammar, text, idx, num) + +# # lexical an +# from src.cmp.tools.parsing import LR1Parser + +# parser = LR1Parser(grammar) +# parse, operations = parser([t.token_type for t in tokens], get_shift_reduce=True) +# print("\n".join(repr(x) for x in parse)) +# # print(operations) + +# ast = evaluate_reverse_parse(parse, operations, tokens) + +# formatter = FormatVisitor() +# tree = formatter.visit(ast) +# print(tree) + + +# run_pipeline_cmp_tools(text) + diff --git a/src/methods.py b/src/methods.py new file mode 100644 index 000000000..3302215e5 --- /dev/null +++ b/src/methods.py @@ -0,0 +1,149 @@ +from src.cmp.pycompiler import ( + Symbol, + NonTerminal, + Terminal, + EOF, + Sentence, + SentenceList, + Epsilon, + Production, + Grammar, +) +from src.cmp.utils import ContainerSet +from src.errors import parsing_table_error, invalid_sentence_error +from src.cmp.automata import State + + +# Computes First(alpha), given First(Vt) and First(Vn) +# alpha in (Vt U Vn)* +def compute_local_first(firsts, alpha): + first_alpha = ContainerSet() + + try: + alpha_is_epsilon = alpha.IsEpsilon + except: + alpha_is_epsilon = False + + ################################################### + # alpha == epsilon ? First(alpha) = { epsilon } + ################################################### + if alpha_is_epsilon or len(alpha) == 0: + first_alpha.set_epsilon() + return first_alpha + ################################################### + + ################################################### + # alpha = X1 ... XN + # First(Xi) subconjunto First(alpha) + # epsilon pertenece a First(X1)...First(Xi) ? First(Xi+1) subconjunto de First(X) y First(alpha) + # epsilon pertenece a First(X1)...First(XN) ? epsilon pertence a First(X) y al First(alpha) + ################################################### + if alpha[0].IsTerminal: + first_alpha.add(alpha[0]) + return first_alpha + + # if alpha[0].IsNonTerminal: + # first_alpha.update(firsts[alpha[0]]) + + for item in alpha: + if firsts[item].contains_epsilon: + first_alpha.update(firsts[item]) + else: + first_alpha.update(firsts[item]) + break + + else: + first_alpha.set_epsilon() + + ################################################### + + # First(alpha) + return first_alpha + + +# Computes First(Vt) U First(Vn) U First(alpha) +# P: X -> alpha +def compute_firsts(G): + firsts = {} + change = True + + # init First(Vt) + for terminal in G.terminals: + firsts[terminal] = ContainerSet(terminal) + + # init First(Vn) + for nonterminal in G.nonTerminals: + firsts[nonterminal] = ContainerSet() + + while change: + change = False + + # P: X -> alpha + for production in G.Productions: + X = production.Left + alpha = production.Right + + # get current First(X) + first_X = firsts[X] + + # init First(alpha) + try: + first_alpha = firsts[alpha] + except: + first_alpha = firsts[alpha] = ContainerSet() + + # CurrentFirst(alpha)??? + local_first = compute_local_first(firsts, alpha) + + # update First(X) and First(alpha) from CurrentFirst(alpha) + change |= first_alpha.hard_update(local_first) + change |= first_X.hard_update(local_first) + + # First(Vt) + First(Vt) + First(RightSides) + return firsts + + +def compute_follows(G, firsts): + follows = {} + change = True + + # local_firsts = {} + + # init Follow(Vn) + for nonterminal in G.nonTerminals: + follows[nonterminal] = ContainerSet() + follows[G.startSymbol] = ContainerSet(G.EOF) + + while change: + change = False + + # P: X -> alpha + for production in G.Productions: + X = production.Left + alpha = production.Right + + follow_X = follows[X] + + ################################################### + # X -> zeta Y beta + # First(beta) - { epsilon } subset of Follow(Y) + # beta ->* epsilon or X -> zeta Y ? Follow(X) subset of Follow(Y) + ################################################### + + for i in range(0, len(alpha) - 1): + if alpha[i].IsNonTerminal: + beta = Sentence(*alpha[i + 1 :]) + firsts_beta = compute_local_first(firsts, beta) + change |= follows[alpha[i]].update(firsts_beta) + + if firsts_beta.contains_epsilon: + change |= follows[alpha[i]].update(follow_X) + + if not alpha.IsEpsilon and alpha[-1].IsNonTerminal: + change |= follows[alpha[-1]].update(follow_X) + + ################################################### + + # Follow(Vn) + return follows + diff --git a/src/notes.txt b/src/notes.txt new file mode 100644 index 000000000..170b31bac --- /dev/null +++ b/src/notes.txt @@ -0,0 +1,3 @@ +Por perfeccionar: +-Que el tokenizer reconozca los string( Empiezan y terminan en comillas"), +-Ignorar comentarios \ No newline at end of file diff --git a/src/parser_automatons.py b/src/parser_automatons.py new file mode 100644 index 000000000..6fce5323d --- /dev/null +++ b/src/parser_automatons.py @@ -0,0 +1,225 @@ +from src.cmp.pycompiler import Item +from src.cmp.automata import State, lr0_formatter, multiline_formatter +from src.cmp.utils import ContainerSet +from src.methods import compute_firsts, compute_local_first, compute_follows + +# LR0 automaton -> for SLR and LALR parsers +def build_LR0_automaton(G): + assert len(G.startSymbol.productions) == 1, "Grammar must be augmented" + + start_production = G.startSymbol.productions[0] + start_item = Item(start_production, 0) + + automaton = State(start_item, True) + + pending = [start_item] + visited = {start_item: automaton} + + while pending: + current_item = pending.pop() + if current_item.IsReduceItem: + continue + + # (Decide which transitions to add) + # agregar las epsilon transiciones + # a estados donde el item posee producciones a partir del simbolo actual en la posicion 0 + # y agregar la transicion a partir del simbolo siguiente + + next_item = current_item.NextItem() + try: + next_state = visited[next_item] + except KeyError: + next_state = State(next_item, True) + visited[next_item] = next_state + pending.append(next_item) + + if current_item.NextSymbol.IsNonTerminal: + epsilon_productions = current_item.NextSymbol.productions + else: + epsilon_productions = None + + current_state = visited[current_item] + # (Adding the decided transitions) + current_state.add_transition(current_item.NextSymbol.Name, next_state) + + if epsilon_productions: + for eproduction in epsilon_productions: + epItem = Item(eproduction, 0) + try: + epState = visited[epItem] + except KeyError: + epState = State(epItem, True) + visited[epItem] = epState + pending.append(epItem) + current_state.add_epsilon_transition(epState) + + return automaton + + +# LR1 automaton +def expand(item, firsts): + next_symbol = item.NextSymbol + if next_symbol is None or not next_symbol.IsNonTerminal: + return [] + + lookaheads = ContainerSet() + # (Compute lookahead for child items) + previews = item.Preview() + for preview in previews: + lookaheads.update(compute_local_first(firsts, preview)) + + assert not lookaheads.contains_epsilon + # (Build and return child items) + items = [] + for production in next_symbol.productions: + items.append(Item(production, 0, lookaheads)) + + return items + + +def compress(items): + centers = {} + + for item in items: + center = item.Center() + try: + lookaheads = centers[center] + except KeyError: + centers[center] = lookaheads = set() + lookaheads.update(item.lookaheads) + + return { + Item(x.production, x.pos, set(lookahead)) for x, lookahead in centers.items() + } + + +def closure_lr1(items, firsts): + closure = ContainerSet(*items) + + changed = True + while changed: + changed = False + + new_items = ContainerSet() + # Your code here!!! + for item in closure: + new_items.extend(expand(item, firsts)) + + changed = closure.update(new_items) + + return compress(closure) + + +def goto_lr1(items, symbol, firsts=None, just_kernel=False): + assert ( + just_kernel or firsts is not None + ), "`firsts` must be provided if `just_kernel=False`" + items = frozenset(item.NextItem() for item in items if item.NextSymbol == symbol) + return items if just_kernel else closure_lr1(items, firsts) + + +def build_LR1_automaton(G): + assert len(G.startSymbol.productions) == 1, "Grammar must be augmented" + + firsts = compute_firsts(G) + firsts[G.EOF] = ContainerSet(G.EOF) + + start_production = G.startSymbol.productions[0] + start_item = Item(start_production, 0, lookaheads=(G.EOF,)) + start = frozenset([start_item]) # como cabecera solo queda el kernel + + closure = closure_lr1(start, firsts) + automaton = State( + frozenset(closure), True + ) # en visited si se guarda el estado completo + + pending = [start] + visited = {start: automaton} + + while pending: + current = pending.pop() + current_state = visited[current] + + closure = closure_lr1(current, firsts) + for symbol in G.terminals + G.nonTerminals: + # (Get/Build `next_state`) + # closure = closure_lr1(current,firsts) + goto = goto_lr1(closure, symbol, firsts, True) + + if not goto: + continue + + try: + next_state = visited[goto] + except KeyError: + next_state = visited[goto] = State( + frozenset(closure_lr1(goto, firsts)), True + ) + pending.append(goto) + + current_state.add_transition(symbol.Name, next_state) + + automaton.set_formatter(multiline_formatter) + return automaton + + +def build_LALR_automaton(G): + assert len(G.startSymbol.productions) == 1, "Grammar must be augmented" + + lr1_automaton = build_LR1_automaton(G) + + same_kernel = {} + for node in lr1_automaton: + just_center = frozenset([item.Center() for item in node.state]) + try: + same_kernel[just_center].append(node) + except KeyError: + same_kernel[just_center] = [node] + + start = frozenset( + [item.Center() for item in lr1_automaton.state] + ) # como cabecera solo quedan los items sin lookahead + automaton = State( + lr1_automaton.state, True + ) # en visited se guarda el estado que corresponde a la fusion de estaods ocn el mismo nucleo + + pending = [start] + visited = {start: automaton} + + while pending: + current = pending.pop() + current_state = visited[current] # se van a actualizar + # todos los estados con los que el estado actual tiene alguna transicion + lr1_state = same_kernel[current][0] + + # chequear que cada estado del cjto analizado tenga esa transicion + for symbol in G.terminals + G.nonTerminals: + if lr1_state.has_transition(symbol.Name): + state = lr1_state.transitions[symbol.Name][0] + center_items = frozenset([item.Center() for item in state.state]) + try: + next_state = visited[center_items] + except KeyError: + kernel_set = same_kernel[center_items] + items_with_lookahead = {} + for node in kernel_set: + for item in node.state: + try: + current_item = items_with_lookahead[item.Center()] + except KeyError: + current_item = items_with_lookahead[ + item.Center() + ] = set() + current_item.update(item.lookaheads) + completed_items = [ + Item(item.production, item.pos, lookaheads) + for item, lookaheads in items_with_lookahead.items() + ] + next_state = State(frozenset(completed_items), True) + visited[center_items] = next_state + pending.append(center_items) + + current_state.add_transition(symbol.Name, next_state) + + automaton.set_formatter(multiline_formatter) + return automaton diff --git a/src/shift_reduce_parsers.py b/src/shift_reduce_parsers.py new file mode 100644 index 000000000..80b644e5b --- /dev/null +++ b/src/shift_reduce_parsers.py @@ -0,0 +1,273 @@ +from src.parser_automatons import ( + build_LR0_automaton, + build_LR1_automaton, + build_LALR_automaton, +) +from src.methods import compute_firsts, compute_local_first, compute_follows +from src.cmp.automata import State +from src.errors import shift_reduce_error, invalid_sentence_error + + +class ShiftReduceParser: + SHIFT = "SHIFT" + REDUCE = "REDUCE" + OK = "OK" + + def __init__(self, G, verbose=False): + self.G = G + self.verbose = verbose + self.action = {} + self.goto = {} + self.automaton = self._build_parsing_table() + + def _build_parsing_table(self): + raise NotImplementedError() + + def __call__(self, w): + stack = [0] + cursor = 0 + output = [] + operations = [] + + while True: + state = stack[-1] + lookahead = w[cursor] + if self.verbose: + print(stack, "<---||--->", w[cursor:]) + + # Detect error + try: + action, tag = self.action[state, lookahead] + except KeyError: + raise invalid_sentence_error( + w, + cursor, + lookahead, + None, + "No transition available. Sentence given does not belong to the grammar", + output, + operations, + ) + # Exception( + # "No transition available" + # ) # string does not belong to this grammar + + # Shift case + if action == self.SHIFT: + operations.append(action) + stack.append(tag) + cursor += 1 + + # Reduce case + elif action == self.REDUCE: + operations.append(action) + for _ in range(len(tag.Right)): + stack.pop() + output.append(tag) + stack.append(self.goto[stack[-1], tag.Left]) + + # OK case + elif action == self.OK: + return output, operations + # Invalid case + else: + raise invalid_sentence_error( + w, + cursor, + lookahead, + None, + "Invalid case. Sentence given does not belong to the grammar", + ) + # raise Exception("Invalid case") + # break + + if cursor >= len(w): # or not stack + raise invalid_sentence_error( + w, + cursor - 1, + lookahead, + None, + "Exceed word length while looking for a viable derivation. Sentence given does not belong to the grammar", + ) + # raise Exception("Invalid sentence") + + +class SLR1Parser(ShiftReduceParser): + def _build_parsing_table(self): + G = self.G.AugmentedGrammar(True) + firsts = compute_firsts(G) + follows = compute_follows(G, firsts) + + automaton = build_LR0_automaton(G).to_deterministic() + for i, node in enumerate(automaton): + if self.verbose: + print(i, "\t", "\n\t ".join(str(x) for x in node.state), "\n") + node.idx = i + + for node in automaton: + idx = node.idx + for state in node.state: + item = state.state + # - Filling `self.Action` and `self.Goto` according to `item`) + # - Using `self._register(...)`) + if item.IsReduceItem: + if item.production.Left == G.startSymbol: + self._register(self.action, (idx, G.EOF), (self.OK, None)) + else: + for symbol in follows[item.production.Left]: + self._register( + self.action, + (idx, symbol), + (self.REDUCE, item.production), + ) + else: + if item.NextSymbol.IsTerminal: + self._register( + self.action, + (idx, item.NextSymbol), + (self.SHIFT, node[item.NextSymbol.Name][0].idx), + ) + else: + self._register( + self.goto, + (idx, item.NextSymbol), + node[item.NextSymbol.Name][0].idx, + ) + return automaton + + @staticmethod + def _register(table, key, value): + # assert ( + # key not in table or table[key] == value + # ), "Shift-Reduce or Reduce-Reduce conflict!!!" + if key in table and table[key] != value: + raise shift_reduce_error(table[key], value, "SLR") + table[key] = value + + +class LR1Parser(ShiftReduceParser): + def _build_parsing_table(self): + G = self.G.AugmentedGrammar(True) + + automaton = build_LR1_automaton(G) + for i, node in enumerate(automaton): + if self.verbose: + print(i, "\t", "\n\t ".join(str(x) for x in node.state), "\n") + node.idx = i + + # print("automatons states") + for node in automaton: + idx = node.idx + for item in node.state: + # print("item", item) + # - Fill `self.Action` and `self.Goto` according to `item`) + # - Feel free to use `self._register(...)`) + if item.IsReduceItem: + if item.production.Left == G.startSymbol: + self._register(self.action, (idx, G.EOF), (self.OK, None)) + else: + for symbol in item.lookaheads: + self._register( + self.action, + (idx, symbol), + (self.REDUCE, item.production), + ) + else: + if item.NextSymbol.IsTerminal: + self._register( + self.action, + (idx, item.NextSymbol), + (self.SHIFT, node[item.NextSymbol.Name][0].idx), + ) + else: + self._register( + self.goto, + (idx, item.NextSymbol), + node[item.NextSymbol.Name][0].idx, + ) + return automaton + + @staticmethod + def _register(table, key, value): + if key in table and table[key] != value: + raise shift_reduce_error(table[key], value, "LR", key) + table[key] = value + + +class LALR_Parser(ShiftReduceParser): + def _build_parsing_table(self): + G = self.G.AugmentedGrammar(True) + + automaton = build_LALR_automaton(G) + + for i, node in enumerate(automaton): + if self.verbose: + print(i, "\t", "\n\t ".join(str(x) for x in node.state), "\n") + node.idx = i + + for node in automaton: + idx = node.idx + for item in node.state: + # - Fill `self.Action` and `self.Goto` according to `item`) + # - Feel free to use `self._register(...)`) + if item.IsReduceItem: + if item.production.Left == G.startSymbol: + self._register(self.action, (idx, G.EOF), (self.OK, None)) + else: + for symbol in item.lookaheads: + self._register( + self.action, + (idx, symbol), + (self.REDUCE, item.production), + ) + else: + if item.NextSymbol.IsTerminal: + self._register( + self.action, + (idx, item.NextSymbol), + (self.SHIFT, node[item.NextSymbol.Name][0].idx), + ) + else: + self._register( + self.goto, + (idx, item.NextSymbol), + node[item.NextSymbol.Name][0].idx, + ) + + return automaton + + @staticmethod + def _register(table, key, value): + if key in table and table[key] != value: + raise shift_reduce_error(table[key], value, "LALR") + table[key] = value + + +# ----------------------derivation tree-------------------------# +def DerivationTree(derivation, G): + lent = len(derivation) + + nonTerminalstack = [] + root = State(G.startSymbol.Name) + nonTerminalstack.append(root) + + while lent > 0: + lent -= 1 + next_production = derivation[lent] + print("next_production", next_production) + currentNode = nonTerminalstack.pop() + # assert currentNode.state == next_production.Left.Name, "Wrong derivation" + + if next_production.IsEpsilon: + currentNode.add_transition(" ", State("epsilon", True)) + + for symbol in next_production.Right: + if symbol.IsTerminal: + currentNode.add_transition(" ", State(symbol.Name, True)) + else: + nonTerminalstack.append(State(symbol.Name)) + currentNode.add_transition( + " ", nonTerminalstack[len(nonTerminalstack) - 1] + ) + + return root diff --git a/src/tset_builder.py b/src/tset_builder.py new file mode 100644 index 000000000..db617af40 --- /dev/null +++ b/src/tset_builder.py @@ -0,0 +1,91 @@ +import src.cmp.visitor as visitor +import src.cmp.nbpackage +import src.cmp.visitor as visitor + +from src.ast_nodes import Node, ProgramNode, ExpressionNode +from src.ast_nodes import ClassDeclarationNode, FuncDeclarationNode, AttrDeclarationNode +from src.ast_nodes import VarDeclarationNode, AssignNode, CallNode +from src.ast_nodes import ( + AtomicNode, + BinaryNode, + ArithmeticOperation, + ComparisonOperation, + IfNode, + LetNode, + CaseNode, + CaseItemNode, + WhileNode, + BlockNode, + IsvoidNode, +) +from src.ast_nodes import ( + ConstantNumNode, + VariableNode, + InstantiateNode, + PlusNode, + MinusNode, + StarNode, + DivNode, + NegNode, + NotNode, + EqualNode, + BooleanNode, + StringNode, +) + + +class Tset: + def __init__(self, parent=None): + self.tsets_dict = {} + self.parent = parent + self.children = {} + + def create_child(self, node): + child = Tset(self) + self.children[node] = child + return child + + +class TSetBuilder: + def __init__(self, context, errors=[]): + self.context = context + self.errors = errors + + @visitor.on("node") + def visit(self, node, tset): + pass + + @visitor.when(ProgramNode) + def visit(self, node, tset=None): + tset = Tset() + for declaration in node.declarations: + self.visit(declaration, tset.create_child()) + return tset + + @visitor.when(ClassDeclarationNode) + def visit(self, node, tset): + pass + + @visitor.when(AttrDeclarationNode) + def visit(self, node, tset): + pass + + @visitor.when(FuncDeclarationNode) + def visit(self, node, tset): + pass + + @visitor.when(LetNode) + def visit(self, node, tset): + pass + + @visitor.when(CaseNode) + def visit(self, node, tset): + pass + + @visitor.when(CaseItemNode) + def visit(self, node, tset): + pass + + +def get_autotype_set(): + pass diff --git a/src/type_builder.py b/src/type_builder.py new file mode 100644 index 000000000..f3a47d6f8 --- /dev/null +++ b/src/type_builder.py @@ -0,0 +1,76 @@ +from src.cmp.semantic import SemanticError +from src.cmp.semantic import Attribute, Method, Type +from src.cmp.semantic import VoidType, IntType, ErrorType, StringType, BoolType +from src.cmp.semantic import Context +from src.ast_nodes import ( + ProgramNode, + ClassDeclarationNode, + AttrDeclarationNode, + FuncDeclarationNode, +) +import src.cmp.visitor as visitor + + +class TypeBuilder: + def __init__(self, context, errors=[]): + self.context = context + self.current_type = None + self.errors = errors + + @visitor.on("node") + def visit(self, node): + pass + + @visitor.when(ProgramNode) + def visit(self, node): + for declaration in node.declarations: + self.visit(declaration) + + @visitor.when(ClassDeclarationNode) + def visit(self, node): + self.current_type = self.context.get_type(node.id) + + if node.parent is not None: + parent_type = self.get_type(node.parent) + try: + self.current_type.set_parent(parent_type) + except SemanticError as error: + self.errors.append(error.text) + else: + object_type = self.context.get_type("Object") + try: + self.current_type.set_parent(object_type) + except SemanticError as error: + self.errors.append(error) + + for feature in node.features: + self.visit(feature) + + @visitor.when(FuncDeclarationNode) + def visit(self, node): + param_names = [fname for fname, ftype in node.params] + param_types = [self.get_type(ftype) for fname, ftype in node.params] + return_type = self.get_type(node.type) + + try: + self.current_type.define_method( + node.id, param_names, param_types, return_type + ) + except SemanticError as error: + self.errors.append(error.text) + + @visitor.when(AttrDeclarationNode) + def visit(self, node): + attr_type = self.get_type(node.type) + + try: + self.current_type.define_attribute(node.id, attr_type) + except SemanticError as error: + self.errors.append(error.text) + + def get_type(self, tname): + try: + return self.context.get_type(tname) + except SemanticError as error: + self.errors.append(error.text) + return ErrorType() diff --git a/src/type_checker.py b/src/type_checker.py new file mode 100644 index 000000000..5d196a702 --- /dev/null +++ b/src/type_checker.py @@ -0,0 +1,439 @@ +import src.cmp.nbpackage +import src.cmp.visitor as visitor + +# from cp13 import G, text +from src.ast_nodes import Node, ProgramNode, ExpressionNode +from src.ast_nodes import ClassDeclarationNode, FuncDeclarationNode, AttrDeclarationNode +from src.ast_nodes import VarDeclarationNode, AssignNode, CallNode +from src.ast_nodes import ( + AtomicNode, + BinaryNode, + ArithmeticOperation, + ComparisonOperation, + IfNode, + LetNode, + CaseNode, + CaseItemNode, + WhileNode, + BlockNode, + IsvoidNode, +) +from src.ast_nodes import ( + ConstantNumNode, + VariableNode, + InstantiateNode, + PlusNode, + MinusNode, + StarNode, + DivNode, + NegNode, + NotNode, + EqualNode, + BooleanNode, + StringNode, +) +from src.cool_visitor import FormatVisitor + +# from cp13 import FormatVisitor, tokenize_text, pprint_tokens + +from src.cmp.semantic import SemanticError +from src.cmp.semantic import Attribute, Method, Type +from src.cmp.semantic import VoidType, ErrorType, IntType +from src.cmp.semantic import Context + +# from cp14 import TypeCollector, TypeBuilder, run_pipeline +from src.cmp.semantic import Scope + +WRONG_SIGNATURE = 'Method "%s" already defined in "%s" with a different signature.' +SELF_IS_READONLY = 'Variable "self" is read-only.' +LOCAL_ALREADY_DEFINED = 'Variable "%s" is already defined in method "%s".' +INCOMPATIBLE_TYPES = 'Cannot convert "%s" into "%s".' +VARIABLE_NOT_DEFINED = 'Variable "%s" is not defined in "%s".' +INVALID_OPERATION = 'Operation is not defined between "%s" and "%s".' + + +class TypeChecker: + def __init__(self, context, errors=[]): + self.context = context + self.current_type = None + self.current_method = None + self.errors = errors + + @visitor.on("node") + def visit(self, node, scope): + pass + + @visitor.when(ProgramNode) + def visit(self, node, scope=None): + scope = Scope() + for declaration in node.declarations: + self.visit(declaration, scope.create_child()) + return scope + + @visitor.when(ClassDeclarationNode) + def visit(self, node, scope): + self.current_type = self.context.get_type(node.id) + scope.define_variable("self", self.current_type) + + for attr in self.current_type.attributes: + scope.define_variable(attr.name, attr.type) + + for feature in node.features: + self.visit(feature, scope) + + @visitor.when(AttrDeclarationNode) + def visit(self, node, scope): + try: + typex = self.context.get_type(node.type) + + except SemanticError as e: + self.errors.append(e) + return ErrorType() + + if node.init_exp != None: + init_expr_type = self.visit(node.init_exp, scope) + if not init_expr_type.conforms_to(typex): + self.errors.append(INCOMPATIBLE_TYPES % (init_expr_type, typex)) + + return typex + + @visitor.when(FuncDeclarationNode) + def visit(self, node, scope): + self.current_method = self.current_type.get_method(node.id) + + child_scope = scope.create_child() + + for i in range(len(self.current_method.param_names)): + child_scope.define_variable( + self.current_method.param_names[i], self.current_method.param_types[i] + ) + + body_type = self.visit(node.body, child_scope) + + if not body_type.conforms_to(self.current_method.return_type): + self.errors.append( + INCOMPATIBLE_TYPES + % (body_type.name, self.current_method.return_type.name) + ) + + if self.current_type.parent is not None: + try: + parent_method = self.current_type.parent.get_method( + self.current_method.name + ) + if parent_method != self.current_method: + self.errors.append(WRONG_SIGNATURE % (parent_method.name, "parent")) + except SemanticError: + pass + + try: + return_type = self.context.get_type(node.type) + return return_type + + except SemanticError as e: + self.errors.append(e) + return ErrorType() + + @visitor.when(VarDeclarationNode) + def visit(self, node, scope): + if scope.is_local(node.id): + self.errors.append( + LOCAL_ALREADY_DEFINED % (node.id, self.current_method.name) + ) + elif node.id == "self": + self.errors.append(SELF_IS_READONLY) + try: + static_type = self.context.get_type(node.type) + except SemanticError as error: + self.errors.append(error.text) + static_type = ErrorType() + + expr_type = self.visit(node.expr, scope) + if not expr_type.conforms_to(static_type): + self.errors.append(INCOMPATIBLE_TYPES % (expr_type.name, static_type.name)) + + scope.define_variable(node.id, static_type) + return static_type + + @visitor.when(AssignNode) + def visit(self, node, scope): + if node.id == "self": + self.errors.append(SELF_IS_READONLY) + + var_type = None + if not scope.is_defined(node.id): + self.errors.append( + VARIABLE_NOT_DEFINED % (node.id, self.current_method.name) + ) + var_type = ErrorType() + else: + var_type = scope.find_variable(node.id).type + + expr_type = self.visit(node.expr, scope) + if not expr_type.conforms_to(var_type): + self.errors.append(INCOMPATIBLE_TYPES % (expr_type.name, var_type.name)) + + return var_type + + @visitor.when(CallNode) + def visit(self, node, scope): + auto_type = self.context.get_type("AUTO_TYPE") + typex = None + if node.obj is not None: + typex = self.visit(node.obj, scope) + if typex == auto_type: + return auto_type + + else: + typex = self.current_type + + if typex == self.context.get_type("Void"): + self.errors.append("Void type cannot dispatch") + return ErrorType() + + method = None + try: + if node.at_type is not None: + node_at_type = self.context.get_type(node.at_type) + method = node_at_type.get_method(node.id) + if not typex.conforms_to(node_at_type): + self.errors.append( + "The static type to the left of @ must conform to the type specified to the right of @ " + ) + return ErrorType() + else: + method = typex.get_method(node.id) + except SemanticError as error: + self.errors.append(error.text) + return ErrorType() + + if len(method.param_names) != len(node.args): + self.errors.append( + f"There is no definition of {method.name} that takes {len(node.args)} arguments " + ) + + for arg, ptype in zip(node.args, method.param_types): + arg_type = self.visit(arg, scope) + if not arg_type.conforms_to(ptype): + self.errors.append(INCOMPATIBLE_TYPES % (arg_type.name, ptype.name)) + + if method.return_type == self.context.get_type("SELF_TYPE"): + return typex + + return method.return_type + + @visitor.when(IfNode) + def visit(self, node, scope): + bool_type = self.context.get_type("Bool") + predicate_type = self.visit(node.if_expr, scope) + + if predicate_type != bool_type: + self.errors.append("Expression must be bool") + return ErrorType() + + then_type = self.visit(node.then_expr, scope) + else_type = self.visit(node.else_expr, scope) + + least_type = find_least_type(then_type, else_type, self.context) + return least_type + + @visitor.when(WhileNode) + def visit(self, node, scope): + condition_type = self.visit(node.condition, scope) + bool_type = self.context.get_type("Bool") + + if condition_type != bool_type: + self.errors.append("Expression must be bool") + return ErrorType() + + return self.context.get_type("Object") + + @visitor.when(BlockNode) + def visit(self, node, scope): + typex = None + for expr in node.expression_list: + typex = self.visit(expr, scope) + + return typex + + @visitor.when(LetNode) + def visit(self, node, scope): + + child_scope = scope.create_child() + + for var_dec in node.identifiers: + self.visit(var_dec, child_scope) + + return self.visit(node.body, child_scope) + + @visitor.when(VarDeclarationNode) + def visit(self, node, scope): + + static_type = None + try: + static_type = self.context.get_type(node.type) + scope.define_variable(node.id, static_type) + + except SemanticError as e: + self.errors.append(e) + return ErrorType() + + if node.expr != None: + typex = self.visit(node.expr, scope) + if not typex.conforms_to(static_type): + self.errors.append(INCOMPATIBLE_TYPES % (typex, static_type)) + + return static_type + + @visitor.when(CaseNode) + def visit(self, node, scope): + self.visit(node.expr, scope) + # typex = self.visit(node.expr, scope) + # if typex == self.context.get_type("Void"): + # self.errors.append("Case expression cannot be Void") + # return ErrorType() + + current_case_type = None + for item in node.case_items: + child_scope = scope.create_child() + case_item_type = self.visit(item, child_scope) + current_case_type = find_least_type( + current_case_type, case_item_type, self.context + ) + + return current_case_type + + @visitor.when(CaseItemNode) + def visit(self, node, scope): + try: + static_type = self.context.get_type(node.type) + scope.define_variable(node.id, static_type) + except SemanticError as e: + self.errors.append(e) + return ErrorType() + + typex = self.visit(node.expr, scope) + + return typex + + @visitor.when(InstantiateNode) # NewNode + def visit(self, node, scope): + try: + typex = self.context.get_type(node.lex) + return typex + except SemanticError as error: + self.errors.append(error.text) + return ErrorType() + + @visitor.when(IsvoidNode) + def visit(self, node, scope): + self.visit(node.expr, scope) + return self.context.get_type("Bool") + + @visitor.when(ArithmeticOperation) + def visit(self, node, scope): + int_type = self.context.get_type("Int") + left_type = self.visit(node.left, scope) + right_type = self.visit(node.right, scope) + + if not left_type.conforms_to(int_type) or not right_type.conforms_to(int_type): + self.errors.append(INVALID_OPERATION % (left_type.name, right_type.name)) + + return int_type + + @visitor.when(ComparisonOperation) + def visit(self, node, scope): + int_type = self.context.get_type("Int") + left_type = self.visit(node.left, scope) + right_type = self.visit(node.right, scope) + + if not left_type.conforms_to(int_type) or not right_type.conforms_to(int_type): + self.errors.append(INVALID_OPERATION % (left_type.name, right_type.name)) + + return self.context.get_type("Bool") + + @visitor.when(EqualNode) + def visit(self, node, scope): + int_type = self.context.get_type("Int") + string_type = self.context.get_type("String") + bool_type = self.context.get_type("Bool") + built_in_types = [int_type, string_type, bool_type] + + left_type = self.visit(node.left, scope) + right_type = self.visit(node.right, scope) + + if left_type in built_in_types or right_type in built_in_types: + if left_type != right_type: + self.errors.append( + "Since one of the expressions of '=' operator is of type Int, String or Bool, the other must have the same static type" + ) + + return self.context.get_type("Void") + + @visitor.when(NotNode) + def visit(self, node, scope): + bool_type = self.context.get_type("Bool") + typex = self.visit(node.expr, scope) + + if typex != bool_type: + self.errors.append("Expression must be Bool") + return ErrorType() + + return bool_type + + @visitor.when(NegNode) + def visit(self, node, scope): + int_type = self.context.get_type("Int") + typex = self.visit(node.expr, scope) + + if typex != int_type: + self.errors.append("Expression must be Int") + return ErrorType() + + return int_type + + @visitor.when(ConstantNumNode) + def visit(self, node, scope): + return self.context.get_type("Int") + + @visitor.when(VariableNode) + def visit(self, node, scope): + var = scope.find_variable(node.lex) + if var is None: + self.errors.append( + VARIABLE_NOT_DEFINED % (node.lex, self.current_method.name) + ) + return ErrorType() + return var.type + + @visitor.when(StringNode) + def visit(self, node, scope): + return self.context.get_type("String") + + @visitor.when(BooleanNode) + def visit(self, node, scope): + return self.context.get_type("Bool") + + +def find_least_type(type_a, type_b, context): + if type_a is None: + return type_b + + if type_b is None: + return type_a + + if type_a.conforms_to(type_b): + return type_b + + if type_b.conforms_to(type_a): + return type_a + + solve = type_a.parent + while solve is not None: + print("Solve ----------------> " + str(solve)) + if type_b.conforms_to(solve): + return solve + solve = solve.parent + + return context.get_type("Object") + diff --git a/src/type_collector.py b/src/type_collector.py new file mode 100644 index 000000000..c920a4dd8 --- /dev/null +++ b/src/type_collector.py @@ -0,0 +1,52 @@ +from src.cmp.semantic import SemanticError +from src.cmp.semantic import Attribute, Method, Type +from src.cmp.semantic import ( + VoidType, + IntType, + ErrorType, + StringType, + BoolType, + AutoType, + ObjectType, + SelfType, +) +from src.cmp.semantic import Context +from src.ast_nodes import ProgramNode, ClassDeclarationNode +import src.cmp.visitor as visitor + + +class TypeCollector(object): + def __init__(self, errors=[]): + self.context = None + self.errors = errors + + @visitor.on("node") + def visit(self, node): + pass + + @visitor.when(ProgramNode) + def visit(self, node): + self.context = Context() + self.context.types["Object"] = ObjectType() + self.context.types["Int"] = IntType() + self.context.types["Void"] = VoidType() + self.context.types["String"] = StringType() + self.context.types["Bool"] = BoolType() + self.context.types["AUTO_TYPE"] = AutoType() + self.context.types["SELF_TYPE"] = SelfType() + + object_type = self.context.get_type("Object") + for typex in self.context.types.values(): + if typex == object_type: + continue + typex.set_parent(object_type) + + for declaration in node.declarations: + self.visit(declaration) + + @visitor.when(ClassDeclarationNode) + def visit(self, node): + try: + self.context.create_type(node.id) + except SemanticError as error: + self.errors.append(error.text) diff --git a/test/run_pipeline.py b/test/run_pipeline.py new file mode 100644 index 000000000..e2f00737b --- /dev/null +++ b/test/run_pipeline.py @@ -0,0 +1,28 @@ +from src.cool_tokenizer import tokenize_cool_text +from src.cool_grammar import define_cool_grammar +from src.cool_visitor import FormatVisitor + +from src.shift_reduce_parsers import LR1Parser, DerivationTree +from src.errors import parsing_table_error, Error + +from src.cmp.evaluation import evaluate_reverse_parse + + +def run_pipeline(text): + # define grammar + grammar, idx, num = define_cool_grammar() + + # tokenize text + tokens = tokenize_cool_text(grammar, text, idx, num, True) + # print(tokens) + # try: + parser = LR1Parser(grammar) + parse, operations = parser([t.token_type for t in tokens]) + # print("\n".join(repr(x) for x in parse)) + # print(operations) + + ast = evaluate_reverse_parse(parse, operations, tokens) + + return ast + # print(tree) + # derivation_list = parser(text) diff --git a/test/test_parser1.py b/test/test_parser1.py new file mode 100644 index 000000000..203c70bef --- /dev/null +++ b/test/test_parser1.py @@ -0,0 +1,37 @@ +from run_pipeline import run_pipeline +from src.cool_visitor import FormatVisitor + + +def test(): + text = """ + class Cons inherits List { + xcar : Int ; + xcdr : List ; + + isNill ( ) : Bool { + false + } ; + + init ( hd : Int , tl : List ) : Cons { + { + xcar <- hd ; + xcdr <- tl ; + self ; + } + } ; + } ; + """ + + ast = run_pipeline(text) + + formatter = FormatVisitor() + tree = formatter.visit(ast) + + tree = tree.replace("\t", "") + tree = tree.replace("\n", "") + tree = tree.replace("\\", "") + + assert ( + tree + == "__ProgramNode [ ... ]__ClassDeclarationNode: class Cons inherits List { ... }__AttrDeclarationNode: xcar : Int <- __NONE__AttrDeclarationNode: xcdr : List <- __NONE__FuncDeclarationNode: isNill() : Bool -> __ BooleanNode: false__FuncDeclarationNode: init(hd:Int, tl:List) : Cons -> __BlockNode: {; ... ;}__AssignNode: xcar <- __ VariableNode: hd__AssignNode: xcdr <- __ VariableNode: tl__ VariableNode: self" + ) diff --git a/test/test_parser2.py b/test/test_parser2.py new file mode 100644 index 000000000..7375d1697 --- /dev/null +++ b/test/test_parser2.py @@ -0,0 +1,37 @@ +from run_pipeline import run_pipeline +from src.cool_visitor import FormatVisitor + + +def test(): + text = """ + class Cons inherits List { + xcar : String ; + xcdr : List ; + + isNill ( ) : Bool { + false + } ; + + init ( hd : Int , tl : List ) : Cons { + { + xcar <- " testing strings " ; + xcdr <- tl ; + self ; + } + } ; + } ; + """ + + ast = run_pipeline(text) + + formatter = FormatVisitor() + tree = formatter.visit(ast) + + tree = tree.replace("\t", "") + tree = tree.replace("\n", "") + tree = tree.replace("\\", "") + + assert ( + tree + == "__ProgramNode [ ... ]__ClassDeclarationNode: class Cons inherits List { ... }__AttrDeclarationNode: xcar : String <- __NONE__AttrDeclarationNode: xcdr : List <- __NONE__FuncDeclarationNode: isNill() : Bool -> __ BooleanNode: false__FuncDeclarationNode: init(hd:Int, tl:List) : Cons -> __BlockNode: {; ... ;}__AssignNode: xcar <- __ StringNode: testing strings __AssignNode: xcdr <- __ VariableNode: tl__ VariableNode: self" + ) diff --git a/test/test_parser3.py b/test/test_parser3.py new file mode 100644 index 000000000..e575c8f70 --- /dev/null +++ b/test/test_parser3.py @@ -0,0 +1,31 @@ +from run_pipeline import run_pipeline +from src.cool_visitor import FormatVisitor + + +def test(): + text = """ + class Main inherits IO { + main ( ) : AUTO_TYPE { + let x : AUTO_TYPE <- 3 + 2 in { + case x of + y : Int => out_string ( " Ok " ) ; + esac ; + } + } ; + } ; + """ + + ast = run_pipeline(text) + + formatter = FormatVisitor() + tree = formatter.visit(ast) + + tree = tree.replace("\t", "") + tree = tree.replace("\n", "") + tree = tree.replace("\\", "") + + assert ( + tree + == "__ProgramNode [ ... ]__ClassDeclarationNode: class Main inherits IO { ... }__FuncDeclarationNode: main() : AUTO_TYPE -> __LetNode: let in __VarDeclarationNode: x : AUTO_TYPE <- __ PlusNode __ ConstantNumNode: 3__ ConstantNumNode: 2__BlockNode: {; ... ;}__LetNode: case of esac__ VariableNode: x__CaseItemNode: y : Int => ;__CallNode: out_string(, ..., )__ StringNode: Ok " + ) + diff --git a/test/test_parser4.py b/test/test_parser4.py new file mode 100644 index 000000000..1ef6a2312 --- /dev/null +++ b/test/test_parser4.py @@ -0,0 +1,29 @@ +from run_pipeline import run_pipeline +from src.cool_visitor import FormatVisitor + + +def test(): + text = """ + class Point { + x : AUTO_TYPE ; + y : AUTO_TYPE ; + init ( n : Int , m : Int ) : SELF_TYPE { + { + x <- n ; + y <- m ; + } } ; + } ; + """ + + ast = run_pipeline(text) + + formatter = FormatVisitor() + tree = formatter.visit(ast) + + tree = tree.replace("\t", "") + tree = tree.replace("\n", "") + tree = tree.replace("\\", "") + assert ( + tree + == "__ProgramNode [ ... ]__ClassDeclarationNode: class Point { ... }__AttrDeclarationNode: x : AUTO_TYPE <- __NONE__AttrDeclarationNode: y : AUTO_TYPE <- __NONE__FuncDeclarationNode: init(n:Int, m:Int) : SELF_TYPE -> __BlockNode: {; ... ;}__AssignNode: x <- __ VariableNode: n__AssignNode: y <- __ VariableNode: m" + ) diff --git a/test/test_parser5.py b/test/test_parser5.py new file mode 100644 index 000000000..c50ba7b97 --- /dev/null +++ b/test/test_parser5.py @@ -0,0 +1,24 @@ +from run_pipeline import run_pipeline +from src.cool_visitor import FormatVisitor + + +def test(): + text = """ + class Point { + succ ( n : Int ) : AUTO_TYPE { n + 1 } ; + } ; + """ + + ast = run_pipeline(text) + + formatter = FormatVisitor() + tree = formatter.visit(ast) + + tree = tree.replace("\t", "") + tree = tree.replace("\n", "") + tree = tree.replace("\\", "") + + assert ( + tree + == "__ProgramNode [ ... ]__ClassDeclarationNode: class Point { ... }__FuncDeclarationNode: succ(n:Int) : AUTO_TYPE -> __ PlusNode __ VariableNode: n__ ConstantNumNode: 1" + ) diff --git a/test/test_parser6.py b/test/test_parser6.py new file mode 100644 index 000000000..5b4da6605 --- /dev/null +++ b/test/test_parser6.py @@ -0,0 +1,28 @@ +from run_pipeline import run_pipeline +from src.cool_visitor import FormatVisitor + + +def test(): + text = """ + class Point { + step ( p : AUTO_TYPE ) : AUTO_TYPE { p . translate ( 1 , 1 ) } ; + main ( ) : Object { + let p : AUTO_TYPE <- new Point in { + step ( p ) ; *Puede lanzar error semantico* + } + } ; + } ; + """ + + ast = run_pipeline(text) + + formatter = FormatVisitor() + tree = formatter.visit(ast) + + tree = tree.replace("\t", "") + tree = tree.replace("\n", "") + tree = tree.replace("\\", "") + assert ( + tree + == "__ProgramNode [ ... ]__ClassDeclarationNode: class Point { ... }__FuncDeclarationNode: step(p:AUTO_TYPE) : AUTO_TYPE -> __CallNode: .translate(, ..., )__ VariableNode: p__ ConstantNumNode: 1__ ConstantNumNode: 1__FuncDeclarationNode: main() : Object -> __LetNode: let in __VarDeclarationNode: p : AUTO_TYPE <- __ InstantiateNode: new Point()__BlockNode: {; ... ;}__CallNode: step(, ..., )__ VariableNode: p" + ) diff --git a/test/test_type_builder.py b/test/test_type_builder.py new file mode 100644 index 000000000..fd2436890 --- /dev/null +++ b/test/test_type_builder.py @@ -0,0 +1,39 @@ +from run_pipeline import run_pipeline +from src.type_collector import TypeCollector +from src.type_builder import TypeBuilder + + +def test(): + text = """ + class A { + a : String ; + b : Bool ; + c : Int <- 0 ; + d : Void <- while c < 1 loop c = c + 1 pool ; + } ; + class Point { + step ( p : AUTO_TYPE ) : AUTO_TYPE { p . translate ( 1 , 1 ) } ; + main ( ) : Object { + let p : AUTO_TYPE <- new Point in { + step ( p ) ; *Puede lanzar error semantico* + } + } ; + } ; + """ + + ast = run_pipeline(text) + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + print("Errors:", errors) + print("Context:") + print(context) + + assert errors == [] diff --git a/test/test_type_checker.py b/test/test_type_checker.py new file mode 100644 index 000000000..dfa19744a --- /dev/null +++ b/test/test_type_checker.py @@ -0,0 +1,75 @@ +from run_pipeline import run_pipeline +from src.type_collector import TypeCollector +from src.type_builder import TypeBuilder +from src.type_checker import TypeChecker + + +def test(): + text = """ + class A { + a : String ; + b : Bool ; + c : Int <- 0 ; + d : Void <- while c < 1 loop c = c + 1 pool ; + step ( p : AUTO_TYPE ) : AUTO_TYPE { p . translate ( 1 , 1 ) } ; + } ; + + class Point { + step ( p : AUTO_TYPE ) : AUTO_TYPE { p . translate ( 1 , 1 ) } ; + main ( ) : Object { + let p : AUTO_TYPE <- new Point in { + step ( p ) ; *Puede lanzar error semantico* + } + } ; + } ; + class B inherits A { + e : Bool ; + step ( p : AUTO_TYPE ) : AUTO_TYPE { p } ; + test ( e : Int ) : Bool { + { + let x : Int <- 4 in e + ~ x ; + + case 5 + 4 of + f : Bool => f ; + g : Bool => not g ; + esac ; + self . step ( e ) ; + } + } ; + } ; + + class C { + a : B ; + b : Int <- 8 ; + c : Bool <- false ; + + m ( ) : Bool { + { + a @ A . step ( b ) ; + if not c then true else false fi ; + a . step ( b ) ; + } + } ; + } ; + """ + + ast = run_pipeline(text) + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + scope = checker.visit(ast, None) + + print("Errors:", errors) + print("Context:") + print(context) + print(scope) + + assert errors == [] diff --git a/test/test_type_collector.py b/test/test_type_collector.py new file mode 100644 index 000000000..5f90576a4 --- /dev/null +++ b/test/test_type_collector.py @@ -0,0 +1,30 @@ +from run_pipeline import run_pipeline +from src.type_collector import TypeCollector + + +def test(): + text = """ + class A { } ; + class Point { + step ( p : AUTO_TYPE ) : AUTO_TYPE { p . translate ( 1 , 1 ) } ; + main ( ) : Object { + let p : AUTO_TYPE <- new Point in { + step ( p ) ; *Puede lanzar error semantico* + } + } ; + } ; + """ + + ast = run_pipeline(text) + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + # context = collector.context + + # print("Errors:", errors) + # print("Context:") + # print(context) + + assert errors == [] From bf6c141103e077f6b33ee475cd08569a46562c36 Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Wed, 25 Nov 2020 23:37:40 -0500 Subject: [PATCH 006/162] Refactor --- .gitignore | 10 +- ast_nodes.py | 182 -------------- cmp/__init__.py | 0 cmp/ast.py | 62 ----- cmp/automata.py | 207 ---------------- cmp/cil.py | 231 ------------------ cmp/evaluation.py | 36 --- cmp/languages.py | 228 ------------------ cmp/nbpackage.py | 87 ------- cmp/pycompiler.py | 512 ---------------------------------------- cmp/semantic.py | 214 ----------------- cmp/utils.py | 219 ----------------- cmp/visitor.py | 80 ------- cool_grammar.py | 184 --------------- cool_tokenizer.py | 43 ---- cool_visitor.py | 161 ------------- errors.py | 61 ----- main.py | 98 -------- methods.py | 150 ------------ notes.txt | 3 - parser_automatons.py | 225 ------------------ shift_reduce_parsers.py | 273 --------------------- 22 files changed, 8 insertions(+), 3258 deletions(-) delete mode 100644 ast_nodes.py delete mode 100755 cmp/__init__.py delete mode 100755 cmp/ast.py delete mode 100755 cmp/automata.py delete mode 100755 cmp/cil.py delete mode 100755 cmp/evaluation.py delete mode 100755 cmp/languages.py delete mode 100755 cmp/nbpackage.py delete mode 100755 cmp/pycompiler.py delete mode 100755 cmp/semantic.py delete mode 100755 cmp/utils.py delete mode 100755 cmp/visitor.py delete mode 100644 cool_grammar.py delete mode 100644 cool_tokenizer.py delete mode 100644 cool_visitor.py delete mode 100644 errors.py delete mode 100644 main.py delete mode 100644 methods.py delete mode 100644 notes.txt delete mode 100644 parser_automatons.py delete mode 100644 shift_reduce_parsers.py diff --git a/.gitignore b/.gitignore index 8ce41bc1b..bb58c3f8b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,8 @@ -cmp/__pycache__/ -__pycache__/ +__pycache__/ +src/__pycache__/ +test/__pycache__/ +src/cmp/__pycache__/ +src/cmp/tools/__pycache__/ +.directory/ +.pytest_cache/ + diff --git a/ast_nodes.py b/ast_nodes.py deleted file mode 100644 index fc033fdb0..000000000 --- a/ast_nodes.py +++ /dev/null @@ -1,182 +0,0 @@ -class Node: - pass - - -class ProgramNode(Node): - def __init__(self, declarations): - self.declarations = declarations - - -class DeclarationNode(Node): - pass - - -class ExpressionNode(Node): - pass - - -class ClassDeclarationNode(DeclarationNode): - def __init__(self, idx, features, parent=None): - self.id = idx - self.parent = parent - self.features = features - - -class FuncDeclarationNode(DeclarationNode): - def __init__(self, idx, params, return_type, body): - self.id = idx - self.params = params - self.type = return_type - self.body = body - - -class AttrDeclarationNode(DeclarationNode): - def __init__(self, idx, typex, init_exp=None): - self.id = idx - self.type = typex - self.init_exp = init_exp - - -class VarDeclarationNode(ExpressionNode): - def __init__(self, idx, typex, expr=None): - self.id = idx - self.type = typex - self.expr = expr - - -class AssignNode(ExpressionNode): - def __init__(self, idx, expr): - self.id = idx - self.expr = expr - - -class LetNode(ExpressionNode): - def __init__(self, identifiers, body): - self.identifiers = identifiers - self.body = body - - -class IfNode(ExpressionNode): - def __init__(self, if_exp, then_exp, else_exp): - self.if_expr = if_exp - self.then_expr = then_exp - self.else_expr = else_exp - - -class WhileNode(ExpressionNode): - def __init__(self, condition, body): - self.condition = condition - self.body = body - - -class CaseNode(ExpressionNode): - def __init__(self, exp, case_items): - self.expr = exp - self.case_items = case_items - - -class CaseItemNode(ExpressionNode): - def __init__(self, idx, typex, exp): - self.id = idx - self.type = typex - self.expr = exp - - -# #atomic? -# class NotNode(ExpressionNode): -# def __init__(self, exp): -# self.exp = exp - -# method_name=id, args,obj,type -# aaaaaaaaaaaaaaaaaaaaaaaaaaaa que hago con estooooooooooooooooooooooooooo -class CallNode(ExpressionNode): - def __init__(self, idx, args, obj=None, at_type=None): - self.obj = obj - self.id = idx - self.args = args - self.at_type = at_type - - -class BlockNode(ExpressionNode): - def __init__(self, expresion_list): - self.expresion_list = expresion_list - - -class AtomicNode(ExpressionNode): - def __init__(self, lex): - self.lex = lex - - -class UnaryNode(ExpressionNode): - def __init__(self, expr): - self.expr = expr - - -class BinaryNode(ExpressionNode): - def __init__(self, left, right): - self.left = left - self.right = right - - -class ConstantNumNode(AtomicNode): - pass - - -class VariableNode(AtomicNode): - pass - - -class StringNode(AtomicNode): - pass - - -class BooleanTrueNode(AtomicNode): - pass - - -class BooleanFalseNode(AtomicNode): - pass - - -class InstantiateNode(AtomicNode): - pass - - -class NotNode(UnaryNode): - pass - - -class IsvoidNode(UnaryNode): - pass - - -class NegNode(UnaryNode): - pass - - -class PlusNode(BinaryNode): - pass - - -class MinusNode(BinaryNode): - pass - - -class StarNode(BinaryNode): - pass - - -class DivNode(BinaryNode): - pass - - -class LessNode(BinaryNode): - pass - - -class LessEqualNode(BinaryNode): - pass - - -class EqualNode(BinaryNode): - pass diff --git a/cmp/__init__.py b/cmp/__init__.py deleted file mode 100755 index e69de29bb..000000000 diff --git a/cmp/ast.py b/cmp/ast.py deleted file mode 100755 index ec162b83b..000000000 --- a/cmp/ast.py +++ /dev/null @@ -1,62 +0,0 @@ -import cmp.visitor as visitor - -class Node: - def evaluate(self): - raise NotImplementedError() - -class AtomicNode(Node): - def __init__(self, lex): - self.lex = lex - -class UnaryNode(Node): - def __init__(self, node): - self.node = node - - def evaluate(self): - value = self.node.evaluate() - return self.operate(value) - - @staticmethod - def operate(value): - raise NotImplementedError() - -class BinaryNode(Node): - def __init__(self, left, right): - self.left = left - self.right = right - - def evaluate(self): - lvalue = self.left.evaluate() - rvalue = self.right.evaluate() - return self.operate(lvalue, rvalue) - - @staticmethod - def operate(lvalue, rvalue): - raise NotImplementedError() - -def get_printer(AtomicNode=AtomicNode, UnaryNode=UnaryNode, BinaryNode=BinaryNode, ): - - class PrintVisitor(object): - @visitor.on('node') - def visit(self, node, tabs): - pass - - @visitor.when(UnaryNode) - def visit(self, node, tabs=0): - ans = '\t' * tabs + f'\\__ {node.__class__.__name__}' - child = self.visit(node.node, tabs + 1) - return f'{ans}\n{child}' - - @visitor.when(BinaryNode) - def visit(self, node, tabs=0): - ans = '\t' * tabs + f'\\__ {node.__class__.__name__} ' - left = self.visit(node.left, tabs + 1) - right = self.visit(node.right, tabs + 1) - return f'{ans}\n{left}\n{right}' - - @visitor.when(AtomicNode) - def visit(self, node, tabs=0): - return '\t' * tabs + f'\\__ {node.__class__.__name__}: {node.lex}' - - printer = PrintVisitor() - return (lambda ast: printer.visit(ast)) \ No newline at end of file diff --git a/cmp/automata.py b/cmp/automata.py deleted file mode 100755 index f42b6f00c..000000000 --- a/cmp/automata.py +++ /dev/null @@ -1,207 +0,0 @@ -try: - import pydot -except: - pass - -class State: - def __init__(self, state, final=False, formatter=lambda x: str(x), shape='circle'): - self.state = state - self.final = final - self.transitions = {} - self.epsilon_transitions = set() - self.tag = None - self.formatter = formatter - self.shape = shape - - # The method name is set this way from compatibility issues. - def set_formatter(self, value, attr='formatter', visited=None): - if visited is None: - visited = set() - elif self in visited: - return - - visited.add(self) - self.__setattr__(attr, value) - for destinations in self.transitions.values(): - for node in destinations: - node.set_formatter(value, attr, visited) - for node in self.epsilon_transitions: - node.set_formatter(value, attr, visited) - return self - - def has_transition(self, symbol): - return symbol in self.transitions - - def add_transition(self, symbol, state): - try: - self.transitions[symbol].append(state) - except: - self.transitions[symbol] = [state] - return self - - def add_epsilon_transition(self, state): - self.epsilon_transitions.add(state) - return self - - def recognize(self, string): - states = self.epsilon_closure - for symbol in string: - states = self.move_by_state(symbol, *states) - states = self.epsilon_closure_by_state(*states) - return any(s.final for s in states) - - def to_deterministic(self, formatter=lambda x: str(x)): - closure = self.epsilon_closure - start = State(tuple(closure), any(s.final for s in closure), formatter) - - closures = [ closure ] - states = [ start ] - pending = [ start ] - - while pending: - state = pending.pop() - symbols = { symbol for s in state.state for symbol in s.transitions } - - for symbol in symbols: - move = self.move_by_state(symbol, *state.state) - closure = self.epsilon_closure_by_state(*move) - - if closure not in closures: - new_state = State(tuple(closure), any(s.final for s in closure), formatter) - closures.append(closure) - states.append(new_state) - pending.append(new_state) - else: - index = closures.index(closure) - new_state = states[index] - - state.add_transition(symbol, new_state) - - return start - - @staticmethod - def from_nfa(nfa, get_states=False): - states = [] - for n in range(nfa.states): - state = State(n, n in nfa.finals) - states.append(state) - - for (origin, symbol), destinations in nfa.map.items(): - origin = states[origin] - origin[symbol] = [ states[d] for d in destinations ] - - if get_states: - return states[nfa.start], states - return states[nfa.start] - - @staticmethod - def move_by_state(symbol, *states): - return { s for state in states if state.has_transition(symbol) for s in state[symbol]} - - @staticmethod - def epsilon_closure_by_state(*states): - closure = { state for state in states } - - l = 0 - while l != len(closure): - l = len(closure) - tmp = [s for s in closure] - for s in tmp: - for epsilon_state in s.epsilon_transitions: - closure.add(epsilon_state) - return closure - - @property - def epsilon_closure(self): - return self.epsilon_closure_by_state(self) - - @property - def name(self): - return self.formatter(self.state) - - def get(self, symbol): - target = self.transitions[symbol] - assert len(target) == 1 - return target[0] - - def __getitem__(self, symbol): - if symbol == '': - return self.epsilon_transitions - try: - return self.transitions[symbol] - except KeyError: - return None - - def __setitem__(self, symbol, value): - if symbol == '': - self.epsilon_transitions = value - else: - self.transitions[symbol] = value - - def __repr__(self): - return str(self) - - def __str__(self): - return str(self.state) - - def __hash__(self): - return hash(self.state) - - def __iter__(self): - yield from self._visit() - - def _visit(self, visited=None): - if visited is None: - visited = set() - elif self in visited: - return - - visited.add(self) - yield self - - for destinations in self.transitions.values(): - for node in destinations: - yield from node._visit(visited) - for node in self.epsilon_transitions: - yield from node._visit(visited) - - def graph(self): - G = pydot.Dot(rankdir='LR', margin=0.1) - G.add_node(pydot.Node('start', shape='plaintext', label='', width=0, height=0)) - - visited = set() - def visit(start): - ids = id(start) - if ids not in visited: - visited.add(ids) - G.add_node(pydot.Node(ids, label=start.name, shape=self.shape, style='bold' if start.final else '')) - for tran, destinations in start.transitions.items(): - for end in destinations: - visit(end) - G.add_edge(pydot.Edge(ids, id(end), label=tran, labeldistance=2)) - for end in start.epsilon_transitions: - visit(end) - G.add_edge(pydot.Edge(ids, id(end), label='ε', labeldistance=2)) - - visit(self) - G.add_edge(pydot.Edge('start', id(self), label='', style='dashed')) - - return G - - def _repr_svg_(self): - try: - return self.graph().create_svg().decode('utf8') - except: - pass - - def write_to(self, fname): - return self.graph().write_svg(fname) - -def multiline_formatter(state): - return '\n'.join(str(item) for item in state) - -def lr0_formatter(state): - try: - return '\n'.join(str(item)[:-4] for item in state) - except TypeError: - return str(state)[:-4] \ No newline at end of file diff --git a/cmp/cil.py b/cmp/cil.py deleted file mode 100755 index de6782c16..000000000 --- a/cmp/cil.py +++ /dev/null @@ -1,231 +0,0 @@ -import cmp.visitor as visitor - - -class Node: - pass - -class ProgramNode(Node): - def __init__(self, dottypes, dotdata, dotcode): - self.dottypes = dottypes - self.dotdata = dotdata - self.dotcode = dotcode - -class TypeNode(Node): - def __init__(self, name): - self.name = name - self.attributes = [] - self.methods = [] - -class DataNode(Node): - def __init__(self, vname, value): - self.name = vname - self.value = value - -class FunctionNode(Node): - def __init__(self, fname, params, localvars, instructions): - self.name = fname - self.params = params - self.localvars = localvars - self.instructions = instructions - -class ParamNode(Node): - def __init__(self, name): - self.name = name - -class LocalNode(Node): - def __init__(self, name): - self.name = name - -class InstructionNode(Node): - pass - -class AssignNode(InstructionNode): - def __init__(self, dest, source): - self.dest = dest - self.source = source - -class ArithmeticNode(InstructionNode): - def __init__(self, dest, left, right): - self.dest = dest - self.left = left - self.right = right - -class PlusNode(ArithmeticNode): - pass - -class MinusNode(ArithmeticNode): - pass - -class StarNode(ArithmeticNode): - pass - -class DivNode(ArithmeticNode): - pass - -class GetAttribNode(InstructionNode): - pass - -class SetAttribNode(InstructionNode): - pass - -class GetIndexNode(InstructionNode): - pass - -class SetIndexNode(InstructionNode): - pass - -class AllocateNode(InstructionNode): - def __init__(self, itype, dest): - self.type = itype - self.dest = dest - -class ArrayNode(InstructionNode): - pass - -class TypeOfNode(InstructionNode): - def __init__(self, obj, dest): - self.obj = obj - self.dest = dest - -class LabelNode(InstructionNode): - pass - -class GotoNode(InstructionNode): - pass - -class GotoIfNode(InstructionNode): - pass - -class StaticCallNode(InstructionNode): - def __init__(self, function, dest): - self.function = function - self.dest = dest - -class DynamicCallNode(InstructionNode): - def __init__(self, xtype, method, dest): - self.type = xtype - self.method = method - self.dest = dest - -class ArgNode(InstructionNode): - def __init__(self, name): - self.name = name - -class ReturnNode(InstructionNode): - def __init__(self, value=None): - self.value = value - -class LoadNode(InstructionNode): - def __init__(self, dest, msg): - self.dest = dest - self.msg = msg - -class LengthNode(InstructionNode): - pass - -class ConcatNode(InstructionNode): - pass - -class PrefixNode(InstructionNode): - pass - -class SubstringNode(InstructionNode): - pass - -class ToStrNode(InstructionNode): - def __init__(self, dest, ivalue): - self.dest = dest - self.ivalue = ivalue - -class ReadNode(InstructionNode): - def __init__(self, dest): - self.dest = dest - -class PrintNode(InstructionNode): - def __init__(self, str_addr): - self.str_addr = str_addr - -def get_formatter(): - - class PrintVisitor(object): - @visitor.on('node') - def visit(self, node): - pass - - @visitor.when(ProgramNode) - def visit(self, node): - dottypes = '\n'.join(self.visit(t) for t in node.dottypes) - dotdata = '\n'.join(self.visit(t) for t in node.dotdata) - dotcode = '\n'.join(self.visit(t) for t in node.dotcode) - - return f'.TYPES\n{dottypes}\n\n.DATA\n{dotdata}\n\n.CODE\n{dotcode}' - - @visitor.when(TypeNode) - def visit(self, node): - attributes = '\n\t'.join(f'attribute {x}' for x in node.attributes) - methods = '\n\t'.join(f'method {x}: {y}' for x,y in node.methods) - - return f'type {node.name} {{\n\t{attributes}\n\n\t{methods}\n}}' - - @visitor.when(FunctionNode) - def visit(self, node): - params = '\n\t'.join(self.visit(x) for x in node.params) - localvars = '\n\t'.join(self.visit(x) for x in node.localvars) - instructions = '\n\t'.join(self.visit(x) for x in node.instructions) - - return f'function {node.name} {{\n\t{params}\n\n\t{localvars}\n\n\t{instructions}\n}}' - - @visitor.when(ParamNode) - def visit(self, node): - return f'PARAM {node.name}' - - @visitor.when(LocalNode) - def visit(self, node): - return f'LOCAL {node.name}' - - @visitor.when(AssignNode) - def visit(self, node): - return f'{node.dest} = {node.source}' - - @visitor.when(PlusNode) - def visit(self, node): - return f'{node.dest} = {node.left} + {node.right}' - - @visitor.when(MinusNode) - def visit(self, node): - return f'{node.dest} = {node.left} - {node.right}' - - @visitor.when(StarNode) - def visit(self, node): - return f'{node.dest} = {node.left} * {node.right}' - - @visitor.when(DivNode) - def visit(self, node): - return f'{node.dest} = {node.left} / {node.right}' - - @visitor.when(AllocateNode) - def visit(self, node): - return f'{node.dest} = ALLOCATE {node.type}' - - @visitor.when(TypeOfNode) - def visit(self, node): - return f'{node.dest} = TYPEOF {node.type}' - - @visitor.when(StaticCallNode) - def visit(self, node): - return f'{node.dest} = CALL {node.function}' - - @visitor.when(DynamicCallNode) - def visit(self, node): - return f'{node.dest} = VCALL {node.type} {node.method}' - - @visitor.when(ArgNode) - def visit(self, node): - return f'ARG {node.name}' - - @visitor.when(ReturnNode) - def visit(self, node): - return f'RETURN {node.value if node.value is not None else ""}' - - printer = PrintVisitor() - return (lambda ast: printer.visit(ast)) \ No newline at end of file diff --git a/cmp/evaluation.py b/cmp/evaluation.py deleted file mode 100755 index 0581e1841..000000000 --- a/cmp/evaluation.py +++ /dev/null @@ -1,36 +0,0 @@ -from cmp.pycompiler import EOF -from shift_reduce_parsers import ShiftReduceParser - - -def evaluate_reverse_parse(right_parse, operations, tokens): - if not right_parse or not operations or not tokens: - return - - right_parse = iter(right_parse) - tokens = iter(tokens) - stack = [] - for operation in operations: - if operation == ShiftReduceParser.SHIFT: - token = next(tokens) - stack.append(token.lex) - elif operation == ShiftReduceParser.REDUCE: - production = next(right_parse) - head, body = production - attributes = production.attributes - assert all( - rule is None for rule in attributes[1:] - ), "There must be only synteticed attributes." - rule = attributes[0] - - if len(body): - synteticed = [None] + stack[-len(body) :] - value = rule(None, synteticed) - stack[-len(body) :] = [value] - else: - stack.append(rule(None, None)) - else: - raise Exception("Invalid action!!!") - - assert len(stack) == 1 - assert isinstance(next(tokens).token_type, EOF) - return stack[0] diff --git a/cmp/languages.py b/cmp/languages.py deleted file mode 100755 index e2c0c33da..000000000 --- a/cmp/languages.py +++ /dev/null @@ -1,228 +0,0 @@ -from cmp.pycompiler import Sentence, Production -from cmp.utils import ContainerSet, Token, UnknownToken -from cmp.tools.parsing import build_parsing_table, metodo_predictivo_no_recursivo - -class BasicXCool: - def __init__(self, G): - self.G = G - self.fixed_tokens = { lex: Token(lex, G[lex]) for lex in '+ - * / ( )'.split() } - - @property - def firsts(self): - G = self.G - return { - G['+']: ContainerSet(G['+'] , contains_epsilon=False), - G['-']: ContainerSet(G['-'] , contains_epsilon=False), - G['*']: ContainerSet(G['*'] , contains_epsilon=False), - G['/']: ContainerSet(G['/'] , contains_epsilon=False), - G['(']: ContainerSet(G['('] , contains_epsilon=False), - G[')']: ContainerSet(G[')'] , contains_epsilon=False), - G['num']: ContainerSet(G['num'] , contains_epsilon=False), - G['E']: ContainerSet(G['num'], G['('] , contains_epsilon=False), - G['T']: ContainerSet(G['num'], G['('] , contains_epsilon=False), - G['F']: ContainerSet(G['num'], G['('] , contains_epsilon=False), - G['X']: ContainerSet(G['-'], G['+'] , contains_epsilon=True), - G['Y']: ContainerSet(G['/'], G['*'] , contains_epsilon=True), - Sentence(G['T'], G['X']): ContainerSet(G['num'], G['('] , contains_epsilon=False), - Sentence(G['+'], G['T'], G['X']): ContainerSet(G['+'] , contains_epsilon=False), - Sentence(G['-'], G['T'], G['X']): ContainerSet(G['-'] , contains_epsilon=False), - G.Epsilon: ContainerSet( contains_epsilon=True), - Sentence(G['F'], G['Y']): ContainerSet(G['num'], G['('] , contains_epsilon=False), - Sentence(G['*'], G['F'], G['Y']): ContainerSet(G['*'] , contains_epsilon=False), - Sentence(G['/'], G['F'], G['Y']): ContainerSet(G['/'] , contains_epsilon=False), - Sentence(G['num']): ContainerSet(G['num'] , contains_epsilon=False), - Sentence(G['('], G['E'], G[')']): ContainerSet(G['('] , contains_epsilon=False) - } - - @property - def follows(self): - G = self.G - return { - G['E']: ContainerSet(G[')'], G.EOF , contains_epsilon=False), - G['T']: ContainerSet(G[')'], G['-'], G.EOF, G['+'] , contains_epsilon=False), - G['F']: ContainerSet(G['-'], G.EOF, G['*'], G['/'], G[')'], G['+'] , contains_epsilon=False), - G['X']: ContainerSet(G[')'], G.EOF , contains_epsilon=False), - G['Y']: ContainerSet(G[')'], G['-'], G.EOF, G['+'] , contains_epsilon=False) - } - - @property - def table(self): - G = self.G - return { - ( G['E'], G['num'], ): [ Production(G['E'], Sentence(G['T'], G['X'])), ], - ( G['E'], G['('], ): [ Production(G['E'], Sentence(G['T'], G['X'])), ], - ( G['X'], G['+'], ): [ Production(G['X'], Sentence(G['+'], G['T'], G['X'])), ], - ( G['X'], G['-'], ): [ Production(G['X'], Sentence(G['-'], G['T'], G['X'])), ], - ( G['X'], G[')'], ): [ Production(G['X'], G.Epsilon), ], - ( G['X'], G.EOF, ): [ Production(G['X'], G.Epsilon), ], - ( G['T'], G['num'], ): [ Production(G['T'], Sentence(G['F'], G['Y'])), ], - ( G['T'], G['('], ): [ Production(G['T'], Sentence(G['F'], G['Y'])), ], - ( G['Y'], G['*'], ): [ Production(G['Y'], Sentence(G['*'], G['F'], G['Y'])), ], - ( G['Y'], G['/'], ): [ Production(G['Y'], Sentence(G['/'], G['F'], G['Y'])), ], - ( G['Y'], G[')'], ): [ Production(G['Y'], G.Epsilon), ], - ( G['Y'], G['-'], ): [ Production(G['Y'], G.Epsilon), ], - ( G['Y'], G.EOF, ): [ Production(G['Y'], G.Epsilon), ], - ( G['Y'], G['+'], ): [ Production(G['Y'], G.Epsilon), ], - ( G['F'], G['num'], ): [ Production(G['F'], Sentence(G['num'])), ], - ( G['F'], G['('], ): [ Production(G['F'], Sentence(G['('], G['E'], G[')'])), ] - } - - @property - def tokenizer(self): - G = self.G - fixed_tokens = self.fixed_tokens - - def tokenize_text(text): - tokens = [] - for item in text.split(): - try: - float(item) - token = Token(item, G['num']) - except ValueError: - try: - token = fixed_tokens[item] - except: - token = UnknownToken(item) - tokens.append(token) - eof = Token('$', G.EOF) - tokens.append(eof) - return tokens - - return tokenize_text - -class PowXCool: - def __init__(self, G): - self.G = G - - @property - def firsts(self): - G = self.G - return { - G['+']: ContainerSet(G['+'] , contains_epsilon=False), - G['-']: ContainerSet(G['-'] , contains_epsilon=False), - G['*']: ContainerSet(G['*'] , contains_epsilon=False), - G['/']: ContainerSet(G['/'] , contains_epsilon=False), - G['^']: ContainerSet(G['^'] , contains_epsilon=False), - G['(']: ContainerSet(G['('] , contains_epsilon=False), - G[')']: ContainerSet(G[')'] , contains_epsilon=False), - G['num']: ContainerSet(G['num'] , contains_epsilon=False), - G['E']: ContainerSet(G['num'], G['('] , contains_epsilon=False), - G['T']: ContainerSet(G['num'], G['('] , contains_epsilon=False), - G['F']: ContainerSet(G['num'], G['('] , contains_epsilon=False), - G['A']: ContainerSet(G['num'], G['('] , contains_epsilon=False), - G['X']: ContainerSet(G['-'], G['+'] , contains_epsilon=True), - G['Y']: ContainerSet(G['/'], G['*'] , contains_epsilon=True), - G['Z']: ContainerSet(G['^'] , contains_epsilon=True), - Sentence(G['T'], G['X']): ContainerSet(G['num'], G['('] , contains_epsilon=False), - Sentence(G['+'], G['T'], G['X']): ContainerSet(G['+'] , contains_epsilon=False), - Sentence(G['-'], G['T'], G['X']): ContainerSet(G['-'] , contains_epsilon=False), - G.Epsilon: ContainerSet( contains_epsilon=True), - Sentence(G['F'], G['Y']): ContainerSet(G['num'], G['('] , contains_epsilon=False), - Sentence(G['*'], G['F'], G['Y']): ContainerSet(G['*'] , contains_epsilon=False), - Sentence(G['/'], G['F'], G['Y']): ContainerSet(G['/'] , contains_epsilon=False), - Sentence(G['A'], G['Z']): ContainerSet(G['num'], G['('] , contains_epsilon=False), - Sentence(G['^'], G['F']): ContainerSet(G['^'] , contains_epsilon=False), - Sentence(G['num']): ContainerSet(G['num'] , contains_epsilon=False), - Sentence(G['('], G['E'], G[')']): ContainerSet(G['('] , contains_epsilon=False) - } - - @property - def follows(self): - G = self.G - return { - G['E']: ContainerSet(G[')'], G.EOF , contains_epsilon=False), - G['T']: ContainerSet(G['-'], G[')'], G.EOF, G['+'] , contains_epsilon=False), - G['F']: ContainerSet(G['-'], G['*'], G['/'], G[')'], G.EOF, G['+'] , contains_epsilon=False), - G['A']: ContainerSet(G['-'], G['*'], G['/'], G['^'], G[')'], G.EOF, G['+'] , contains_epsilon=False), - G['X']: ContainerSet(G[')'], G.EOF , contains_epsilon=False), - G['Y']: ContainerSet(G['-'], G[')'], G.EOF, G['+'] , contains_epsilon=False), - G['Z']: ContainerSet(G['-'], G['*'], G['/'], G[')'], G.EOF, G['+'] , contains_epsilon=False) - } - -class Regex: - def __init__(self, G): - self.G = G - - @property - def firsts(self): - G = self.G - return { - G['|']: ContainerSet(G['|'] , contains_epsilon=False), - G['*']: ContainerSet(G['*'] , contains_epsilon=False), - G['(']: ContainerSet(G['('] , contains_epsilon=False), - G[')']: ContainerSet(G[')'] , contains_epsilon=False), - G['symbol']: ContainerSet(G['symbol'] , contains_epsilon=False), - G['ε']: ContainerSet(G['ε'] , contains_epsilon=False), - G['E']: ContainerSet(G['symbol'], G['ε'], G['('] , contains_epsilon=False), - G['T']: ContainerSet(G['symbol'], G['ε'], G['('] , contains_epsilon=False), - G['F']: ContainerSet(G['symbol'], G['ε'], G['('] , contains_epsilon=False), - G['A']: ContainerSet(G['ε'], G['symbol'], G['('] , contains_epsilon=False), - G['X']: ContainerSet(G['|'] , contains_epsilon=True), - G['Y']: ContainerSet(G['symbol'], G['ε'], G['('] , contains_epsilon=True), - G['Z']: ContainerSet(G['*'] , contains_epsilon=True), - Sentence(G['T'], G['X']): ContainerSet(G['symbol'], G['ε'], G['('] , contains_epsilon=False), - Sentence(G['|'], G['E']): ContainerSet(G['|'] , contains_epsilon=False), - G.Epsilon: ContainerSet( contains_epsilon=True), - Sentence(G['F'], G['Y']): ContainerSet(G['symbol'], G['ε'], G['('] , contains_epsilon=False), - Sentence(G['T']): ContainerSet(G['symbol'], G['ε'], G['('] , contains_epsilon=False), - Sentence(G['A'], G['Z']): ContainerSet(G['symbol'], G['ε'], G['('] , contains_epsilon=False), - Sentence(G['*']): ContainerSet(G['*'] , contains_epsilon=False), - Sentence(G['symbol']): ContainerSet(G['symbol'] , contains_epsilon=False), - Sentence(G['ε']): ContainerSet(G['ε'] , contains_epsilon=False), - Sentence(G['('], G['E'], G[')']): ContainerSet(G['('] , contains_epsilon=False) - } - - @property - def follows(self): - G = self.G - return { - G['E']: ContainerSet(G[')'], G.EOF , contains_epsilon=False), - G['T']: ContainerSet(G[')'], G.EOF, G['|'] , contains_epsilon=False), - G['F']: ContainerSet(G[')'], G.EOF, G['symbol'], G['|'], G['ε'], G['('] , contains_epsilon=False), - G['A']: ContainerSet(G.EOF, G['|'], G['*'], G['('], G[')'], G['symbol'], G['ε'] , contains_epsilon=False), - G['X']: ContainerSet(G[')'], G.EOF , contains_epsilon=False), - G['Y']: ContainerSet(G[')'], G.EOF, G['|'] , contains_epsilon=False), - G['Z']: ContainerSet(G.EOF, G['|'], G['('], G[')'], G['symbol'], G['ε'] , contains_epsilon=False) - } - - @property - def table(self): - G = self.G - return { - ( G['E'], G['symbol'], ): [ Production(G['E'], Sentence(G['T'], G['X'])), ], - ( G['E'], G['ε'], ): [ Production(G['E'], Sentence(G['T'], G['X'])), ], - ( G['E'], G['('], ): [ Production(G['E'], Sentence(G['T'], G['X'])), ], - ( G['X'], G['|'], ): [ Production(G['X'], Sentence(G['|'], G['E'])), ], - ( G['X'], G[')'], ): [ Production(G['X'], G.Epsilon), ], - ( G['X'], G.EOF, ): [ Production(G['X'], G.Epsilon), ], - ( G['T'], G['symbol'], ): [ Production(G['T'], Sentence(G['F'], G['Y'])), ], - ( G['T'], G['ε'], ): [ Production(G['T'], Sentence(G['F'], G['Y'])), ], - ( G['T'], G['('], ): [ Production(G['T'], Sentence(G['F'], G['Y'])), ], - ( G['Y'], G['symbol'], ): [ Production(G['Y'], Sentence(G['T'])), ], - ( G['Y'], G['ε'], ): [ Production(G['Y'], Sentence(G['T'])), ], - ( G['Y'], G['('], ): [ Production(G['Y'], Sentence(G['T'])), ], - ( G['Y'], G[')'], ): [ Production(G['Y'], G.Epsilon), ], - ( G['Y'], G.EOF, ): [ Production(G['Y'], G.Epsilon), ], - ( G['Y'], G['|'], ): [ Production(G['Y'], G.Epsilon), ], - ( G['F'], G['symbol'], ): [ Production(G['F'], Sentence(G['A'], G['Z'])), ], - ( G['F'], G['ε'], ): [ Production(G['F'], Sentence(G['A'], G['Z'])), ], - ( G['F'], G['('], ): [ Production(G['F'], Sentence(G['A'], G['Z'])), ], - ( G['Z'], G['*'], ): [ Production(G['Z'], Sentence(G['*'])), ], - ( G['Z'], G.EOF, ): [ Production(G['Z'], G.Epsilon), ], - ( G['Z'], G['|'], ): [ Production(G['Z'], G.Epsilon), ], - ( G['Z'], G['('], ): [ Production(G['Z'], G.Epsilon), ], - ( G['Z'], G[')'], ): [ Production(G['Z'], G.Epsilon), ], - ( G['Z'], G['symbol'], ): [ Production(G['Z'], G.Epsilon), ], - ( G['Z'], G['ε'], ): [ Production(G['Z'], G.Epsilon), ], - ( G['A'], G['symbol'], ): [ Production(G['A'], Sentence(G['symbol'])), ], - ( G['A'], G['ε'], ): [ Production(G['A'], Sentence(G['ε'])), ], - ( G['A'], G['('], ): [ Production(G['A'], Sentence(G['('], G['E'], G[')'])), ] - } - - @property - def parser(self): - firsts = self.firsts - follows = self.follows - M = build_parsing_table(self.G, firsts, follows) - parser = metodo_predictivo_no_recursivo(self.G, M) - return parser \ No newline at end of file diff --git a/cmp/nbpackage.py b/cmp/nbpackage.py deleted file mode 100755 index e89c62ad3..000000000 --- a/cmp/nbpackage.py +++ /dev/null @@ -1,87 +0,0 @@ -import io, os, sys, types - -from IPython import get_ipython -from nbformat import read -from IPython.core.interactiveshell import InteractiveShell - -def find_notebook(fullname, path=None): - """find a notebook, given its fully qualified name and an optional path - - This turns "foo.bar" into "foo/bar.ipynb" - and tries turning "Foo_Bar" into "Foo Bar" if Foo_Bar - does not exist. - """ - name = fullname.rsplit('.', 1)[-1] - if not path: - path = [''] - for d in path: - nb_path = os.path.join(d, name + ".ipynb") - if os.path.isfile(nb_path): - return nb_path - # let import Notebook_Name find "Notebook Name.ipynb" - nb_path = nb_path.replace("_", " ") - if os.path.isfile(nb_path): - return nb_path - -class NotebookLoader(object): - """Module Loader for Jupyter Notebooks""" - def __init__(self, path=None): - self.shell = InteractiveShell.instance() - self.path = path - - def load_module(self, fullname): - """import a notebook as a module""" - path = find_notebook(fullname, self.path) - - print ("importing Jupyter notebook from %s" % path) - - # load the notebook object - with io.open(path, 'r', encoding='utf-8') as f: - nb = read(f, 4) - - - # create the module and add it to sys.modules - # if name in sys.modules: - # return sys.modules[name] - mod = types.ModuleType(fullname) - mod.__file__ = path - mod.__loader__ = self - mod.__dict__['get_ipython'] = get_ipython - sys.modules[fullname] = mod - - # extra work to ensure that magics that would affect the user_ns - # actually affect the notebook module's ns - save_user_ns = self.shell.user_ns - self.shell.user_ns = mod.__dict__ - - try: - for cell in nb.cells: - if cell.cell_type == 'code': - # transform the input to executable Python - code = self.shell.input_transformer_manager.transform_cell(cell.source) - # run the code in themodule - exec(code, mod.__dict__) - finally: - self.shell.user_ns = save_user_ns - return mod - -class NotebookFinder(object): - """Module finder that locates Jupyter Notebooks""" - def __init__(self): - self.loaders = {} - - def find_module(self, fullname, path=None): - nb_path = find_notebook(fullname, path) - if not nb_path: - return - - key = path - if path: - # lists aren't hashable - key = os.path.sep.join(path) - - if key not in self.loaders: - self.loaders[key] = NotebookLoader(path) - return self.loaders[key] - -sys.meta_path.append(NotebookFinder()) \ No newline at end of file diff --git a/cmp/pycompiler.py b/cmp/pycompiler.py deleted file mode 100755 index 3ef02deeb..000000000 --- a/cmp/pycompiler.py +++ /dev/null @@ -1,512 +0,0 @@ -import json - -class Symbol(object): - - def __init__(self, name, grammar): - self.Name = name - self.Grammar = grammar - - def __str__(self): - return self.Name - - def __repr__(self): - return repr(self.Name) - - def __add__(self, other): - if isinstance(other, Symbol): - return Sentence(self, other) - - raise TypeError(other) - - def __or__(self, other): - - if isinstance(other, (Sentence)): - return SentenceList(Sentence(self), other) - - raise TypeError(other) - - @property - def IsEpsilon(self): - return False - - def __len__(self): - return 1 - -class NonTerminal(Symbol): - - - def __init__(self, name, grammar): - super().__init__(name, grammar) - self.productions = [] - - - def __imod__(self, other): - - if isinstance(other, (Sentence)): - p = Production(self, other) - self.Grammar.Add_Production(p) - return self - - if isinstance(other, tuple): - assert len(other) > 1 - - if len(other) == 2: - other += (None,) * len(other[0]) - - assert len(other) == len(other[0]) + 2, "Debe definirse una, y solo una, regla por cada símbolo de la producción" - # assert len(other) == 2, "Tiene que ser una Tupla de 2 elementos (sentence, attribute)" - - if isinstance(other[0], Symbol) or isinstance(other[0], Sentence): - p = AttributeProduction(self, other[0], other[1:]) - else: - raise Exception("") - - self.Grammar.Add_Production(p) - return self - - if isinstance(other, Symbol): - p = Production(self, Sentence(other)) - self.Grammar.Add_Production(p) - return self - - if isinstance(other, SentenceList): - - for s in other: - p = Production(self, s) - self.Grammar.Add_Production(p) - - return self - - raise TypeError(other) - - @property - def IsTerminal(self): - return False - - @property - def IsNonTerminal(self): - return True - - @property - def IsEpsilon(self): - return False - -class Terminal(Symbol): - - def __init__(self, name, grammar): - super().__init__(name, grammar) - - @property - def IsTerminal(self): - return True - - @property - def IsNonTerminal(self): - return False - - @property - def IsEpsilon(self): - return False - -class EOF(Terminal): - - def __init__(self, Grammar): - super().__init__('$', Grammar) - -class Sentence(object): - - def __init__(self, *args): - self._symbols = tuple(x for x in args if not x.IsEpsilon) - self.hash = hash(self._symbols) - - def __len__(self): - return len(self._symbols) - - def __add__(self, other): - if isinstance(other, Symbol): - return Sentence(*(self._symbols + (other,))) - - if isinstance(other, Sentence): - return Sentence(*(self._symbols + other._symbols)) - - raise TypeError(other) - - def __or__(self, other): - if isinstance(other, Sentence): - return SentenceList(self, other) - - if isinstance(other, Symbol): - return SentenceList(self, Sentence(other)) - - raise TypeError(other) - - def __repr__(self): - return str(self) - - def __str__(self): - return ("%s " * len(self._symbols) % tuple(self._symbols)).strip() - - def __iter__(self): - return iter(self._symbols) - - def __getitem__(self, index): - return self._symbols[index] - - def __eq__(self, other): - return self._symbols == other._symbols - - def __hash__(self): - return self.hash - - @property - def IsEpsilon(self): - return False - -class SentenceList(object): - - def __init__(self, *args): - self._sentences = list(args) - - def Add(self, symbol): - if not symbol and (symbol is None or not symbol.IsEpsilon): - raise ValueError(symbol) - - self._sentences.append(symbol) - - def __iter__(self): - return iter(self._sentences) - - def __or__(self, other): - if isinstance(other, Sentence): - self.Add(other) - return self - - if isinstance(other, Symbol): - return self | Sentence(other) - - -class Epsilon(Terminal, Sentence): - - def __init__(self, grammar): - super().__init__('epsilon', grammar) - - - def __str__(self): - return "e" - - def __repr__(self): - return 'epsilon' - - def __iter__(self): - yield from () - - def __len__(self): - return 0 - - def __add__(self, other): - return other - - def __eq__(self, other): - return isinstance(other, (Epsilon,)) - - def __hash__(self): - return hash("") - - @property - def IsEpsilon(self): - return True - -class Production(object): - - def __init__(self, nonTerminal, sentence): - - self.Left = nonTerminal - self.Right = sentence - - def __str__(self): - - return '%s := %s' % (self.Left, self.Right) - - def __repr__(self): - return '%s -> %s' % (self.Left, self.Right) - - def __iter__(self): - yield self.Left - yield self.Right - - def __eq__(self, other): - return isinstance(other, Production) and self.Left == other.Left and self.Right == other.Right - - def __hash__(self): - return hash((self.Left, self.Right)) - - @property - def IsEpsilon(self): - return self.Right.IsEpsilon - -class AttributeProduction(Production): - - def __init__(self, nonTerminal, sentence, attributes): - if not isinstance(sentence, Sentence) and isinstance(sentence, Symbol): - sentence = Sentence(sentence) - super(AttributeProduction, self).__init__(nonTerminal, sentence) - - self.attributes = attributes - - def __str__(self): - return '%s := %s' % (self.Left, self.Right) - - def __repr__(self): - return '%s -> %s' % (self.Left, self.Right) - - def __iter__(self): - yield self.Left - yield self.Right - - - @property - def IsEpsilon(self): - return self.Right.IsEpsilon - - # sintetizar en ingles??????, pending aggrement - def syntetice(self): - pass - -class Grammar(): - - def __init__(self): - - self.Productions = [] - self.nonTerminals = [] - self.terminals = [] - self.startSymbol = None - # production type - self.pType = None - self.Epsilon = Epsilon(self) - self.EOF = EOF(self) - - self.symbDict = { '$': self.EOF } - - def NonTerminal(self, name, startSymbol = False): - - name = name.strip() - if not name: - raise Exception("Empty name") - - term = NonTerminal(name,self) - - if startSymbol: - - if self.startSymbol is None: - self.startSymbol = term - else: - raise Exception("Cannot define more than one start symbol.") - - self.nonTerminals.append(term) - self.symbDict[name] = term - return term - - def NonTerminals(self, names): - - ans = tuple((self.NonTerminal(x) for x in names.strip().split())) - - return ans - - - def Add_Production(self, production): - - if len(self.Productions) == 0: - self.pType = type(production) - - assert type(production) == self.pType, "The Productions most be of only 1 type." - - production.Left.productions.append(production) - self.Productions.append(production) - - - def Terminal(self, name): - - name = name.strip() - if not name: - raise Exception("Empty name") - - term = Terminal(name, self) - self.terminals.append(term) - self.symbDict[name] = term - return term - - def Terminals(self, names): - - ans = tuple((self.Terminal(x) for x in names.strip().split())) - - return ans - - - def __str__(self): - - mul = '%s, ' - - ans = 'Non-Terminals:\n\t' - - nonterminals = mul * (len(self.nonTerminals)-1) + '%s\n' - - ans += nonterminals % tuple(self.nonTerminals) - - ans += 'Terminals:\n\t' - - terminals = mul * (len(self.terminals)-1) + '%s\n' - - ans += terminals % tuple(self.terminals) - - ans += 'Productions:\n\t' - - ans += str(self.Productions) - - return ans - - def __getitem__(self, name): - try: - return self.symbDict[name] - except KeyError: - return None - - @property - def to_json(self): - - productions = [] - - for p in self.Productions: - head = p.Left.Name - - body = [] - - for s in p.Right: - body.append(s.Name) - - productions.append({'Head':head, 'Body':body}) - - d={'NonTerminals':[symb.Name for symb in self.nonTerminals], 'Terminals': [symb.Name for symb in self.terminals],\ - 'Productions':productions} - - # [{'Head':p.Left.Name, "Body": [s.Name for s in p.Right]} for p in self.Productions] - return json.dumps(d) - - @staticmethod - def from_json(data): - data = json.loads(data) - - G = Grammar() - dic = {'epsilon':G.Epsilon} - - for term in data['Terminals']: - dic[term] = G.Terminal(term) - - for noTerm in data['NonTerminals']: - dic[noTerm] = G.NonTerminal(noTerm) - - for p in data['Productions']: - head = p['Head'] - dic[head] %= Sentence(*[dic[term] for term in p['Body']]) - - return G - - def copy(self): - G = Grammar() - G.Productions = self.Productions.copy() - G.nonTerminals = self.nonTerminals.copy() - G.terminals = self.terminals.copy() - G.pType = self.pType - G.startSymbol = self.startSymbol - G.Epsilon = self.Epsilon - G.EOF = self.EOF - G.symbDict = self.symbDict.copy() - - return G - - @property - def IsAugmentedGrammar(self): - augmented = 0 - for left, right in self.Productions: - if self.startSymbol == left: - augmented += 1 - if augmented <= 1: - return True - else: - return False - - def AugmentedGrammar(self, force=False): - if not self.IsAugmentedGrammar or force: - - G = self.copy() - # S, self.startSymbol, SS = self.startSymbol, None, self.NonTerminal('S\'', True) - S = G.startSymbol - G.startSymbol = None - SS = G.NonTerminal('S\'', True) - if G.pType is AttributeProduction: - SS %= S + G.Epsilon, lambda x : x - else: - SS %= S + G.Epsilon - - return G - else: - return self.copy() - #endchange - -class Item: - - def __init__(self, production, pos, lookaheads=[]): - self.production = production - self.pos = pos - self.lookaheads = frozenset(look for look in lookaheads) - - def __str__(self): - s = str(self.production.Left) + " -> " - if len(self.production.Right) > 0: - for i,c in enumerate(self.production.Right): - if i == self.pos: - s += "." - s += str(self.production.Right[i]) - if self.pos == len(self.production.Right): - s += "." - else: - s += "." - s += ", " + str(self.lookaheads)[10:-1] - return s - - def __repr__(self): - return str(self) - - - def __eq__(self, other): - return ( - (self.pos == other.pos) and - (self.production == other.production) and - (set(self.lookaheads) == set(other.lookaheads)) - ) - - def __hash__(self): - return hash((self.production,self.pos,self.lookaheads)) - - @property - def IsReduceItem(self): - return len(self.production.Right) == self.pos - - @property - def NextSymbol(self): - if self.pos < len(self.production.Right): - return self.production.Right[self.pos] - else: - return None - - def NextItem(self): - if self.pos < len(self.production.Right): - return Item(self.production,self.pos+1,self.lookaheads) - else: - return None - - def Preview(self, skip=1): - unseen = self.production.Right[self.pos+skip:] - return [ unseen + (lookahead,) for lookahead in self.lookaheads ] - - def Center(self): - return Item(self.production, self.pos) \ No newline at end of file diff --git a/cmp/semantic.py b/cmp/semantic.py deleted file mode 100755 index 9279bda3c..000000000 --- a/cmp/semantic.py +++ /dev/null @@ -1,214 +0,0 @@ -import itertools as itt -from collections import OrderedDict - - -class SemanticError(Exception): - @property - def text(self): - return self.args[0] - -class Attribute: - def __init__(self, name, typex): - self.name = name - self.type = typex - - def __str__(self): - return f'[attrib] {self.name} : {self.type.name};' - - def __repr__(self): - return str(self) - -class Method: - def __init__(self, name, param_names, params_types, return_type): - self.name = name - self.param_names = param_names - self.param_types = params_types - self.return_type = return_type - - def __str__(self): - params = ', '.join(f'{n}:{t.name}' for n,t in zip(self.param_names, self.param_types)) - return f'[method] {self.name}({params}): {self.return_type.name};' - - def __eq__(self, other): - return other.name == self.name and \ - other.return_type == self.return_type and \ - other.param_types == self.param_types - -class Type: - def __init__(self, name:str): - self.name = name - self.attributes = [] - self.methods = [] - self.parent = None - - def set_parent(self, parent): - if self.parent is not None: - raise SemanticError(f'Parent type is already set for {self.name}.') - self.parent = parent - - def get_attribute(self, name:str): - try: - return next(attr for attr in self.attributes if attr.name == name) - except StopIteration: - if self.parent is None: - raise SemanticError(f'Attribute "{name}" is not defined in {self.name}.') - try: - return self.parent.get_attribute(name) - except SemanticError: - raise SemanticError(f'Attribute "{name}" is not defined in {self.name}.') - - def define_attribute(self, name:str, typex): - try: - self.get_attribute(name) - except SemanticError: - attribute = Attribute(name, typex) - self.attributes.append(attribute) - return attribute - else: - raise SemanticError(f'Attribute "{name}" is already defined in {self.name}.') - - def get_method(self, name:str): - try: - return next(method for method in self.methods if method.name == name) - except StopIteration: - if self.parent is None: - raise SemanticError(f'Method "{name}" is not defined in {self.name}.') - try: - return self.parent.get_method(name) - except SemanticError: - raise SemanticError(f'Method "{name}" is not defined in {self.name}.') - - def define_method(self, name:str, param_names:list, param_types:list, return_type): - if name in (method.name for method in self.methods): - raise SemanticError(f'Method "{name}" already defined in {self.name}') - - method = Method(name, param_names, param_types, return_type) - self.methods.append(method) - return method - - def all_attributes(self, clean=True): - plain = OrderedDict() if self.parent is None else self.parent.all_attributes(False) - for attr in self.attributes: - plain[attr.name] = (attr, self) - return plain.values() if clean else plain - - def all_methods(self, clean=True): - plain = OrderedDict() if self.parent is None else self.parent.all_methods(False) - for method in self.methods: - plain[method.name] = (method, self) - return plain.values() if clean else plain - - def conforms_to(self, other): - return other.bypass() or self == other or self.parent is not None and self.parent.conforms_to(other) - - def bypass(self): - return False - - def __str__(self): - output = f'type {self.name}' - parent = '' if self.parent is None else f' : {self.parent.name}' - output += parent - output += ' {' - output += '\n\t' if self.attributes or self.methods else '' - output += '\n\t'.join(str(x) for x in self.attributes) - output += '\n\t' if self.attributes else '' - output += '\n\t'.join(str(x) for x in self.methods) - output += '\n' if self.methods else '' - output += '}\n' - return output - - def __repr__(self): - return str(self) - -class ErrorType(Type): - def __init__(self): - Type.__init__(self, '') - - def conforms_to(self, other): - return True - - def bypass(self): - return True - - def __eq__(self, other): - return isinstance(other, Type) - -class VoidType(Type): - def __init__(self): - Type.__init__(self, '') - - def conforms_to(self, other): - raise Exception('Invalid type: void type.') - - def bypass(self): - return True - - def __eq__(self, other): - return isinstance(other, VoidType) - -class IntType(Type): - def __init__(self): - Type.__init__(self, 'int') - - def __eq__(self, other): - return other.name == self.name or isinstance(other, IntType) - -class Context: - def __init__(self): - self.types = {} - - def create_type(self, name:str): - if name in self.types: - raise SemanticError(f'Type with the same name ({name}) already in context.') - typex = self.types[name] = Type(name) - return typex - - def get_type(self, name:str): - try: - return self.types[name] - except KeyError: - raise SemanticError(f'Type "{name}" is not defined.') - - def __str__(self): - return '{\n\t' + '\n\t'.join(y for x in self.types.values() for y in str(x).split('\n')) + '\n}' - - def __repr__(self): - return str(self) - -class VariableInfo: - def __init__(self, name, vtype): - self.name = name - self.type = vtype - -class Scope: - def __init__(self, parent=None): - self.locals = [] - self.parent = parent - self.children = [] - self.index = 0 if parent is None else len(parent) - - def __len__(self): - return len(self.locals) - - def create_child(self): - child = Scope(self) - self.children.append(child) - return child - - def define_variable(self, vname, vtype): - info = VariableInfo(vname, vtype) - self.locals.append(info) - return info - - def find_variable(self, vname, index=None): - locals = self.locals if index is None else itt.islice(self.locals, index) - try: - return next(x for x in locals if x.name == vname) - except StopIteration: - return self.parent.find_variable(vname, self.index) if self.parent is None else None - - def is_defined(self, vname): - return self.find_variable(vname) is not None - - def is_local(self, vname): - return any(True for x in self.locals if x.name == vname) diff --git a/cmp/utils.py b/cmp/utils.py deleted file mode 100755 index a839ff5ee..000000000 --- a/cmp/utils.py +++ /dev/null @@ -1,219 +0,0 @@ -from cmp.pycompiler import Production, Sentence, Symbol, EOF, Epsilon - -class ContainerSet: - def __init__(self, *values, contains_epsilon=False): - self.set = set(values) - self.contains_epsilon = contains_epsilon - - def add(self, value): - n = len(self.set) - self.set.add(value) - return n != len(self.set) - - def extend(self, values): - change = False - for value in values: - change |= self.add(value) - return change - - def set_epsilon(self, value=True): - last = self.contains_epsilon - self.contains_epsilon = value - return last != self.contains_epsilon - - def update(self, other): - n = len(self.set) - self.set.update(other.set) - return n != len(self.set) - - def epsilon_update(self, other): - return self.set_epsilon(self.contains_epsilon | other.contains_epsilon) - - def hard_update(self, other): - return self.update(other) | self.epsilon_update(other) - - def find_match(self, match): - for item in self.set: - if item == match: - return item - return None - - def __len__(self): - return len(self.set) + int(self.contains_epsilon) - - def __str__(self): - return '%s-%s' % (str(self.set), self.contains_epsilon) - - def __repr__(self): - return str(self) - - def __iter__(self): - return iter(self.set) - - def __nonzero__(self): - return len(self) > 0 - - def __eq__(self, other): - if isinstance(other, set): - return self.set == other - return isinstance(other, ContainerSet) and self.set == other.set and self.contains_epsilon == other.contains_epsilon - - -def inspect(item, grammar_name='G', mapper=None): - try: - return mapper[item] - except (TypeError, KeyError ): - if isinstance(item, dict): - items = ',\n '.join(f'{inspect(key, grammar_name, mapper)}: {inspect(value, grammar_name, mapper)}' for key, value in item.items() ) - return f'{{\n {items} \n}}' - elif isinstance(item, ContainerSet): - args = f'{ ", ".join(inspect(x, grammar_name, mapper) for x in item.set) } ,' if item.set else '' - return f'ContainerSet({args} contains_epsilon={item.contains_epsilon})' - elif isinstance(item, EOF): - return f'{grammar_name}.EOF' - elif isinstance(item, Epsilon): - return f'{grammar_name}.Epsilon' - elif isinstance(item, Symbol): - return f"G['{item.Name}']" - elif isinstance(item, Sentence): - items = ', '.join(inspect(s, grammar_name, mapper) for s in item._symbols) - return f'Sentence({items})' - elif isinstance(item, Production): - left = inspect(item.Left, grammar_name, mapper) - right = inspect(item.Right, grammar_name, mapper) - return f'Production({left}, {right})' - elif isinstance(item, tuple) or isinstance(item, list): - ctor = ('(', ')') if isinstance(item, tuple) else ('[',']') - return f'{ctor[0]} {("%s, " * len(item)) % tuple(inspect(x, grammar_name, mapper) for x in item)}{ctor[1]}' - else: - raise ValueError(f'Invalid: {item}') - -def pprint(item, header=""): - if header: - print(header) - - if isinstance(item, dict): - for key, value in item.items(): - print(f'{key} ---> {value}') - elif isinstance(item, list): - print('[') - for x in item: - print(f' {repr(x)}') - print(']') - else: - print(item) - -class Token: - """ - Basic token class. - - Parameters - ---------- - lex : str - Token's lexeme. - token_type : Enum - Token's type. - """ - - def __init__(self, lex, token_type): - self.lex = lex - self.token_type = token_type - - def __str__(self): - return f'{self.token_type}: {self.lex}' - - def __repr__(self): - return str(self) - - @property - def is_valid(self): - return True - -class UnknownToken(Token): - def __init__(self, lex): - Token.__init__(self, lex, None) - - def transform_to(self, token_type): - return Token(self.lex, token_type) - - @property - def is_valid(self): - return False - -def tokenizer(G, fixed_tokens): - def decorate(func): - def tokenize_text(text): - tokens = [] - for lex in text.split(): - try: - token = fixed_tokens[lex] - except KeyError: - token = UnknownToken(lex) - try: - token = func(token) - except TypeError: - pass - tokens.append(token) - tokens.append(Token('$', G.EOF)) - return tokens - - if hasattr(func, '__call__'): - return tokenize_text - elif isinstance(func, str): - return tokenize_text(func) - else: - raise TypeError('Argument must be "str" or a callable object.') - return decorate - -class DisjointSet: - def __init__(self, *items): - self.nodes = { x: DisjointNode(x) for x in items } - - def merge(self, items): - items = (self.nodes[x] for x in items) - try: - head, *others = items - for other in others: - head.merge(other) - except ValueError: - pass - - @property - def representatives(self): - return { n.representative for n in self.nodes.values() } - - @property - def groups(self): - return [[n for n in self.nodes.values() if n.representative == r] for r in self.representatives] - - def __len__(self): - return len(self.representatives) - - def __getitem__(self, item): - return self.nodes[item] - - def __str__(self): - return str(self.groups) - - def __repr__(self): - return str(self) - -class DisjointNode: - def __init__(self, value): - self.value = value - self.parent = self - - @property - def representative(self): - if self.parent != self: - self.parent = self.parent.representative - return self.parent - - def merge(self, other): - other.representative.parent = self.representative - - def __str__(self): - return str(self.value) - - def __repr__(self): - return str(self) \ No newline at end of file diff --git a/cmp/visitor.py b/cmp/visitor.py deleted file mode 100755 index 964842836..000000000 --- a/cmp/visitor.py +++ /dev/null @@ -1,80 +0,0 @@ -# The MIT License (MIT) -# -# Copyright (c) 2013 Curtis Schlak -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -import inspect - -__all__ = ['on', 'when'] - -def on(param_name): - def f(fn): - dispatcher = Dispatcher(param_name, fn) - return dispatcher - return f - - -def when(param_type): - def f(fn): - frame = inspect.currentframe().f_back - func_name = fn.func_name if 'func_name' in dir(fn) else fn.__name__ - dispatcher = frame.f_locals[func_name] - if not isinstance(dispatcher, Dispatcher): - dispatcher = dispatcher.dispatcher - dispatcher.add_target(param_type, fn) - def ff(*args, **kw): - return dispatcher(*args, **kw) - ff.dispatcher = dispatcher - return ff - return f - - -class Dispatcher(object): - def __init__(self, param_name, fn): - frame = inspect.currentframe().f_back.f_back - top_level = frame.f_locals == frame.f_globals - self.param_index = self.__argspec(fn).args.index(param_name) - self.param_name = param_name - self.targets = {} - - def __call__(self, *args, **kw): - typ = args[self.param_index].__class__ - d = self.targets.get(typ) - if d is not None: - return d(*args, **kw) - else: - issub = issubclass - t = self.targets - ks = t.keys() - ans = [t[k](*args, **kw) for k in ks if issub(typ, k)] - if len(ans) == 1: - return ans.pop() - return ans - - def add_target(self, typ, target): - self.targets[typ] = target - - @staticmethod - def __argspec(fn): - # Support for Python 3 type hints requires inspect.getfullargspec - if hasattr(inspect, 'getfullargspec'): - return inspect.getfullargspec(fn) - else: - return inspect.getargspec(fn) diff --git a/cool_grammar.py b/cool_grammar.py deleted file mode 100644 index 8dbfae440..000000000 --- a/cool_grammar.py +++ /dev/null @@ -1,184 +0,0 @@ -from cmp.pycompiler import Grammar -from ast_nodes import ( - ProgramNode, - ClassDeclarationNode, - FuncDeclarationNode, - AttrDeclarationNode, - IfNode, - WhileNode, - LetNode, - CaseNode, - IsvoidNode, - AssignNode, - VarDeclarationNode, - CaseItemNode, - NotNode, - LessNode, - LessEqualNode, - EqualNode, - PlusNode, - MinusNode, - StarNode, - DivNode, - NegNode, - InstantiateNode, - BlockNode, - CallNode, - ConstantNumNode, - VariableNode, - BooleanFalseNode, - BooleanTrueNode, - StringNode, -) - - -def define_cool_grammar(print_grammar=False): - # grammar - G = Grammar() - - # non-terminals - program = G.NonTerminal("", startSymbol=True) - class_list, def_class = G.NonTerminals(" ") - feature_list, def_attr, def_func = G.NonTerminals( - " " - ) - param_list, param = G.NonTerminals(" ") - expr, comp, arith, term, factor, element, atom = G.NonTerminals( - " " - ) - identifiers_list, identifier_init = G.NonTerminals(" ") - block, case_block, case_item = G.NonTerminals(" ") - func_call, arg_list = G.NonTerminals(" ") - - # terminals - classx, inherits, notx, isvoid = G.Terminals("class inherits not isvoid") - let, inx = G.Terminals("let in") - ifx, then, elsex, fi = G.Terminals("if then else fi") - whilex, loop, pool = G.Terminals("while loop pool") - case, of, esac = G.Terminals("case of esac") - semi, colon, comma, dot, opar, cpar, ocur, ccur, at, larrow, rarrow = G.Terminals( - "; : , . ( ) { } @ <- =>" - ) - equal, plus, minus, star, div, less, equal, lesseq, neg = G.Terminals( - "= + - * / < = <= ~" - ) - idx, num, new, string, true, false = G.Terminals("id int new string true false") - - # productions - program %= class_list, lambda h, s: ProgramNode(s[1]) - - class_list %= def_class + class_list, lambda h, s: [s[1]] + s[2] - class_list %= def_class, lambda h, s: [s[1]] - - def_class %= ( - classx + idx + ocur + feature_list + ccur + semi, - lambda h, s: ClassDeclarationNode(s[2], s[4]), - ) - def_class %= ( - classx + idx + inherits + idx + ocur + feature_list + ccur + semi, - lambda h, s: ClassDeclarationNode(s[2], s[6], s[4]), - ) - - feature_list %= def_attr + semi + feature_list, lambda h, s: [s[1]] + s[3] - feature_list %= def_func + semi + feature_list, lambda h, s: [s[1]] + s[3] - feature_list %= G.Epsilon, lambda h, s: [] - - def_attr %= ( - idx + colon + idx + larrow + expr, - lambda h, s: AttrDeclarationNode(s[1], s[3], s[5]), - ) - def_attr %= idx + colon + idx, lambda h, s: AttrDeclarationNode(s[1], s[3]) - - def_func %= ( - idx + opar + param_list + cpar + colon + idx + ocur + expr + ccur, - lambda h, s: FuncDeclarationNode(s[1], s[3], s[6], s[8]), - ) - - param_list %= param + comma + param_list, lambda h, s: [s[1]] + s[3] - param_list %= param, lambda h, s: [s[1]] - param_list %= G.Epsilon, lambda h, s: [] - - param %= idx + colon + idx, lambda h, s: (s[1], s[3]) - - expr %= idx + larrow + expr, lambda h, s: AssignNode(s[1], s[3]) - expr %= let + identifiers_list + inx + expr, lambda h, s: LetNode(s[2], s[4]) - expr %= ( - ifx + expr + then + expr + elsex + expr + fi, - lambda h, s: IfNode(s[2], s[4], s[6]), - ) - expr %= whilex + expr + loop + expr + pool, lambda h, s: WhileNode(s[2], s[4]) - expr %= case + expr + of + case_block + esac, lambda h, s: CaseNode(s[2], s[4]) - expr %= notx + expr, lambda h, s: NotNode(s[2]) - expr %= comp, lambda h, s: s[1] - - identifiers_list %= ( - identifier_init + comma + identifiers_list, - lambda h, s: [s[1]] + s[3], - ) - identifiers_list %= identifier_init, lambda h, s: [s[1]] - - identifier_init %= ( - idx + colon + idx + larrow + expr, - lambda h, s: VarDeclarationNode(s[1], s[3], s[5]), - ) - identifier_init %= idx + colon + idx, lambda h, s: VarDeclarationNode(s[1], s[3]) - - case_block %= case_item + case_block, lambda h, s: [s[1]] + s[2] - case_block %= case_item, lambda h, s: [s[1]] - case_item %= ( - idx + colon + idx + rarrow + expr + semi, - lambda h, s: CaseItemNode(s[1], s[3], s[5]), - ) - - comp %= comp + less + arith, lambda h, s: LessNode(s[1], s[3]) - comp %= comp + equal + arith, lambda h, s: EqualNode(s[1], s[3]) - comp %= comp + lesseq + arith, lambda h, s: LessEqualNode(s[1], s[3]) - comp %= arith, lambda h, s: s[1] - - arith %= arith + plus + term, lambda h, s: PlusNode(s[1], s[3]) - arith %= arith + minus + term, lambda h, s: MinusNode(s[1], s[3]) - arith %= term, lambda h, s: s[1] - - term %= term + star + factor, lambda h, s: StarNode(s[1], s[3]) - term %= term + div + factor, lambda h, s: DivNode(s[1], s[3]) - term %= factor, lambda h, s: s[1] - - factor %= isvoid + element, lambda h, s: IsvoidNode(s[2]) - factor %= neg + element, lambda h, s: NegNode(s[2]) - factor %= new + idx, lambda h, s: InstantiateNode(s[2]) - factor %= element, lambda h, s: s[1] - - element %= opar + expr + cpar, lambda h, s: s[2] - element %= ocur + block + ccur, lambda h, s: BlockNode(s[2]) - element %= ( - element + dot + func_call, - lambda h, s: CallNode(*s[3], obj=s[1]), - ) - element %= ( - element + at + idx + dot + func_call, - lambda h, s: CallNode(*s[5], obj=s[1], at_type=s[3]), - ) - element %= func_call, lambda h, s: CallNode(*s[3]) - element %= atom, lambda h, s: s[1] - - atom %= num, lambda h, s: ConstantNumNode(s[1]) - atom %= idx, lambda h, s: VariableNode(s[1]) - atom %= ( - true, - lambda h, s: BooleanTrueNode(s[1]), - ) # verificar #include en el tokenizer - atom %= false, lambda h, s: BooleanFalseNode(s[1]) # include en el tokenizer - atom %= string, lambda h, s: StringNode(s[1]) # include en el tokenizer - - block %= expr + semi, lambda h, s: [s[1]] - block %= expr + semi + block, lambda h, s: [s[1]] + s[3] - - func_call %= idx + opar + arg_list + cpar, lambda h, s: (s[1], s[3]) - - arg_list %= expr + comma + arg_list, lambda h, s: [s[1]] + s[3] - arg_list %= expr, lambda h, s: [s[1]] - arg_list %= G.Epsilon, lambda h, s: [] - - if print_grammar: - print(G) - return (G, idx, num) diff --git a/cool_tokenizer.py b/cool_tokenizer.py deleted file mode 100644 index 55ac0195f..000000000 --- a/cool_tokenizer.py +++ /dev/null @@ -1,43 +0,0 @@ -from cmp.utils import Token, tokenizer - - -def tokenize_cool_text(G, text, idx, num, print_tokens=False): - fixed_tokens = { - t.Name: Token(t.Name, t) for t in G.terminals if t not in {idx, num} - } - - @tokenizer(G, fixed_tokens) - def tokenize_text(token): - lex = token.lex - try: - float(lex) - return token.transform_to(num) - except ValueError: # verificar los string - return token.transform_to(idx) - - # (do something like if(lex[0] == " and lex[-1] ==")) - tokens = tokenize_text(text) - if print_tokens: - pprint_tokens(tokens) - return tokens - - -# pie co los lex, arreglar como toca -def pprint_tokens(tokens): - indent = 0 - pending = [] - for token in tokens: - pending.append(token) - if token.lex in {"{", "}", ";"}: - if token.lex == "}": - indent -= 1 - print(" " * indent + " ".join(str(t.token_type) for t in pending)) - pending.clear() - if token.lex == "{": - indent += 1 - print(" ".join([str(t.token_type) for t in pending])) - - -# if __name__ == "__main__": -# pprint_tokens(tokens) - diff --git a/cool_visitor.py b/cool_visitor.py deleted file mode 100644 index aba87398b..000000000 --- a/cool_visitor.py +++ /dev/null @@ -1,161 +0,0 @@ -import cmp.visitor as visitor -from ast_nodes import ( - ProgramNode, - ClassDeclarationNode, - FuncDeclarationNode, - AttrDeclarationNode, - IfNode, - WhileNode, - LetNode, - CaseNode, - AssignNode, - VarDeclarationNode, - CaseItemNode, - InstantiateNode, - BlockNode, - CallNode, - BinaryNode, - AtomicNode, - UnaryNode, -) - - -class FormatVisitor(object): - @visitor.on("node") - def visit(self, node, tabs): - pass - - @visitor.when(ProgramNode) - def visit(self, node, tabs=0): - ans = "\t" * tabs + f"\\__ProgramNode [ ... ]" - statements = "\n".join( - self.visit(child, tabs + 1) for child in node.declarations - ) - return f"{ans}\n{statements}" - - @visitor.when(ClassDeclarationNode) - def visit(self, node, tabs=0): - parent = "" if node.parent is None else f"inherits {node.parent}" - ans = ( - "\t" * tabs - + f"\\__ClassDeclarationNode: class {node.id} {parent} {{ ... }}" - ) - features = "\n".join(self.visit(child, tabs + 1) for child in node.features) - return f"{ans}\n{features}" - - @visitor.when(AttrDeclarationNode) - def visit(self, node, tabs=0): - ans = "\t" * tabs + f"\\__AttrDeclarationNode: {node.id} : {node.type} <- " - exp = "\t" * (tabs + 1) + "__NONE" - if not node.init_exp is None: - exp = "\n".join(self.visit(node.init_exp, tabs + 1)) - return f"{ans}\n{exp}" - - @visitor.when(VarDeclarationNode) - def visit(self, node, tabs=0): - ans = "\t" * tabs + f"\\__VarDeclarationNode: {node.id} : {node.type} <- " - expr = "\t" * (tabs + 1) + "__NONE" - if not node.expr is None: - expr = self.visit(node.expr, tabs + 1) - return f"{ans}\n{expr}" - - @visitor.when(AssignNode) - def visit(self, node, tabs=0): - ans = "\t" * tabs + f"\\__AssignNode: {node.id} <- " - expr = self.visit(node.expr, tabs + 1) - return f"{ans}\n{expr}" - - @visitor.when(FuncDeclarationNode) - def visit(self, node, tabs=0): - params = ", ".join(":".join(param) for param in node.params) - ans = ( - "\t" * tabs - + f"\\__FuncDeclarationNode: {node.id}({params}) : {node.type} -> " - ) - body = self.visit(node.body, tabs + 1) - return f"{ans}\n{body}" - - @visitor.when(BinaryNode) - def visit(self, node, tabs=0): - ans = "\t" * tabs + f"\\__ {node.__class__.__name__} " - left = self.visit(node.left, tabs + 1) - right = self.visit(node.right, tabs + 1) - return f"{ans}\n{left}\n{right}" - - @visitor.when(AtomicNode) - def visit(self, node, tabs=0): - return "\t" * tabs + f"\\__ {node.__class__.__name__}: {node.lex}" - - @visitor.when(UnaryNode) - def visit(self, node, tabs=0): - class_name = node.__class__.__name__.split("Node")[0] - ans = "\t" * tabs + f"\\__ {node.__class__.__name__}: {class_name} " - expr = self.visit(node.expr, tabs + 1) - return f"{ans}\n{expr}" - - @visitor.when(CallNode) - def visit(self, node, tabs=0): - args = "\n".join(self.visit(arg, tabs + 1) for arg in node.args) - if not node.obj is None: - obj = self.visit(node.obj, tabs + 1) - if not node.at_type is None: - ans = ( - "\t" * tabs - + f"\\__CallNode: @{node.at_type}.{node.id}(, ..., )" - ) - else: - ans = ( - "\t" * tabs + f"\\__CallNode: .{node.id}(, ..., )" - ) - return f"{ans}\n{obj}\n{args}" - else: - ans = "\t" * tabs + f"\\__CallNode: {node.id}(, ..., )" - return f"{ans}\n{args}" - - @visitor.when(InstantiateNode) - def visit(self, node, tabs=0): - return "\t" * tabs + f"\\__ InstantiateNode: new {node.lex}()" - - @visitor.when(BlockNode) - def visit(self, node, tabs=0): - ans = "\t" * tabs + f"\\__BlockNode: {{; ... ;}}" - body = "\n".join(self.visit(child, tabs + 1) for child in node.expresion_list) - return f"{ans}\n{body}" - - @visitor.when(IfNode) - def visit(self, node, tabs=0): - ans = "\t" * tabs + f"\\__IfNode: if then else fi" - if_expr = self.visit(node.if_expr, tabs + 1) - then_expr = self.visit(node.then_expr, tabs + 1) - else_expr = self.visit(node.else_expr, tabs + 1) - return f"{ans}\n{if_expr}\n{then_expr}\n{else_expr}" - - @visitor.when(WhileNode) - def visit(self, node, tabs=0): - ans = "\t" * tabs + f"\\__WhileNode: while loop pool" - condition = self.visit(node.condition, tabs + 1) - body = self.visit(node.body, tabs + 1) - return f"{ans}\n{condition}\n{body}" - - @visitor.when(LetNode) - def visit(self, node, tabs=0): - ans = "\t" * tabs + f"\\__LetNode: let in " - ident_list = "\n".join( - self.visit(child, tabs + 1) for child in node.identifiers - ) - body = self.visit(node.body, tabs + 1) - return f"{ans}\n{ident_list}\n{body}" - - @visitor.when(CaseNode) - def visit(self, node, tabs=0): - ans = "\t" * tabs + f"\\__LetNode: case of esac" - case_block = "\n".join(self.visit(child, tabs + 1) for child in node.case_items) - expr = self.visit(node.expr, tabs + 1) - return f"{ans}\n{expr}\n{case_block}" - - @visitor.when(CaseItemNode) - def visit(self, node, tabs=0): - ans = "\t" * tabs + f"\\__CaseItemNode: {node.id} : {node.type} => ;" - expr = self.visit(node.expr, tabs + 1) - return f"{ans}\n{expr}" - diff --git a/errors.py b/errors.py deleted file mode 100644 index 945bb486b..000000000 --- a/errors.py +++ /dev/null @@ -1,61 +0,0 @@ -class Error(Exception): - "Base class for exceptions" - pass - - -class parsing_table_error(Error): - "raised when T[X,t] possess more than one production" - - def __init__(self, production1, production2, invalid_sentence): - Error.__init__( - self, - f"conflict betweeen {production1} and {production2}, invalid sentence: {invalid_sentence}", - ) - - -class shift_reduce_error(Error): - "raised when goto or action table in shift reduce parsers possess more than one production" - - def __init__(self, action1, action2, grammar, key=None): - if action1[0] == action2[0] == "REDUCE": - conflict = "Reduce-Reduce" - else: - conflict = "Shift-Reduce" - - Error.__init__( - self, - f"When analizing {key}, {conflict} conflict!!! betweeen {action1} and {action2}. Grammar given is not {grammar}", - ) - - -class invalid_sentence_error(Error): - "raised when w is not in G" - - def __init__( - self, - w, - pos, - actual_token, - expected_token=None, - message="", - output=None, - operations=None, - ): - if expected_token != None: - Error.__init__( - self, - f"Invalid sentence {w}. Expected {expected_token} at position {pos} but received {actual_token} instead. {message}", - ) - else: - Error.__init__( - self, - f"Unexpected token {actual_token} at position {pos}. Invalid sentence {w}. {message}. Secuencia de derivaciones: {output}. Operaciones: {operations}", - ) - - -class non_regular_production_error(Error): - def __init__(self, production): - Error.__init__( - self, - f"production {production} most be of the form: A -> a, A -> e or A -> aX", - ) diff --git a/main.py b/main.py deleted file mode 100644 index c47493bb8..000000000 --- a/main.py +++ /dev/null @@ -1,98 +0,0 @@ -from cool_tokenizer import tokenize_cool_text -from cool_grammar import define_cool_grammar -from cool_visitor import FormatVisitor - -from shift_reduce_parsers import LR1Parser, DerivationTree -from errors import parsing_table_error, Error - -from cmp.evaluation import evaluate_reverse_parse - -text = """ -class Cons inherits List { - xcar : Int ; - xcdr : List ; - - isNill ( ) : Bool { - false - } ; - - init ( hd : Int , tl : List ) : Cons { - { - xcar <- hd ; - xcdr <- tl ; - self ; - } - } ; -} ; -""" - -# text = """ -# class Cons inherits List { -# xcar : Int ; -# xcdr : List ; - -# isNill ( ) : Bool { -# false -# } ; -# } ; -# """ - -# text = """ -# class Cons inherits List { -# xcar : Int ; -# xcdr : List ; -# } ; -# """ - - -def run_pipeline(text): - # define grammar - grammar, idx, num = define_cool_grammar() - - # tokenize text - tokens = tokenize_cool_text(grammar, text, idx, num) - - # try: - parser = LR1Parser(grammar) - parse, operations = parser([t.token_type for t in tokens]) - # print("\n".join(repr(x) for x in parse)) - # print(operations) - - ast = evaluate_reverse_parse(parse, operations, tokens) - formatter = FormatVisitor() - tree = formatter.visit(ast) - print(tree) - # derivation_list = parser(text) - # derivation_tree_aut = DerivationTree(derivation_list[0], G) - - # except Error as err: - # print(err) - - -# def run_pipeline_cmp_tools(text): -# # only for testing -# # define grammar -# grammar, idx, num = define_cool_grammar() - -# # tokenizer -# tokens = tokenize_cool_text(grammar, text, idx, num) - -# # lexical an -# from cmp.tools.parsing import LR1Parser - -# parser = LR1Parser(grammar) -# parse, operations = parser([t.token_type for t in tokens], get_shift_reduce=True) -# print("\n".join(repr(x) for x in parse)) -# # print(operations) - -# ast = evaluate_reverse_parse(parse, operations, tokens) - -# formatter = FormatVisitor() -# tree = formatter.visit(ast) -# print(tree) - - -run_pipeline(text) - -# run_pipeline_cmp_tools(text) - diff --git a/methods.py b/methods.py deleted file mode 100644 index 504d50086..000000000 --- a/methods.py +++ /dev/null @@ -1,150 +0,0 @@ -from cmp.pycompiler import ( - Symbol, - NonTerminal, - Terminal, - EOF, - Sentence, - SentenceList, - Epsilon, - Production, - Grammar, -) -from cmp.utils import ContainerSet -from errors import parsing_table_error, invalid_sentence_error -from itertools import islice -from cmp.automata import State - - -# Computes First(alpha), given First(Vt) and First(Vn) -# alpha in (Vt U Vn)* -def compute_local_first(firsts, alpha): - first_alpha = ContainerSet() - - try: - alpha_is_epsilon = alpha.IsEpsilon - except: - alpha_is_epsilon = False - - ################################################### - # alpha == epsilon ? First(alpha) = { epsilon } - ################################################### - if alpha_is_epsilon or len(alpha) == 0: - first_alpha.set_epsilon() - return first_alpha - ################################################### - - ################################################### - # alpha = X1 ... XN - # First(Xi) subconjunto First(alpha) - # epsilon pertenece a First(X1)...First(Xi) ? First(Xi+1) subconjunto de First(X) y First(alpha) - # epsilon pertenece a First(X1)...First(XN) ? epsilon pertence a First(X) y al First(alpha) - ################################################### - if alpha[0].IsTerminal: - first_alpha.add(alpha[0]) - return first_alpha - - # if alpha[0].IsNonTerminal: - # first_alpha.update(firsts[alpha[0]]) - - for item in alpha: - if firsts[item].contains_epsilon: - first_alpha.update(firsts[item]) - else: - first_alpha.update(firsts[item]) - break - - else: - first_alpha.set_epsilon() - - ################################################### - - # First(alpha) - return first_alpha - - -# Computes First(Vt) U First(Vn) U First(alpha) -# P: X -> alpha -def compute_firsts(G): - firsts = {} - change = True - - # init First(Vt) - for terminal in G.terminals: - firsts[terminal] = ContainerSet(terminal) - - # init First(Vn) - for nonterminal in G.nonTerminals: - firsts[nonterminal] = ContainerSet() - - while change: - change = False - - # P: X -> alpha - for production in G.Productions: - X = production.Left - alpha = production.Right - - # get current First(X) - first_X = firsts[X] - - # init First(alpha) - try: - first_alpha = firsts[alpha] - except: - first_alpha = firsts[alpha] = ContainerSet() - - # CurrentFirst(alpha)??? - local_first = compute_local_first(firsts, alpha) - - # update First(X) and First(alpha) from CurrentFirst(alpha) - change |= first_alpha.hard_update(local_first) - change |= first_X.hard_update(local_first) - - # First(Vt) + First(Vt) + First(RightSides) - return firsts - - -def compute_follows(G, firsts): - follows = {} - change = True - - # local_firsts = {} - - # init Follow(Vn) - for nonterminal in G.nonTerminals: - follows[nonterminal] = ContainerSet() - follows[G.startSymbol] = ContainerSet(G.EOF) - - while change: - change = False - - # P: X -> alpha - for production in G.Productions: - X = production.Left - alpha = production.Right - - follow_X = follows[X] - - ################################################### - # X -> zeta Y beta - # First(beta) - { epsilon } subset of Follow(Y) - # beta ->* epsilon or X -> zeta Y ? Follow(X) subset of Follow(Y) - ################################################### - - for i in range(0, len(alpha) - 1): - if alpha[i].IsNonTerminal: - beta = Sentence(*alpha[i + 1 :]) - firsts_beta = compute_local_first(firsts, beta) - change |= follows[alpha[i]].update(firsts_beta) - - if firsts_beta.contains_epsilon: - change |= follows[alpha[i]].update(follow_X) - - if not alpha.IsEpsilon and alpha[-1].IsNonTerminal: - change |= follows[alpha[-1]].update(follow_X) - - ################################################### - - # Follow(Vn) - return follows - diff --git a/notes.txt b/notes.txt deleted file mode 100644 index 0b5838984..000000000 --- a/notes.txt +++ /dev/null @@ -1,3 +0,0 @@ -Por perfeccionar: --Que el tokenizer reconozca los string( Empiezan y terminan en comillas"), --Ignorar comentarios \ No newline at end of file diff --git a/parser_automatons.py b/parser_automatons.py deleted file mode 100644 index 9a84b7395..000000000 --- a/parser_automatons.py +++ /dev/null @@ -1,225 +0,0 @@ -from cmp.pycompiler import Item -from cmp.automata import State, lr0_formatter, multiline_formatter -from cmp.utils import ContainerSet -from methods import compute_firsts, compute_local_first, compute_follows - -# LR0 automaton -> for SLR and LALR parsers -def build_LR0_automaton(G): - assert len(G.startSymbol.productions) == 1, "Grammar must be augmented" - - start_production = G.startSymbol.productions[0] - start_item = Item(start_production, 0) - - automaton = State(start_item, True) - - pending = [start_item] - visited = {start_item: automaton} - - while pending: - current_item = pending.pop() - if current_item.IsReduceItem: - continue - - # (Decide which transitions to add) - # agregar las epsilon transiciones - # a estados donde el item posee producciones a partir del simbolo actual en la posicion 0 - # y agregar la transicion a partir del simbolo siguiente - - next_item = current_item.NextItem() - try: - next_state = visited[next_item] - except KeyError: - next_state = State(next_item, True) - visited[next_item] = next_state - pending.append(next_item) - - if current_item.NextSymbol.IsNonTerminal: - epsilon_productions = current_item.NextSymbol.productions - else: - epsilon_productions = None - - current_state = visited[current_item] - # (Adding the decided transitions) - current_state.add_transition(current_item.NextSymbol.Name, next_state) - - if epsilon_productions: - for eproduction in epsilon_productions: - epItem = Item(eproduction, 0) - try: - epState = visited[epItem] - except KeyError: - epState = State(epItem, True) - visited[epItem] = epState - pending.append(epItem) - current_state.add_epsilon_transition(epState) - - return automaton - - -# LR1 automaton -def expand(item, firsts): - next_symbol = item.NextSymbol - if next_symbol is None or not next_symbol.IsNonTerminal: - return [] - - lookaheads = ContainerSet() - # (Compute lookahead for child items) - previews = item.Preview() - for preview in previews: - lookaheads.update(compute_local_first(firsts, preview)) - - assert not lookaheads.contains_epsilon - # (Build and return child items) - items = [] - for production in next_symbol.productions: - items.append(Item(production, 0, lookaheads)) - - return items - - -def compress(items): - centers = {} - - for item in items: - center = item.Center() - try: - lookaheads = centers[center] - except KeyError: - centers[center] = lookaheads = set() - lookaheads.update(item.lookaheads) - - return { - Item(x.production, x.pos, set(lookahead)) for x, lookahead in centers.items() - } - - -def closure_lr1(items, firsts): - closure = ContainerSet(*items) - - changed = True - while changed: - changed = False - - new_items = ContainerSet() - # Your code here!!! - for item in closure: - new_items.extend(expand(item, firsts)) - - changed = closure.update(new_items) - - return compress(closure) - - -def goto_lr1(items, symbol, firsts=None, just_kernel=False): - assert ( - just_kernel or firsts is not None - ), "`firsts` must be provided if `just_kernel=False`" - items = frozenset(item.NextItem() for item in items if item.NextSymbol == symbol) - return items if just_kernel else closure_lr1(items, firsts) - - -def build_LR1_automaton(G): - assert len(G.startSymbol.productions) == 1, "Grammar must be augmented" - - firsts = compute_firsts(G) - firsts[G.EOF] = ContainerSet(G.EOF) - - start_production = G.startSymbol.productions[0] - start_item = Item(start_production, 0, lookaheads=(G.EOF,)) - start = frozenset([start_item]) # como cabecera solo queda el kernel - - closure = closure_lr1(start, firsts) - automaton = State( - frozenset(closure), True - ) # en visited si se guarda el estado completo - - pending = [start] - visited = {start: automaton} - - while pending: - current = pending.pop() - current_state = visited[current] - - closure = closure_lr1(current, firsts) - for symbol in G.terminals + G.nonTerminals: - # (Get/Build `next_state`) - # closure = closure_lr1(current,firsts) - goto = goto_lr1(closure, symbol, firsts, True) - - if not goto: - continue - - try: - next_state = visited[goto] - except KeyError: - next_state = visited[goto] = State( - frozenset(closure_lr1(goto, firsts)), True - ) - pending.append(goto) - - current_state.add_transition(symbol.Name, next_state) - - automaton.set_formatter(multiline_formatter) - return automaton - - -def build_LALR_automaton(G): - assert len(G.startSymbol.productions) == 1, "Grammar must be augmented" - - lr1_automaton = build_LR1_automaton(G) - - same_kernel = {} - for node in lr1_automaton: - just_center = frozenset([item.Center() for item in node.state]) - try: - same_kernel[just_center].append(node) - except KeyError: - same_kernel[just_center] = [node] - - start = frozenset( - [item.Center() for item in lr1_automaton.state] - ) # como cabecera solo quedan los items sin lookahead - automaton = State( - lr1_automaton.state, True - ) # en visited se guarda el estado que corresponde a la fusion de estaods ocn el mismo nucleo - - pending = [start] - visited = {start: automaton} - - while pending: - current = pending.pop() - current_state = visited[current] # se van a actualizar - # todos los estados con los que el estado actual tiene alguna transicion - lr1_state = same_kernel[current][0] - - # chequear que cada estado del cjto analizado tenga esa transicion - for symbol in G.terminals + G.nonTerminals: - if lr1_state.has_transition(symbol.Name): - state = lr1_state.transitions[symbol.Name][0] - center_items = frozenset([item.Center() for item in state.state]) - try: - next_state = visited[center_items] - except KeyError: - kernel_set = same_kernel[center_items] - items_with_lookahead = {} - for node in kernel_set: - for item in node.state: - try: - current_item = items_with_lookahead[item.Center()] - except KeyError: - current_item = items_with_lookahead[ - item.Center() - ] = set() - current_item.update(item.lookaheads) - completed_items = [ - Item(item.production, item.pos, lookaheads) - for item, lookaheads in items_with_lookahead.items() - ] - next_state = State(frozenset(completed_items), True) - visited[center_items] = next_state - pending.append(center_items) - - current_state.add_transition(symbol.Name, next_state) - - automaton.set_formatter(multiline_formatter) - return automaton diff --git a/shift_reduce_parsers.py b/shift_reduce_parsers.py deleted file mode 100644 index 7440d6104..000000000 --- a/shift_reduce_parsers.py +++ /dev/null @@ -1,273 +0,0 @@ -from parser_automatons import ( - build_LR0_automaton, - build_LR1_automaton, - build_LALR_automaton, -) -from methods import compute_firsts, compute_local_first, compute_follows -from cmp.automata import State -from errors import shift_reduce_error, invalid_sentence_error - - -class ShiftReduceParser: - SHIFT = "SHIFT" - REDUCE = "REDUCE" - OK = "OK" - - def __init__(self, G, verbose=False): - self.G = G - self.verbose = verbose - self.action = {} - self.goto = {} - self.automaton = self._build_parsing_table() - - def _build_parsing_table(self): - raise NotImplementedError() - - def __call__(self, w): - stack = [0] - cursor = 0 - output = [] - operations = [] - - while True: - state = stack[-1] - lookahead = w[cursor] - if self.verbose: - print(stack, "<---||--->", w[cursor:]) - - # Detect error - try: - action, tag = self.action[state, lookahead] - except KeyError: - raise invalid_sentence_error( - w, - cursor, - lookahead, - None, - "No transition available. Sentence given does not belong to the grammar", - output, - operations, - ) - # Exception( - # "No transition available" - # ) # string does not belong to this grammar - - # Shift case - if action == self.SHIFT: - operations.append(action) - stack.append(tag) - cursor += 1 - - # Reduce case - elif action == self.REDUCE: - operations.append(action) - for _ in range(len(tag.Right)): - stack.pop() - output.append(tag) - stack.append(self.goto[stack[-1], tag.Left]) - - # OK case - elif action == self.OK: - return output, operations - # Invalid case - else: - raise invalid_sentence_error( - w, - cursor, - lookahead, - None, - "Invalid case. Sentence given does not belong to the grammar", - ) - # raise Exception("Invalid case") - # break - - if cursor >= len(w): # or not stack - raise invalid_sentence_error( - w, - cursor - 1, - lookahead, - None, - "Exceed word length while looking for a viable derivation. Sentence given does not belong to the grammar", - ) - # raise Exception("Invalid sentence") - - -class SLR1Parser(ShiftReduceParser): - def _build_parsing_table(self): - G = self.G.AugmentedGrammar(True) - firsts = compute_firsts(G) - follows = compute_follows(G, firsts) - - automaton = build_LR0_automaton(G).to_deterministic() - for i, node in enumerate(automaton): - if self.verbose: - print(i, "\t", "\n\t ".join(str(x) for x in node.state), "\n") - node.idx = i - - for node in automaton: - idx = node.idx - for state in node.state: - item = state.state - # - Filling `self.Action` and `self.Goto` according to `item`) - # - Using `self._register(...)`) - if item.IsReduceItem: - if item.production.Left == G.startSymbol: - self._register(self.action, (idx, G.EOF), (self.OK, None)) - else: - for symbol in follows[item.production.Left]: - self._register( - self.action, - (idx, symbol), - (self.REDUCE, item.production), - ) - else: - if item.NextSymbol.IsTerminal: - self._register( - self.action, - (idx, item.NextSymbol), - (self.SHIFT, node[item.NextSymbol.Name][0].idx), - ) - else: - self._register( - self.goto, - (idx, item.NextSymbol), - node[item.NextSymbol.Name][0].idx, - ) - return automaton - - @staticmethod - def _register(table, key, value): - # assert ( - # key not in table or table[key] == value - # ), "Shift-Reduce or Reduce-Reduce conflict!!!" - if key in table and table[key] != value: - raise shift_reduce_error(table[key], value, "SLR") - table[key] = value - - -class LR1Parser(ShiftReduceParser): - def _build_parsing_table(self): - G = self.G.AugmentedGrammar(True) - - automaton = build_LR1_automaton(G) - for i, node in enumerate(automaton): - if self.verbose: - print(i, "\t", "\n\t ".join(str(x) for x in node.state), "\n") - node.idx = i - - # print("automatons states") - for node in automaton: - idx = node.idx - for item in node.state: - # print("item", item) - # - Fill `self.Action` and `self.Goto` according to `item`) - # - Feel free to use `self._register(...)`) - if item.IsReduceItem: - if item.production.Left == G.startSymbol: - self._register(self.action, (idx, G.EOF), (self.OK, None)) - else: - for symbol in item.lookaheads: - self._register( - self.action, - (idx, symbol), - (self.REDUCE, item.production), - ) - else: - if item.NextSymbol.IsTerminal: - self._register( - self.action, - (idx, item.NextSymbol), - (self.SHIFT, node[item.NextSymbol.Name][0].idx), - ) - else: - self._register( - self.goto, - (idx, item.NextSymbol), - node[item.NextSymbol.Name][0].idx, - ) - return automaton - - @staticmethod - def _register(table, key, value): - if key in table and table[key] != value: - raise shift_reduce_error(table[key], value, "LR", key) - table[key] = value - - -class LALR_Parser(ShiftReduceParser): - def _build_parsing_table(self): - G = self.G.AugmentedGrammar(True) - - automaton = build_LALR_automaton(G) - - for i, node in enumerate(automaton): - if self.verbose: - print(i, "\t", "\n\t ".join(str(x) for x in node.state), "\n") - node.idx = i - - for node in automaton: - idx = node.idx - for item in node.state: - # - Fill `self.Action` and `self.Goto` according to `item`) - # - Feel free to use `self._register(...)`) - if item.IsReduceItem: - if item.production.Left == G.startSymbol: - self._register(self.action, (idx, G.EOF), (self.OK, None)) - else: - for symbol in item.lookaheads: - self._register( - self.action, - (idx, symbol), - (self.REDUCE, item.production), - ) - else: - if item.NextSymbol.IsTerminal: - self._register( - self.action, - (idx, item.NextSymbol), - (self.SHIFT, node[item.NextSymbol.Name][0].idx), - ) - else: - self._register( - self.goto, - (idx, item.NextSymbol), - node[item.NextSymbol.Name][0].idx, - ) - - return automaton - - @staticmethod - def _register(table, key, value): - if key in table and table[key] != value: - raise shift_reduce_error(table[key], value, "LALR") - table[key] = value - - -# ----------------------derivation tree-------------------------# -def DerivationTree(derivation, G): - lent = len(derivation) - - nonTerminalstack = [] - root = State(G.startSymbol.Name) - nonTerminalstack.append(root) - - while lent > 0: - lent -= 1 - next_production = derivation[lent] - print("next_production", next_production) - currentNode = nonTerminalstack.pop() - # assert currentNode.state == next_production.Left.Name, "Wrong derivation" - - if next_production.IsEpsilon: - currentNode.add_transition(" ", State("epsilon", True)) - - for symbol in next_production.Right: - if symbol.IsTerminal: - currentNode.add_transition(" ", State(symbol.Name, True)) - else: - nonTerminalstack.append(State(symbol.Name)) - currentNode.add_transition( - " ", nonTerminalstack[len(nonTerminalstack) - 1] - ) - - return root From d71eb17f453da0f338c7bf3bfe6e1018219a8977 Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Thu, 26 Nov 2020 14:14:06 -0500 Subject: [PATCH 007/162] TSet builder Another sweep for the ast. Collects the types of variables and conforms a set. The set of a variable with type AUTO_TYPE is formed by all existent types in context --- src/ast_nodes.py | 21 +++---- src/tset_builder.py | 117 +++++++++++++++++++++++++++++++++++--- test/test_tset_builder.py | 79 +++++++++++++++++++++++++ 3 files changed, 195 insertions(+), 22 deletions(-) create mode 100644 test/test_tset_builder.py diff --git a/src/ast_nodes.py b/src/ast_nodes.py index 61c295125..d8dfa6aaf 100644 --- a/src/ast_nodes.py +++ b/src/ast_nodes.py @@ -33,13 +33,6 @@ def __init__(self, idx, typex, init_exp=None): self.init_exp = init_exp -class VarDeclarationNode: - def __init__(self, idx, typex, expr=None): - self.id = idx - self.type = typex - self.expr = expr - - class AssignNode(ExpressionNode): def __init__(self, idx, expr): self.id = idx @@ -52,6 +45,13 @@ def __init__(self, identifiers, body): self.body = body +class VarDeclarationNode: + def __init__(self, idx, typex, expr=None): + self.id = idx + self.type = typex + self.expr = expr + + class IfNode(ExpressionNode): def __init__(self, if_exp, then_exp, else_exp): self.if_expr = if_exp @@ -78,13 +78,6 @@ def __init__(self, idx, typex, exp): self.expr = exp -# #atomic? -# class NotNode(ExpressionNode): -# def __init__(self, exp): -# self.exp = exp - -# method_name=id, args,obj,type -# aaaaaaaaaaaaaaaaaaaaaaaaaaaa que hago con estooooooooooooooooooooooooooo class CallNode(ExpressionNode): def __init__(self, idx, args, obj=None, at_type=None): self.obj = obj diff --git a/src/tset_builder.py b/src/tset_builder.py index db617af40..a1b0cfdce 100644 --- a/src/tset_builder.py +++ b/src/tset_builder.py @@ -2,11 +2,23 @@ import src.cmp.nbpackage import src.cmp.visitor as visitor +from src.cmp.semantic import ( + ObjectType, + IntType, + StringType, + VoidType, + BoolType, + ErrorType, + AutoType, + SelfType, + SemanticError, +) from src.ast_nodes import Node, ProgramNode, ExpressionNode from src.ast_nodes import ClassDeclarationNode, FuncDeclarationNode, AttrDeclarationNode from src.ast_nodes import VarDeclarationNode, AssignNode, CallNode from src.ast_nodes import ( AtomicNode, + UnaryNode, BinaryNode, ArithmeticOperation, ComparisonOperation, @@ -45,12 +57,30 @@ def create_child(self, node): self.children[node] = child return child + def __str__(self): + output = "" + + for key, value in self.tsets_dict.items(): + output += "\t" + str(key) + ":" + str(value) + "\n" + for key, chil in self.children.items(): + output += "\n" + try: + output += key.id + "--->" + except AttributeError: + output += "let or case --->" + output += "\n" + output += str(chil) + return output + class TSetBuilder: def __init__(self, context, errors=[]): self.context = context self.errors = errors + def get_autotype_set(self): + return set(self.context.types.keys()) + @visitor.on("node") def visit(self, node, tset): pass @@ -59,33 +89,104 @@ def visit(self, node, tset): def visit(self, node, tset=None): tset = Tset() for declaration in node.declarations: - self.visit(declaration, tset.create_child()) + self.visit(declaration, tset.create_child(declaration)) return tset @visitor.when(ClassDeclarationNode) def visit(self, node, tset): - pass + for feature in node.features: + self.visit(feature, tset) @visitor.when(AttrDeclarationNode) def visit(self, node, tset): - pass + static_type = self.context.get_type(node.type) + if static_type.name == "AUTO_TYPE": + tset.tsets_dict[node.id] = self.get_autotype_set() + else: + tset.tsets_dict[node.id] = set([static_type.name]) + if node.init_exp is not None: + self.visit(node.init_exp, tset) @visitor.when(FuncDeclarationNode) def visit(self, node, tset): - pass + child_set = tset.create_child(node) + for param in node.params: + typex = self.context.get_type(param[1]) + if typex.name == "AUTO_TYPE": + child_set.tsets_dict[param[0]] = self.get_autotype_set() + else: + child_set.tsets_dict[param[0]] = set([typex.name]) + + self.visit(node.body, child_set) + + @visitor.when(AssignNode) + def visit(self, node, tset): + self.visit(node.expr, tset) @visitor.when(LetNode) def visit(self, node, tset): - pass + child_set = tset.create_child(node) + for var_dec in node.identifiers: + self.visit(var_dec, child_set) + + self.visit(node.body, child_set) + + @visitor.when(VarDeclarationNode) + def visit(self, node, tset): + typex = self.context.get_type(node.type) + if typex.name == "AUTO_TYPE": + tset.tsets_dict[node.id] = self.get_autotype_set() + else: + tset.tsets_dict[node.id] = set([typex.name]) + + self.visit(node.expr, tset) + + @visitor.when(IfNode) + def visit(self, node, tset): + self.visit(node.if_expr, tset) + self.visit(node.then_expr, tset) + self.visit(node.else_expr, tset) + + @visitor.when(WhileNode) + def visit(self, node, tset): + self.visit(node.condition, tset) + self.visit(node.body, tset) @visitor.when(CaseNode) def visit(self, node, tset): - pass + self.visit(node.expr, tset) + + for item in node.case_items: + self.visit(item, tset.create_child(item)) @visitor.when(CaseItemNode) + def visit(self, node, tset): + typex = self.context.get_type(node.type) + if typex.name == "AUTO_TYPE": + tset.tsets_dict[node.id] = self.get_autotype_set() + else: + tset.tsets_dict[node.id] = set([typex.name]) + + self.visit(node.expr, tset) + + @visitor.when(CallNode) def visit(self, node, tset): pass + @visitor.when(BlockNode) + def visit(self, node, tset): + for expr in node.expression_list: + self.visit(expr, tset) + + @visitor.when(AtomicNode) + def visit(self, node, tset): + pass -def get_autotype_set(): - pass + @visitor.when(UnaryNode) + def visit(self, node, tset): + self.visit(node.expr, tset) + + @visitor.when(BinaryNode) + def visit(self, node, tset): + self.visit(node.left, tset) + self.visit(node.right, tset) diff --git a/test/test_tset_builder.py b/test/test_tset_builder.py new file mode 100644 index 000000000..9ec95de96 --- /dev/null +++ b/test/test_tset_builder.py @@ -0,0 +1,79 @@ +from run_pipeline import run_pipeline +from src.type_collector import TypeCollector +from src.type_builder import TypeBuilder +from src.type_checker import TypeChecker +from src.tset_builder import TSetBuilder + + +def test(): + text = """ + class A { + a : String ; + b : Bool ; + c : Int <- 0 ; + d : Void <- while c < 1 loop c = c + 1 pool ; + step ( p : AUTO_TYPE ) : AUTO_TYPE { p . translate ( 1 , 1 ) } ; + } ; + + class Point { + step ( p : AUTO_TYPE ) : AUTO_TYPE { p . translate ( 1 , 1 ) } ; + main ( ) : Object { + let p : AUTO_TYPE <- new Point in { + step ( p ) ; *Puede lanzar error semantico* + } + } ; + } ; + class B inherits A { + e : Bool ; + step ( p : AUTO_TYPE ) : AUTO_TYPE { p } ; + test ( e : Int ) : Bool { + { + let x : Int <- 4 in e + ~ x ; + + case 5 + 4 of + f : Bool => f ; + g : Bool => not g ; + esac ; + self . step ( e ) ; + } + } ; + } ; + + class C { + a : B ; + b : Int <- 8 ; + c : Bool <- false ; + + m ( ) : Bool { + { + a @ A . step ( b ) ; + if not c then true else false fi ; + a . step ( b ) ; + } + } ; + } ; + """ + + ast = run_pipeline(text) + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + scope = checker.visit(ast, None) + + tset_builder = TSetBuilder(context, errors) + tset = tset_builder.visit(ast, None) + + print("Errors:", errors) + print("Context:") + print(context) + print(tset) + + assert errors == [] From 68a5a236860d86f3ceee6703f27e525db55db394 Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Fri, 27 Nov 2020 23:59:37 -0500 Subject: [PATCH 008/162] Tset reducer in some nodes. Case and Call nodes are not implemented. Some of the implemented nodes still need to be tested. --- src/cmp/semantic.py | 6 +- src/cmp/utils.py | 49 ++++++++++ src/tset.py | 33 +++++++ src/tset_builder.py | 44 ++------- src/tsets_reducer.py | 227 +++++++++++++++++++++++++++++++++++++++++++ src/type_checker.py | 31 +----- test/test_reducer.py | 67 +++++++++++++ 7 files changed, 390 insertions(+), 67 deletions(-) create mode 100644 src/tset.py create mode 100644 src/tsets_reducer.py create mode 100644 test/test_reducer.py diff --git a/src/cmp/semantic.py b/src/cmp/semantic.py index 787a53a4a..bdb5a360a 100644 --- a/src/cmp/semantic.py +++ b/src/cmp/semantic.py @@ -122,7 +122,7 @@ def conforms_to(self, other): or self == other or self.name == "AUTO_TYPE" or other.name == "AUTO_TYPE" - or self.parent is not None + or self.parent != None and self.parent.conforms_to(other) ) @@ -167,8 +167,8 @@ def __init__(self): def conforms_to(self, other): raise Exception("Invalid type at 'conforms_to' : void type.") - def bypass(self): - return True + # def bypass(self): + # return True def __eq__(self, other): return isinstance(other, VoidType) diff --git a/src/cmp/utils.py b/src/cmp/utils.py index b69b1e5db..f6bc72985 100644 --- a/src/cmp/utils.py +++ b/src/cmp/utils.py @@ -280,3 +280,52 @@ def __str__(self): def __repr__(self): return str(self) + + +def find_least_type(type_a, type_b, context): + if type_a is None: + return type_b + + if type_b is None: + return type_a + + if type_a.conforms_to(type_b): + return type_b + + if type_b.conforms_to(type_a): + return type_a + + solve = type_a.parent + while solve is not None: + if type_b.conforms_to(solve): + return solve + solve = solve.parent + + return context.get_type("Object") + + +def union(set_a, set_b): + for item in set_b: + set_a.add(item) + return set_a + + +def intersection(set_a, set_b): + solve = set() + for item in set_a: + if item in set_b: + solve.add(item) + return solve + + +def reduce_set(set_a, set_b): + if "InferenceError" in set_a: + return union(set_a, set_b) + + _intersection = intersection(set_a, set_b) + if len(_intersection) == 0: + _union = union(set_a, set_b) + _union.add("InferenceError") + return _union + else: + return _intersection diff --git a/src/tset.py b/src/tset.py new file mode 100644 index 000000000..71777eff6 --- /dev/null +++ b/src/tset.py @@ -0,0 +1,33 @@ +class Tset: + def __init__(self, parent=None): + self.locals = {} + self.parent = parent + self.children = {} + + def create_child(self, node): + child = Tset(self) + self.children[node] = child + return child + + def find_set(self, idx): + if idx in self.locals.keys(): + return self.locals + elif self.parent != None: + return self.parent.find_set(idx) + + return None + + def __str__(self): + output = "" + + for key, value in self.locals.items(): + output += "\t" + str(key) + ":" + str(value) + "\n" + for key, chil in self.children.items(): + output += "\n" + try: + output += key.id + "--->" + except AttributeError: + output += "let or case --->" + output += "\n" + output += str(chil) + return output diff --git a/src/tset_builder.py b/src/tset_builder.py index a1b0cfdce..320b2cc87 100644 --- a/src/tset_builder.py +++ b/src/tset_builder.py @@ -2,6 +2,7 @@ import src.cmp.nbpackage import src.cmp.visitor as visitor +from src.tset import Tset from src.cmp.semantic import ( ObjectType, IntType, @@ -46,33 +47,6 @@ ) -class Tset: - def __init__(self, parent=None): - self.tsets_dict = {} - self.parent = parent - self.children = {} - - def create_child(self, node): - child = Tset(self) - self.children[node] = child - return child - - def __str__(self): - output = "" - - for key, value in self.tsets_dict.items(): - output += "\t" + str(key) + ":" + str(value) + "\n" - for key, chil in self.children.items(): - output += "\n" - try: - output += key.id + "--->" - except AttributeError: - output += "let or case --->" - output += "\n" - output += str(chil) - return output - - class TSetBuilder: def __init__(self, context, errors=[]): self.context = context @@ -101,9 +75,9 @@ def visit(self, node, tset): def visit(self, node, tset): static_type = self.context.get_type(node.type) if static_type.name == "AUTO_TYPE": - tset.tsets_dict[node.id] = self.get_autotype_set() + tset.locals[node.id] = self.get_autotype_set() else: - tset.tsets_dict[node.id] = set([static_type.name]) + tset.locals[node.id] = set([static_type.name]) if node.init_exp is not None: self.visit(node.init_exp, tset) @@ -113,9 +87,9 @@ def visit(self, node, tset): for param in node.params: typex = self.context.get_type(param[1]) if typex.name == "AUTO_TYPE": - child_set.tsets_dict[param[0]] = self.get_autotype_set() + child_set.locals[param[0]] = self.get_autotype_set() else: - child_set.tsets_dict[param[0]] = set([typex.name]) + child_set.locals[param[0]] = set([typex.name]) self.visit(node.body, child_set) @@ -135,9 +109,9 @@ def visit(self, node, tset): def visit(self, node, tset): typex = self.context.get_type(node.type) if typex.name == "AUTO_TYPE": - tset.tsets_dict[node.id] = self.get_autotype_set() + tset.locals[node.id] = self.get_autotype_set() else: - tset.tsets_dict[node.id] = set([typex.name]) + tset.locals[node.id] = set([typex.name]) self.visit(node.expr, tset) @@ -163,9 +137,9 @@ def visit(self, node, tset): def visit(self, node, tset): typex = self.context.get_type(node.type) if typex.name == "AUTO_TYPE": - tset.tsets_dict[node.id] = self.get_autotype_set() + tset.locals[node.id] = self.get_autotype_set() else: - tset.tsets_dict[node.id] = set([typex.name]) + tset.locals[node.id] = set([typex.name]) self.visit(node.expr, tset) diff --git a/src/tsets_reducer.py b/src/tsets_reducer.py new file mode 100644 index 000000000..b75f945d1 --- /dev/null +++ b/src/tsets_reducer.py @@ -0,0 +1,227 @@ +import src.cmp.visitor as visitor +import src.cmp.nbpackage +import src.cmp.visitor as visitor + +from src.tset import Tset +from src.cmp.semantic import ( + ObjectType, + IntType, + StringType, + VoidType, + BoolType, + ErrorType, + AutoType, + SelfType, + SemanticError, +) +from src.ast_nodes import Node, ProgramNode, ExpressionNode +from src.ast_nodes import ClassDeclarationNode, FuncDeclarationNode, AttrDeclarationNode +from src.ast_nodes import VarDeclarationNode, AssignNode, CallNode +from src.ast_nodes import ( + AtomicNode, + UnaryNode, + BinaryNode, + ArithmeticOperation, + ComparisonOperation, + IfNode, + LetNode, + CaseNode, + CaseItemNode, + WhileNode, + BlockNode, + IsvoidNode, +) +from src.ast_nodes import ( + ConstantNumNode, + VariableNode, + InstantiateNode, + PlusNode, + MinusNode, + StarNode, + DivNode, + NegNode, + NotNode, + EqualNode, + BooleanNode, + StringNode, +) +from src.cmp.utils import find_least_type, union, intersection, reduce_set + + +class TSetReducer: + def __init__(self, context, errors=[]): + self.context = context + self.errors = errors + + def get_autotype_set(self): + return {self.context.types.keys()} + + @visitor.on("node") + def visit(self, node, tset): + pass + + @visitor.when(ProgramNode) + def visit(self, node, tset): + for declaration in node.declarations: + self.visit(declaration, tset.children[declaration]) + return tset + + @visitor.when(ClassDeclarationNode) + def visit(self, node, tset): + for feature in node.features: + self.visit(feature, tset) + + @visitor.when(AttrDeclarationNode) + def visit(self, node, tset): + if node.init_exp is not None: + init_expr_set = self.visit(node.init_exp, tset) + tset.locals[node.id] = reduce_set(tset.locals[node.id], init_expr_set) + return tset.locals[node.id] + + return tset.locals[node.id] + + @visitor.when(FuncDeclarationNode) + def visit(self, node, tset): + current_tset = tset.children[node] + self.visit(node.body, current_tset) + + @visitor.when(AssignNode) + def visit(self, node, tset): + expr_set = self.visit(node.expr, tset) + var_set = tset.find_set(node.id) + var_set[node.id] = reduce_set(var_set[node.id], expr_set) + return var_set + + @visitor.when(LetNode) + def visit(self, node, tset): + current_tset = tset.children[node] + for var_dec in node.identifiers: + self.visit(var_dec, current_tset) + + return self.visit(node.body, current_tset) + + @visitor.when(VarDeclarationNode) + def visit(self, node, tset): + if node.expr is not None: + expr_set = self.visit(node.expr, tset) + tset.locals[node.id] = reduce_set(tset.locals[node.id], expr_set) + + return tset.locals[node.id] + + @visitor.when(IfNode) + def visit(self, node, tset): + self.visit(node.if_expr, tset) + if isinstance(node.if_expr, VariableNode): + tset_locals = tset.find_set(node.if_expr.lex) + tset_locals[node.if_expr.lex] = reduce_set( + tset_locals[node.if_expr.lex], {"Bool"} + ) + then_expr_set = self.visit(node.then_expr, tset) + else_expr_set = self.visit(node.else_expr, tset) + + _union = union(then_expr_set, else_expr_set) + + current_type = None + for item in _union: + typex = self.context.get_type(item) + current_type = find_least_type(current_type, typex, self.context) + + return {current_type.name} + + @visitor.when(WhileNode) + def visit(self, node, tset): + self.visit(node.condition, tset) + self.visit(node.body, tset) + + return {"Object"} + + @visitor.when(CaseNode) + def visit(self, node, tset): + self.visit(node.expr, tset) + + union_set = set() + for item in node.case_items: + item_set = self.visit(item, tset.children[item]) + union_set = union(union_set, item_set) + + current_type = None + for item in union_set: + current_type = find_least_type(current_type, item, self.context) + + return current_type + + @visitor.when(CaseItemNode) + def visit(self, node, tset): + expr_tset = self.visit(node.expr, tset) + return reduce_set(tset.locals[node.id], expr_tset) + + @visitor.when(CallNode) + def visit(self, node, tset): + pass + + @visitor.when(BlockNode) + def visit(self, node, tset): + current_set = None + for expr in node.expression_list: + current_set = self.visit(expr, tset) + + return current_set + + @visitor.when(InstantiateNode) # NewNode + def visit(self, node, tset): + return {node.lex} + + @visitor.when(IsvoidNode) + def visit(self, node, tset): + self.visit(node.expr, tset) + return {"Bool"} + + @visitor.when(BinaryNode) + def visit(self, node, tset): + self.visit(node.left, tset) + self.visit(node.right, tset) + + int_set = {"Int"} + if isinstance(node.left, VariableNode): + node_id = node.left.lex + tset_locals = tset.find_set(node_id) + tset_locals[node_id] = reduce_set(tset_locals[node_id], int_set) + + if isinstance(node.right, VariableNode): + node_id = node.right.lex + tset_locals = tset.find_set(node_id) + tset_locals[node_id] = reduce_set(tset_locals[node_id], int_set) + + return int_set + + @visitor.when(EqualNode) + def visit(self, node, tset): + pass + + @visitor.when(NotNode) + def visit(self, node, tset): + self.visit(node.expr, tset) + return {"Bool"} + + @visitor.when(NegNode) + def visit(self, node, tset): + self.visit(node.expr, tset) + return {"Int"} + + @visitor.when(ConstantNumNode) + def visit(self, node, tset): + return {"Int"} + + @visitor.when(VariableNode) + def visit(self, node, tset): + tset_locals = tset.find_set(node.lex) + return tset_locals[node.lex] + + @visitor.when(StringNode) + def visit(self, node, tset): + return {"String"} + + @visitor.when(BooleanNode) + def visit(self, node, tset): + return {"Bool"} + diff --git a/src/type_checker.py b/src/type_checker.py index 5d196a702..c50516619 100644 --- a/src/type_checker.py +++ b/src/type_checker.py @@ -1,7 +1,6 @@ import src.cmp.nbpackage import src.cmp.visitor as visitor -# from cp13 import G, text from src.ast_nodes import Node, ProgramNode, ExpressionNode from src.ast_nodes import ClassDeclarationNode, FuncDeclarationNode, AttrDeclarationNode from src.ast_nodes import VarDeclarationNode, AssignNode, CallNode @@ -34,15 +33,13 @@ ) from src.cool_visitor import FormatVisitor -# from cp13 import FormatVisitor, tokenize_text, pprint_tokens - from src.cmp.semantic import SemanticError from src.cmp.semantic import Attribute, Method, Type from src.cmp.semantic import VoidType, ErrorType, IntType from src.cmp.semantic import Context -# from cp14 import TypeCollector, TypeBuilder, run_pipeline from src.cmp.semantic import Scope +from src.cmp.utils import find_least_type WRONG_SIGNATURE = 'Method "%s" already defined in "%s" with a different signature.' SELF_IS_READONLY = 'Variable "self" is read-only.' @@ -224,10 +221,9 @@ def visit(self, node, scope): @visitor.when(IfNode) def visit(self, node, scope): - bool_type = self.context.get_type("Bool") predicate_type = self.visit(node.if_expr, scope) - if predicate_type != bool_type: + if predicate_type.name != "Bool" and predicate_type.name != "AUTO_TYPE": self.errors.append("Expression must be bool") return ErrorType() @@ -414,26 +410,3 @@ def visit(self, node, scope): def visit(self, node, scope): return self.context.get_type("Bool") - -def find_least_type(type_a, type_b, context): - if type_a is None: - return type_b - - if type_b is None: - return type_a - - if type_a.conforms_to(type_b): - return type_b - - if type_b.conforms_to(type_a): - return type_a - - solve = type_a.parent - while solve is not None: - print("Solve ----------------> " + str(solve)) - if type_b.conforms_to(solve): - return solve - solve = solve.parent - - return context.get_type("Object") - diff --git a/test/test_reducer.py b/test/test_reducer.py new file mode 100644 index 000000000..83a48f3a7 --- /dev/null +++ b/test/test_reducer.py @@ -0,0 +1,67 @@ +from run_pipeline import run_pipeline +from src.type_collector import TypeCollector +from src.type_builder import TypeBuilder +from src.type_checker import TypeChecker +from src.tset_builder import TSetBuilder +from src.tsets_reducer import TSetReducer + + +def test(): + text = """ + class A { + a : String ; + b : AUTO_TYPE ; + c : Int <- 0 ; + d : Object <- while c < 1 loop c + 1 pool ; + j : AUTO_TYPE ; + l : AUTO_TYPE ; + step ( p : AUTO_TYPE ) : AUTO_TYPE { + b <- + { + p + 5 ; + p <- false ; + j <- p ; + isvoid d ; + } + } ; + } ; + + class Point inherits A { + h : AUTO_TYPE <- "debe ser tipo string" ; + k : AUTO_TYPE ; + step ( p : AUTO_TYPE ) : AUTO_TYPE { k <- if p then new Point else new A fi } ; + main ( ) : Object { + let i : AUTO_TYPE <- new A in { + isvoid i ; *Puede lanzar error semantico* + } + } ; + } ; + """ + # l <- ~ c ; + + ast = run_pipeline(text) + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + __ = checker.visit(ast, None) + + tset_builder = TSetBuilder(context, errors) + tset = tset_builder.visit(ast, None) + + tset_reducer = TSetReducer(context, errors) + reduced_set = tset_reducer.visit(ast, tset) + + print("Errors:", errors) + print("Context:") + print(context) + print(reduced_set) + + assert False From 3ab4f4d05e63de10fd2de2e2836a51b8dce86aed Mon Sep 17 00:00:00 2001 From: Gaby Date: Sat, 28 Nov 2020 15:52:05 -0500 Subject: [PATCH 009/162] Add .vscode to gitignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index bb58c3f8b..30e914fab 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,4 @@ src/cmp/__pycache__/ src/cmp/tools/__pycache__/ .directory/ .pytest_cache/ - +.vscode/ From bd2499d7d7d8806bf3ad8479952d0a9d9be089c0 Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Sun, 29 Nov 2020 22:26:32 -0500 Subject: [PATCH 010/162] Complete pipeline. Infer as expected. Removed Void type. --- src/cmp/semantic.py | 5 +- src/cmp/utils.py | 12 +++ src/main.py | 45 ++++++++++- src/tset.py | 39 +++++++++ src/tset_builder.py | 22 +++-- src/tset_merger.py | 163 ++++++++++++++++++++++++++++++++++++++ src/tsets_reducer.py | 99 +++++++++++++++++++---- src/type_checker.py | 50 +++++++----- src/type_collector.py | 1 - test/test_merger.py | 105 ++++++++++++++++++++++++ test/test_reducer.py | 30 ++++--- test/test_reducer2.py | 53 +++++++++++++ test/test_reducer3.py | 55 +++++++++++++ test/test_tset_builder.py | 2 +- test/test_type_builder.py | 2 +- test/test_type_checker.py | 2 +- 16 files changed, 624 insertions(+), 61 deletions(-) create mode 100644 src/tset_merger.py create mode 100644 test/test_merger.py create mode 100644 test/test_reducer2.py create mode 100644 test/test_reducer3.py diff --git a/src/cmp/semantic.py b/src/cmp/semantic.py index bdb5a360a..f4fb7d21a 100644 --- a/src/cmp/semantic.py +++ b/src/cmp/semantic.py @@ -26,6 +26,7 @@ def __init__(self, name, param_names, params_types, return_type): self.param_names = param_names self.param_types = params_types self.return_type = return_type + self.tset = None def __str__(self): params = ", ".join( @@ -164,8 +165,8 @@ class VoidType(Type): def __init__(self): Type.__init__(self, "Void") - def conforms_to(self, other): - raise Exception("Invalid type at 'conforms_to' : void type.") + # def conforms_to(self, other): + # raise Exception("Invalid type at 'conforms_to' : void type.") # def bypass(self): # return True diff --git a/src/cmp/utils.py b/src/cmp/utils.py index f6bc72985..5bcf97b19 100644 --- a/src/cmp/utils.py +++ b/src/cmp/utils.py @@ -304,6 +304,15 @@ def find_least_type(type_a, type_b, context): return context.get_type("Object") +def least_type(type_set, context): + solve = None + for item in type_set: + typex = context.get_type(item) + solve = find_least_type(solve, typex, context) + + return solve.name + + def union(set_a, set_b): for item in set_b: set_a.add(item) @@ -319,6 +328,9 @@ def intersection(set_a, set_b): def reduce_set(set_a, set_b): + if "!static_type_declared" in set_a: + return set_a + if "InferenceError" in set_a: return union(set_a, set_b) diff --git a/src/main.py b/src/main.py index 54cf7486b..4d493a329 100644 --- a/src/main.py +++ b/src/main.py @@ -1,7 +1,13 @@ from src.cool_tokenizer import tokenize_cool_text from src.cool_grammar import define_cool_grammar from src.cool_visitor import FormatVisitor + from src.type_collector import TypeCollector +from src.type_builder import TypeBuilder +from src.type_checker import TypeChecker +from src.tset_builder import TSetBuilder +from src.tsets_reducer import TSetReducer +from src.tset_merger import TSetMerger from src.shift_reduce_parsers import LR1Parser, DerivationTree from src.errors import parsing_table_error, Error @@ -24,9 +30,42 @@ def run_pipeline(text): ast = evaluate_reverse_parse(parse, operations, tokens) - formatter = FormatVisitor() - tree = formatter.visit(ast) - print(tree) + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + tset_builder = TSetBuilder(context, errors) + tset = tset_builder.visit(ast, None) + + tset_reducer = TSetReducer(context, errors) + reduced_set = tset_reducer.visit(ast, tset) + + tset_merger = TSetMerger(context, errors) + tset_merger.visit(ast, reduced_set) + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + # formatter = FormatVisitor() + # tree = formatter.visit(ast) + # print(tree) # derivation_list = parser(text) # derivation_tree_aut = DerivationTree(derivation_list[0], G) diff --git a/src/tset.py b/src/tset.py index 71777eff6..684b58d74 100644 --- a/src/tset.py +++ b/src/tset.py @@ -31,3 +31,42 @@ def __str__(self): output += "\n" output += str(chil) return output + + def clone(self): + solve = Tset() + solve.parent = self.parent + for idx, typex in self.locals.items(): + solve.locals[idx] = typex.copy() + + for key, value in self.children.items(): + solve.children[key] = value.clone() + + return solve + + def compare(self, other): + if len(self.locals) != len(other.locals) or len(self.children) != len( + other.children + ): + return False + + for (idx, tset), (idx_other, tset_other) in zip( + self.locals.items(), other.locals.items() + ): + if idx != idx_other or tset != tset_other: + return False + for (key, value), (key_other, value_other) in zip( + self.children.items(), other.children.items() + ): + if key != key_other or not value.compare(value_other): + return False + return True + + def clean(self): + for typex in self.locals.values(): + if "InferenceError" in typex: + typex.remove("InferenceError") + if "!static_type_declared" in typex: + typex.remove("!static_type_declared") + for child in self.children.values(): + child.clean() + diff --git a/src/tset_builder.py b/src/tset_builder.py index 320b2cc87..549e4aee4 100644 --- a/src/tset_builder.py +++ b/src/tset_builder.py @@ -50,10 +50,13 @@ class TSetBuilder: def __init__(self, context, errors=[]): self.context = context + self.current_type = None self.errors = errors def get_autotype_set(self): - return set(self.context.types.keys()) + solve = set(self.context.types.keys()) + solve.remove("AUTO_TYPE") + return solve @visitor.on("node") def visit(self, node, tset): @@ -68,6 +71,7 @@ def visit(self, node, tset=None): @visitor.when(ClassDeclarationNode) def visit(self, node, tset): + self.current_type = self.context.get_type(node.id) for feature in node.features: self.visit(feature, tset) @@ -77,19 +81,27 @@ def visit(self, node, tset): if static_type.name == "AUTO_TYPE": tset.locals[node.id] = self.get_autotype_set() else: - tset.locals[node.id] = set([static_type.name]) + tset.locals[node.id] = {static_type.name, "!static_type_declared"} if node.init_exp is not None: self.visit(node.init_exp, tset) @visitor.when(FuncDeclarationNode) def visit(self, node, tset): + if node.type == "AUTO_TYPE": + tset.locals[node.id] = self.get_autotype_set() + else: + tset.locals[node.id] = {node.type, "!static_type_declared"} + + method = self.current_type.get_method(node.id) + method.tset = tset.locals[node.id] + child_set = tset.create_child(node) for param in node.params: typex = self.context.get_type(param[1]) if typex.name == "AUTO_TYPE": child_set.locals[param[0]] = self.get_autotype_set() else: - child_set.locals[param[0]] = set([typex.name]) + child_set.locals[param[0]] = {typex.name, "!static_type_declared"} self.visit(node.body, child_set) @@ -111,7 +123,7 @@ def visit(self, node, tset): if typex.name == "AUTO_TYPE": tset.locals[node.id] = self.get_autotype_set() else: - tset.locals[node.id] = set([typex.name]) + tset.locals[node.id] = {typex.name, "!static_type_declared"} self.visit(node.expr, tset) @@ -139,7 +151,7 @@ def visit(self, node, tset): if typex.name == "AUTO_TYPE": tset.locals[node.id] = self.get_autotype_set() else: - tset.locals[node.id] = set([typex.name]) + tset.locals[node.id] = {typex.name, "!static_type_declared"} self.visit(node.expr, tset) diff --git a/src/tset_merger.py b/src/tset_merger.py new file mode 100644 index 000000000..178132095 --- /dev/null +++ b/src/tset_merger.py @@ -0,0 +1,163 @@ +import src.cmp.visitor as visitor +import src.cmp.nbpackage +import src.cmp.visitor as visitor + +from src.tset import Tset +from src.cmp.semantic import ( + ObjectType, + IntType, + StringType, + VoidType, + BoolType, + ErrorType, + AutoType, + SelfType, + SemanticError, +) +from src.ast_nodes import Node, ProgramNode, ExpressionNode +from src.ast_nodes import ClassDeclarationNode, FuncDeclarationNode, AttrDeclarationNode +from src.ast_nodes import VarDeclarationNode, AssignNode, CallNode +from src.ast_nodes import ( + AtomicNode, + UnaryNode, + BinaryNode, + ArithmeticOperation, + ComparisonOperation, + IfNode, + LetNode, + CaseNode, + CaseItemNode, + WhileNode, + BlockNode, + IsvoidNode, +) +from src.ast_nodes import ( + ConstantNumNode, + VariableNode, + InstantiateNode, + PlusNode, + MinusNode, + StarNode, + DivNode, + NegNode, + NotNode, + EqualNode, + BooleanNode, + StringNode, +) +from src.cmp.utils import least_type + + +class TSetMerger: + def __init__(self, context, errors=[]): + self.context = context + self.errors = errors + + def get_autotype_set(self): + solve = set(self.context.types.keys()) + solve.remove("AUTO_TYPE") + return solve + + @visitor.on("node") + def visit(self, node, tset): + pass + + @visitor.when(ProgramNode) + def visit(self, node, tset): + for declaration in node.declarations: + self.visit(declaration, tset.children[declaration]) + + @visitor.when(ClassDeclarationNode) + def visit(self, node, tset): + for feature in node.features: + self.visit(feature, tset) + + @visitor.when(AttrDeclarationNode) + def visit(self, node, tset): + typex = least_type(tset.locals[node.id], self.context) + node.type = typex + + if node.init_exp is not None: + self.visit(node.init_exp, tset) + + @visitor.when(FuncDeclarationNode) + def visit(self, node, tset): + return_type = least_type(tset.locals[node.id], self.context) + node.type = return_type + + child_tset = tset.children[node] + args_types = [] + for param in node.params: + typex = least_type(child_tset.locals[param[0]], self.context) + args_types.append((param[0], typex)) + + for i in range(len(args_types)): + node.params[i] = args_types[i] + self.visit(node.body, child_tset) + + @visitor.when(AssignNode) + def visit(self, node, tset): + self.visit(node.expr, tset) + + @visitor.when(LetNode) + def visit(self, node, tset): + child_set = tset.children[node] + for var_dec in node.identifiers: + self.visit(var_dec, child_set) + + self.visit(node.body, child_set) + + @visitor.when(VarDeclarationNode) + def visit(self, node, tset): + typex = least_type(tset.locals[node.id], self.context) + node.type = typex + + if node.expr is not None: + self.visit(node.expr, tset) + + @visitor.when(IfNode) + def visit(self, node, tset): + self.visit(node.if_expr, tset) + self.visit(node.then_expr, tset) + self.visit(node.else_expr, tset) + + @visitor.when(WhileNode) + def visit(self, node, tset): + self.visit(node.condition, tset) + self.visit(node.body, tset) + + @visitor.when(CaseNode) + def visit(self, node, tset): + self.visit(node.expr, tset) + + for item in node.case_items: + self.visit(item, tset.children[item]) + + @visitor.when(CaseItemNode) + def visit(self, node, tset): + typex = least_type(tset.locals[node.id], self.context) + node.type = typex + self.visit(node.expr, tset) + + @visitor.when(CallNode) + def visit(self, node, tset): + for arg in node.args: + self.visit(arg, tset) + + @visitor.when(BlockNode) + def visit(self, node, tset): + for expr in node.expression_list: + self.visit(expr, tset) + + @visitor.when(AtomicNode) + def visit(self, node, tset): + pass + + @visitor.when(UnaryNode) + def visit(self, node, tset): + self.visit(node.expr, tset) + + @visitor.when(BinaryNode) + def visit(self, node, tset): + self.visit(node.left, tset) + self.visit(node.right, tset) diff --git a/src/tsets_reducer.py b/src/tsets_reducer.py index b75f945d1..a4b9e7711 100644 --- a/src/tsets_reducer.py +++ b/src/tsets_reducer.py @@ -51,6 +51,8 @@ class TSetReducer: def __init__(self, context, errors=[]): self.context = context + self.current_type = None + self.current_method = None self.errors = errors def get_autotype_set(self): @@ -62,12 +64,19 @@ def visit(self, node, tset): @visitor.when(ProgramNode) def visit(self, node, tset): - for declaration in node.declarations: - self.visit(declaration, tset.children[declaration]) + backup_tset = Tset() + while not backup_tset.compare(tset): + backup_tset = tset.clone() + + for declaration in node.declarations: + self.visit(declaration, tset.children[declaration]) + + tset.clean() return tset @visitor.when(ClassDeclarationNode) def visit(self, node, tset): + self.current_type = self.context.get_type(node.id) for feature in node.features: self.visit(feature, tset) @@ -82,15 +91,20 @@ def visit(self, node, tset): @visitor.when(FuncDeclarationNode) def visit(self, node, tset): + method = self.current_type.get_method(node.id) + self.current_method = method + current_tset = tset.children[node] - self.visit(node.body, current_tset) + body_set = self.visit(node.body, current_tset) + tset.locals[node.id] = reduce_set(tset.locals[node.id], body_set) + method.tset = tset.locals[node.id] @visitor.when(AssignNode) def visit(self, node, tset): expr_set = self.visit(node.expr, tset) var_set = tset.find_set(node.id) var_set[node.id] = reduce_set(var_set[node.id], expr_set) - return var_set + return var_set[node.id] @visitor.when(LetNode) def visit(self, node, tset): @@ -119,18 +133,21 @@ def visit(self, node, tset): then_expr_set = self.visit(node.then_expr, tset) else_expr_set = self.visit(node.else_expr, tset) - _union = union(then_expr_set, else_expr_set) + solve = intersection(then_expr_set, else_expr_set) + if len(solve) == 0: + solve = union(then_expr_set, else_expr_set) - current_type = None - for item in _union: - typex = self.context.get_type(item) - current_type = find_least_type(current_type, typex, self.context) - - return {current_type.name} + return solve @visitor.when(WhileNode) def visit(self, node, tset): self.visit(node.condition, tset) + + if isinstance(node.condition, VariableNode): + node_id = node.condition.lex + tset_locals = tset.find_set(node_id) + tset_locals[node_id] = reduce_set(tset_locals[node_id], {"Bool"}) + self.visit(node.body, tset) return {"Object"} @@ -146,18 +163,67 @@ def visit(self, node, tset): current_type = None for item in union_set: - current_type = find_least_type(current_type, item, self.context) + if item == "!static_type_declared": + continue + item_type = self.context.get_type(item) + current_type = find_least_type([current_type, item_type], self.context) - return current_type + return {current_type.name} @visitor.when(CaseItemNode) def visit(self, node, tset): expr_tset = self.visit(node.expr, tset) - return reduce_set(tset.locals[node.id], expr_tset) + tset.locals[node.id] = reduce_set(tset.locals[node.id], expr_tset) + return tset.locals[node.id] @visitor.when(CallNode) def visit(self, node, tset): - pass + for expr in node.args: + self.visit(expr, tset) + + if node.obj is not None: + expr_set = self.visit(node.obj, tset) + else: + expr_set = {self.current_type.name} + + types_with_method = set() + if node.at_type is not None: + types_with_method.add(node.at_type) + + else: + for typex in self.context.types.values(): + try: + method = typex.get_method(node.id) + if len(method.param_names) == len(node.args): + types_with_method.add(typex.name) + except SemanticError: + continue + + # DUDA!!!! + # if len(types_with_method) == 0: + # raise SemanticError( + # f"There is no method named {node.id} that takes {len(node.args)} arguments" + # ) + + if isinstance(node.obj, VariableNode): + node_id = node.obj.lex + tset_locals = tset.find_set(node_id) + + tset_locals[node_id] = reduce_set(tset_locals[node_id], types_with_method) + + types_reduced = intersection(expr_set, types_with_method) + + if len(types_reduced) == 0: + return {"InferenceError"} + + return_types = set() + for item in types_reduced: + item_type = self.context.get_type(item) + method = item_type.get_method(node.id) + for typex in method.tset: + return_types.add(typex) + + return return_types @visitor.when(BlockNode) def visit(self, node, tset): @@ -196,7 +262,8 @@ def visit(self, node, tset): @visitor.when(EqualNode) def visit(self, node, tset): - pass + self.visit(node.left, tset) + self.visit(node.right, tset) @visitor.when(NotNode) def visit(self, node, tset): diff --git a/src/type_checker.py b/src/type_checker.py index c50516619..6bf2dcbb6 100644 --- a/src/type_checker.py +++ b/src/type_checker.py @@ -184,10 +184,6 @@ def visit(self, node, scope): else: typex = self.current_type - if typex == self.context.get_type("Void"): - self.errors.append("Void type cannot dispatch") - return ErrorType() - method = None try: if node.at_type is not None: @@ -195,7 +191,7 @@ def visit(self, node, scope): method = node_at_type.get_method(node.id) if not typex.conforms_to(node_at_type): self.errors.append( - "The static type to the left of @ must conform to the type specified to the right of @ " + f"The static type to the left of @ ({typex.name}) must conform to the type specified to the right of @ ({node_at_type.name}) " ) return ErrorType() else: @@ -224,7 +220,9 @@ def visit(self, node, scope): predicate_type = self.visit(node.if_expr, scope) if predicate_type.name != "Bool" and predicate_type.name != "AUTO_TYPE": - self.errors.append("Expression must be bool") + self.errors.append( + f"Expression after 'if' must be bool, current is {predicate_type.name}" + ) return ErrorType() then_type = self.visit(node.then_expr, scope) @@ -238,8 +236,10 @@ def visit(self, node, scope): condition_type = self.visit(node.condition, scope) bool_type = self.context.get_type("Bool") - if condition_type != bool_type: - self.errors.append("Expression must be bool") + if condition_type != bool_type and condition_type.name != "AUTO_TYPE": + self.errors.append( + f"Expression after 'while' must be bool, current is {condition_type.name}" + ) return ErrorType() return self.context.get_type("Object") @@ -284,10 +284,6 @@ def visit(self, node, scope): @visitor.when(CaseNode) def visit(self, node, scope): self.visit(node.expr, scope) - # typex = self.visit(node.expr, scope) - # if typex == self.context.get_type("Void"): - # self.errors.append("Case expression cannot be Void") - # return ErrorType() current_case_type = None for item in node.case_items: @@ -332,7 +328,9 @@ def visit(self, node, scope): left_type = self.visit(node.left, scope) right_type = self.visit(node.right, scope) - if not left_type.conforms_to(int_type) or not right_type.conforms_to(int_type): + if (left_type != int_type and left_type.name != "AUTO_TYPE") or ( + right_type != int_type and right_type.name != "AUTO_TYPE" + ): self.errors.append(INVALID_OPERATION % (left_type.name, right_type.name)) return int_type @@ -343,7 +341,9 @@ def visit(self, node, scope): left_type = self.visit(node.left, scope) right_type = self.visit(node.right, scope) - if not left_type.conforms_to(int_type) or not right_type.conforms_to(int_type): + if (left_type != int_type and left_type.name != "AUTO_TYPE") or ( + right_type != int_type and right_type.name != "AUTO_TYPE" + ): self.errors.append(INVALID_OPERATION % (left_type.name, right_type.name)) return self.context.get_type("Bool") @@ -359,20 +359,26 @@ def visit(self, node, scope): right_type = self.visit(node.right, scope) if left_type in built_in_types or right_type in built_in_types: - if left_type != right_type: + if ( + left_type != right_type + and left_type.name != "AUTO_TYPE" + and right_type.name != "AUTO_TYPE" + ): self.errors.append( - "Since one of the expressions of '=' operator is of type Int, String or Bool, the other must have the same static type" + f"One of the expressions of '=' operator is of type Int, String or Bool, the other must have the same static type. Left type: {left_type.name}.Right type: {right_type.name}" ) - return self.context.get_type("Void") + return self.context.get_type("Bool") @visitor.when(NotNode) def visit(self, node, scope): bool_type = self.context.get_type("Bool") typex = self.visit(node.expr, scope) - if typex != bool_type: - self.errors.append("Expression must be Bool") + if typex != bool_type and not typex.name == "AUTO_TYPE": + self.errors.append( + f"Expression after 'not' must be Bool, current is {typex.name}" + ) return ErrorType() return bool_type @@ -382,8 +388,10 @@ def visit(self, node, scope): int_type = self.context.get_type("Int") typex = self.visit(node.expr, scope) - if typex != int_type: - self.errors.append("Expression must be Int") + if typex != int_type and not typex.name == "AUTO_TYPE": + self.errors.append( + f"Expression after '~' must be Int, current is {typex.name}" + ) return ErrorType() return int_type diff --git a/src/type_collector.py b/src/type_collector.py index c920a4dd8..6418886ea 100644 --- a/src/type_collector.py +++ b/src/type_collector.py @@ -29,7 +29,6 @@ def visit(self, node): self.context = Context() self.context.types["Object"] = ObjectType() self.context.types["Int"] = IntType() - self.context.types["Void"] = VoidType() self.context.types["String"] = StringType() self.context.types["Bool"] = BoolType() self.context.types["AUTO_TYPE"] = AutoType() diff --git a/test/test_merger.py b/test/test_merger.py new file mode 100644 index 000000000..a20211872 --- /dev/null +++ b/test/test_merger.py @@ -0,0 +1,105 @@ +from run_pipeline import run_pipeline +from src.type_collector import TypeCollector +from src.type_builder import TypeBuilder +from src.type_checker import TypeChecker +from src.tset_builder import TSetBuilder +from src.tsets_reducer import TSetReducer +from src.tset_merger import TSetMerger +from src.cool_visitor import FormatVisitor + + +def test(): + text = """ + + class A { + a : String ; + b : AUTO_TYPE ; + c : AUTO_TYPE <- 0 ; + d : Object <- while c loop c + 1 pool ; *first and second errors* + j : AUTO_TYPE ; + l : AUTO_TYPE ; + fact ( n : AUTO_TYPE ) : AUTO_TYPE { if n < 0 then 1 else n + fact ( n - 1 ) fi } ; + step ( p : AUTO_TYPE ) : AUTO_TYPE { + b <- + { + p + 5 ; + j <- p ; *third error* + p <- false ; + isvoid d ; + + + l @ Point . main ( ) ; + } + } ; + } ; + class Point inherits A { + h : AUTO_TYPE <- "debe ser tipo string" ; + k : AUTO_TYPE ; + main ( ) : AUTO_TYPE { + let i : AUTO_TYPE <- new A in { + isvoid i ; *Puede lanzar error semantico* + } + } ; + ackermann ( m : AUTO_TYPE , n : AUTO_TYPE ) : AUTO_TYPE { + if m < 0 then 1 else + if n < 0 then ackermann ( m - 1 , 1 ) else + ackermann ( m - 1 , ackermann ( m , n - 1 ) ) + fi + fi + } ; + } ; + + """ + + ast = run_pipeline(text) + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + print(errors) + if errors != []: + assert False + + tset_builder = TSetBuilder(context, errors) + tset = tset_builder.visit(ast, None) + + tset_reducer = TSetReducer(context, errors) + reduced_set = tset_reducer.visit(ast, tset) + + tset_merger = TSetMerger(context, errors) + tset_merger.visit(ast, reduced_set) + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + formatter = FormatVisitor() + tree = formatter.visit(ast) + + print("Errors:", errors) + print("Context:") + print(context) + print(reduced_set) + print(tree) + + assert errors == [ + "Expression after 'while' must be bool, current is Object", + 'Operation is not defined between "Object" and "Int".', + 'Cannot convert "Object" into "Int".', + ] diff --git a/test/test_reducer.py b/test/test_reducer.py index 83a48f3a7..0c1ede562 100644 --- a/test/test_reducer.py +++ b/test/test_reducer.py @@ -8,36 +8,46 @@ def test(): text = """ + class A { a : String ; b : AUTO_TYPE ; - c : Int <- 0 ; - d : Object <- while c < 1 loop c + 1 pool ; + c : AUTO_TYPE <- 0 ; + d : Object <- while c loop c + 1 pool ; j : AUTO_TYPE ; l : AUTO_TYPE ; + fact ( n : AUTO_TYPE ) : AUTO_TYPE { if n < 0 then 1 else n + fact ( n - 1 ) fi } ; step ( p : AUTO_TYPE ) : AUTO_TYPE { b <- { p + 5 ; - p <- false ; j <- p ; + p <- false ; isvoid d ; + + + l @ Point . main ( ) ; } } ; - } ; - - class Point inherits A { + } ; + class Point inherits A { h : AUTO_TYPE <- "debe ser tipo string" ; k : AUTO_TYPE ; - step ( p : AUTO_TYPE ) : AUTO_TYPE { k <- if p then new Point else new A fi } ; - main ( ) : Object { + main ( ) : AUTO_TYPE { let i : AUTO_TYPE <- new A in { isvoid i ; *Puede lanzar error semantico* } } ; + ackermann ( m : AUTO_TYPE , n : AUTO_TYPE ) : AUTO_TYPE { + if m < 0 then 1 else + if n < 0 then ackermann ( m - 1 , 1 ) else + ackermann ( m - 1 , ackermann ( m , n - 1 ) ) + fi + fi + } ; } ; + """ - # l <- ~ c ; ast = run_pipeline(text) errors = [] @@ -64,4 +74,4 @@ class Point inherits A { print(context) print(reduced_set) - assert False + assert errors == [] diff --git a/test/test_reducer2.py b/test/test_reducer2.py new file mode 100644 index 000000000..36a4a4982 --- /dev/null +++ b/test/test_reducer2.py @@ -0,0 +1,53 @@ +from run_pipeline import run_pipeline +from src.type_collector import TypeCollector +from src.type_builder import TypeBuilder +from src.type_checker import TypeChecker +from src.tset_builder import TSetBuilder +from src.tsets_reducer import TSetReducer + + +def test(): + text = """ + + class A { + a : String ; + } ; + class Point inherits A { + ackermann ( m : AUTO_TYPE , n : AUTO_TYPE ) : AUTO_TYPE { + if m < 0 then 1 else + if n < 0 then ackermann ( m - 1 , 1 ) else + ackermann ( m - 1 , ackermann ( m , n - 1 ) ) + fi + fi + } ; + + } ; + + """ + + ast = run_pipeline(text) + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + __ = checker.visit(ast, None) + + tset_builder = TSetBuilder(context, errors) + tset = tset_builder.visit(ast, None) + + tset_reducer = TSetReducer(context, errors) + reduced_set = tset_reducer.visit(ast, tset) + + print("Errors:", errors) + print("Context:") + print(context) + print(reduced_set) + + assert errors == [] diff --git a/test/test_reducer3.py b/test/test_reducer3.py new file mode 100644 index 000000000..6e263a003 --- /dev/null +++ b/test/test_reducer3.py @@ -0,0 +1,55 @@ +from run_pipeline import run_pipeline +from src.type_collector import TypeCollector +from src.type_builder import TypeBuilder +from src.type_checker import TypeChecker +from src.tset_builder import TSetBuilder +from src.tsets_reducer import TSetReducer + + +def test(): + text = """ + + class A { + a : String ; + } ; + class Point inherits A { + f ( a : AUTO_TYPE , b : AUTO_TYPE ) : AUTO_TYPE { + if ( a = 1 ) then b else + g ( a + 1 , b / 2 ) + fi + } ; + g ( a : AUTO_TYPE , b : AUTO_TYPE ) : AUTO_TYPE { + if ( b = 1 ) then a else + f ( a / 2 , b + 1 ) + fi + } ; + } ; + + """ + + ast = run_pipeline(text) + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + __ = checker.visit(ast, None) + + tset_builder = TSetBuilder(context, errors) + tset = tset_builder.visit(ast, None) + + tset_reducer = TSetReducer(context, errors) + reduced_set = tset_reducer.visit(ast, tset) + + print("Errors:", errors) + print("Context:") + print(context) + print(reduced_set) + + assert errors == [] diff --git a/test/test_tset_builder.py b/test/test_tset_builder.py index 9ec95de96..082b6da37 100644 --- a/test/test_tset_builder.py +++ b/test/test_tset_builder.py @@ -11,7 +11,7 @@ class A { a : String ; b : Bool ; c : Int <- 0 ; - d : Void <- while c < 1 loop c = c + 1 pool ; + d : Object <- while c < 1 loop c = c + 1 pool ; step ( p : AUTO_TYPE ) : AUTO_TYPE { p . translate ( 1 , 1 ) } ; } ; diff --git a/test/test_type_builder.py b/test/test_type_builder.py index fd2436890..492b481fd 100644 --- a/test/test_type_builder.py +++ b/test/test_type_builder.py @@ -9,7 +9,7 @@ class A { a : String ; b : Bool ; c : Int <- 0 ; - d : Void <- while c < 1 loop c = c + 1 pool ; + d : Object <- while c < 1 loop c = c + 1 pool ; } ; class Point { step ( p : AUTO_TYPE ) : AUTO_TYPE { p . translate ( 1 , 1 ) } ; diff --git a/test/test_type_checker.py b/test/test_type_checker.py index dfa19744a..969d56f6a 100644 --- a/test/test_type_checker.py +++ b/test/test_type_checker.py @@ -10,7 +10,7 @@ class A { a : String ; b : Bool ; c : Int <- 0 ; - d : Void <- while c < 1 loop c = c + 1 pool ; + d : Object <- while c < 1 loop c = c + 1 pool ; step ( p : AUTO_TYPE ) : AUTO_TYPE { p . translate ( 1 , 1 ) } ; } ; From 3cd06de1a94a787cac017b7a9d0587fddae678aa Mon Sep 17 00:00:00 2001 From: Gaby Date: Mon, 30 Nov 2020 06:15:01 -0500 Subject: [PATCH 011/162] Tokenizer rules specified for ply lexer --- src/cool_grammar.py | 4 +- src/lexical_analizer.py | 51 +++++++++ src/main.py | 5 +- src/tokens_rules.py | 235 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 289 insertions(+), 6 deletions(-) create mode 100644 src/lexical_analizer.py create mode 100644 src/tokens_rules.py diff --git a/src/cool_grammar.py b/src/cool_grammar.py index 3ae100d23..637597ead 100644 --- a/src/cool_grammar.py +++ b/src/cool_grammar.py @@ -58,9 +58,7 @@ def define_cool_grammar(print_grammar=False): semi, colon, comma, dot, opar, cpar, ocur, ccur, at, larrow, rarrow = G.Terminals( "; : , . ( ) { } @ <- =>" ) - equal, plus, minus, star, div, less, equal, lesseq, neg = G.Terminals( - "= + - * / < = <= ~" - ) + plus, minus, star, div, less, equal, lesseq, neg = G.Terminals("+ - * / < = <= ~") idx, num, new, string, true, false = G.Terminals("id int new string true false") # productions diff --git a/src/lexical_analizer.py b/src/lexical_analizer.py new file mode 100644 index 000000000..4efef2716 --- /dev/null +++ b/src/lexical_analizer.py @@ -0,0 +1,51 @@ +import ply.lex as lex +import tokens_rules + +lexer = lex.lex(module=tokens_rules) + + +# To use the lexer, you first need to feed it some input text using its input() method. +# After that, repeated calls to token() produce tokens. The following code shows how this +# works: + + +# Test it out +# data = ''' +# 3 + 4 * 10 +# + -20 *2 +# ''' + +data = """ + class Cons inherits List{ + --class Cons super important comment + xcar : Int ; + xcdr : List ; + ascommenterdnsideerdajajajaaquiiiedsacommentjajajaed(): Bool{true}; + isNill () : Bool{ + false}; + + init (hd : Int, tl : List) : Cons{ + { xcar <- "hola \\t helou + sd"; + xcdr <- 1 + 2; + self;} + }; + }; + """ + +# Give the lexer some input +lexer.input(data) + +# Tokenize +while True: + tok = lexer.token() + if not tok: + break # No more input + print(tok) + +# Compute column. +# input is the input text string +# token is a token instance +def find_column(input, token): + line_start = input.rfind('\n', 0, token.lexpos) + 1 + return (token.lexpos - line_start) + 1 \ No newline at end of file diff --git a/src/main.py b/src/main.py index 54cf7486b..f7f4201bd 100644 --- a/src/main.py +++ b/src/main.py @@ -7,7 +7,7 @@ from src.errors import parsing_table_error, Error from src.cmp.evaluation import evaluate_reverse_parse - + def run_pipeline(text): # define grammar @@ -57,5 +57,4 @@ def run_pipeline(text): # print(tree) -# run_pipeline_cmp_tools(text) - +# run_pipeline_cmp_tools(text) \ No newline at end of file diff --git a/src/tokens_rules.py b/src/tokens_rules.py new file mode 100644 index 000000000..b8cd87a41 --- /dev/null +++ b/src/tokens_rules.py @@ -0,0 +1,235 @@ +# https://www.dabeaz.com/ply/ply.html +# file for PLY rules +# import ply.lex as lex + +# Declare the state +states = ( + ('comments','exclusive'), +) + + +# All lexers must provide a list tokens that defines all of the possible token names +# that can be produced by the lexer. +first_tokens = [ + 'SEMI', + 'COLON', + 'COMMA', + 'DOT', + 'OPAR', + 'CPAR', + 'OCUR', + 'CCUR', + 'AT', + 'LARROW', + 'RARROW', + 'PLUS', + 'MINUS', + 'STAR', + 'DIV', + 'LESS', + 'EQUAL', + 'LESSEQUAL', + 'NEG', + 'ID', + 'NUM', + 'STRING', +] + +reserved = { + 'class':'CLASS', + 'inherits':'INHERITS', + 'not':'NOT', + 'isvoid':'ISVOID', + 'let':'LET', + 'in':'IN', + 'if' : 'IF', + 'then' : 'THEN', + 'else' : 'ELSE', + 'fi':'FI', + 'loop':'LOOP', + 'pool':'POOL', + 'case':'CASE', + 'of':'OF', + 'esac':'ESAC', + 'while' : 'WHILE', + 'new' : 'NEW', + 'true' : 'TRUE', + 'false' : 'FALSE' +} + +tokens = first_tokens + list(reserved.values()) + +# Match the first (*. Enter comments state. +def t_comments(t): + r'\(\*' + t.lexer.code_start = t.lexer.lexpos # Record the starting position + t.lexer.level = 1 # Initial level + t.lexer.begin('comments') # Enter 'comments' state + +# # Match the first ". Enter strings state. +# def t_strings(t): +# r'"' +# t.lexer.code_start = t.lexer.lexpos # Record the starting position +# t.lexer.string_list = [] +# t.lexer.begin('strings') # Enter 'strings' state + +# Rules for the strings state +# def t_strings_startsymb(t): +# r'\"' +# t.lexer.level +=1 + +# def t_strings_endsymb(t): +# r'"' +# # t.value = t.lexer.string_list +# t.value = t.lexer.lexdata[t.lexer.code_start:t.lexer.lexpos - 1] +# t.type = "STRING" +# t.lexer.lineno = t.value.count('\n') +# # t.lexer.lineno += t.lexer.lexdata[t.lexer.code_start:t.lexer.lexpos+1].count('\n') +# t.lexer.begin('INITIAL') +# return t + +# # def t_comments_anything(t): +# # r'(?!\(\*|\*\))' + +# # For bad characters, we just skip over it +# def t_strings_error(t): +# t.lexer.skip(1) + +# # EOF handling rule +# def t_strings_eof(t): +# if t.lexer.level > 0:#guardar este error y actuar acorde +# print("Strings can not contain EOF caracter nor cross file boundaries") +# return None + +# Rules for the comments state +# Comments starting symbol +def t_comments_opsymb(t): + r'\(\*' + t.lexer.level +=1 + +# Comments closing symbol +def t_comments_clsymb(t): + r'\*\)' + t.lexer.level -=1 + + if t.lexer.level == 0: + t.value = t.lexer.lexdata[t.lexer.code_start:t.lexer.lexpos+1] + t.lexer.lineno += t.value.count('\n') + t.lexer.begin('INITIAL') + + +# For bad characters. In this case we just skip over everything but (* or *) +def t_comments_error(t): + t.lexer.skip(1) + +# EOF handling rule +def t_comments_eof(t): + if t.lexer.level > 0:#guardar este error y actuar acorde + print("Comments can not cross file boundaries") + return None + +# Rules for initial state (default state) +def t_ID(t): + r'[a-zA-Z_][a-zA-Z_0-9]*' + t.type = reserved.get(t.value,'ID') # Check for reserved words. If it isn't a reserved word is categorized as identifier + return t + +#matching int numbers +def t_NUM(t): + r'\d+' + t.value = int(t.value) + # r'\d+(\.\d*)?' float numbers + # t.value = float(t.value) + return t + +def t_COMMENT1(t): + r'\--.*' + pass + # No return value. Token discarded + + +def t_STRING(t): + # r'\"[^\"]*\"' + r'\"' + string_list = [] + # string_to_append = '' + text = t.lexer.lexdata + initial = t.lexer.lexpos + index = t.lexer.lexpos + final = len(text) + + while(index < final and text[index]!= '"'): + if(text[index] == '\\'): + if(text[index + 1] in ['t','b','f','n']): + # string_to_append+=f'\\{text[index + 1]}' + string_list.append(text[index:index + 2])#\t,\b,\f + elif(text[index + 1] == '\n'):#non scape \n whith \ before + # string_to_append+='\n' + string_list.append('\n') + elif(text[index + 1] == '0'):#null character \0 is not allowed + print("Illegal character \\0 inside string")#do something about it + else: + string_list.append(text[index:index + 2])#]character c: take the character in \c + # string_to_append += text[index + 1] + index += 2 + + elif(text[index] == '\n'):#\n whithout and extra \ is not allowed + print("Illegal character \\n inside string")#do something about it + index += 1 + else: + string_list.append(text[index]) + # string_to_append += text[index + 1] + index += 1 + + if(index == final): + print("String may not cross file boundaries")#do something about it + else: + index+=1 + + t.value = ''.join(string_list) + t.type = 'STRING' + t.lexer.lexpos += index - initial + t.lexer.lineno += text[initial:index+1].count('\n') + # print(t.value) + # print(string_to_append) + return t + + +# Define a rule so we can track line numbers +def t_newline(t): + r'\n+' + t.lexer.lineno += len(t.value) + + +t_SEMI = r';' +t_COLON = r':' +t_COMMA = r',' +t_DOT = r'\.' +t_OPAR = r'\(' +t_CPAR = r'\)' +t_OCUR = r'\{' +t_CCUR = r'\}' +t_AT = r'\@' +t_LARROW = r'<-' +t_RARROW = r'=>' + +t_PLUS = r'\+' +t_MINUS = r'-' +t_STAR = r'\*' +t_DIV = r'/' +t_LESS = r'<' +t_EQUAL = r'=' +t_LESSEQUAL = r'<=' +t_NEG = r'~' + + +# A string containing ignored characters (spaces and tabs) +t_ignore = ' \t' + + + # Error handling rule +def t_error(t): + print("Illegal character '%s'" % t.value[0]) + t.lexer.skip(1) + + From 6c7e2ca85ae6e651835fddace365d09eaad64278 Mon Sep 17 00:00:00 2001 From: Gaby Date: Mon, 30 Nov 2020 14:57:37 -0500 Subject: [PATCH 012/162] Merge Tokenizer --- src/lexical_analizer.py | 79 ++++++----- src/main.py | 50 +++++-- src/shift_reduce_parsers.py | 3 +- src/tokens_rules.py | 265 +++++++++++++++--------------------- 4 files changed, 195 insertions(+), 202 deletions(-) diff --git a/src/lexical_analizer.py b/src/lexical_analizer.py index 4efef2716..02c736362 100644 --- a/src/lexical_analizer.py +++ b/src/lexical_analizer.py @@ -1,10 +1,34 @@ import ply.lex as lex -import tokens_rules +import src.tokens_rules +from src.cmp.utils import Token -lexer = lex.lex(module=tokens_rules) +def tokenize_cool_text(grammar, data, printing=False): + lexer = lex.lex(module=tokens_rules) -# To use the lexer, you first need to feed it some input text using its input() method. + # Give the lexer some input + lexer.input(data) + + fixed_tokens = {t.Name: Token(t.Name, t) for t in grammar.terminals} + tokens = [] + # Tokenize + while True: + tok = lexer.token() + if not tok: + tokens.append(Token("$", grammar.EOF)) + break # No more input + else: + # tokens.append(tok) + try: + tokens.append(fixed_tokens[tok.type]) + except: + tokens.append(fixed_tokens[tok.value]) + if printing: + print(tokens) + return tokens + + +# To use the lexer, you first need to feed it some input text using its input() method. # After that, repeated calls to token() produce tokens. The following code shows how this # works: @@ -15,37 +39,28 @@ # + -20 *2 # ''' -data = """ - class Cons inherits List{ - --class Cons super important comment - xcar : Int ; - xcdr : List ; - ascommenterdnsideerdajajajaaquiiiedsacommentjajajaed(): Bool{true}; - isNill () : Bool{ - false}; - - init (hd : Int, tl : List) : Cons{ - { xcar <- "hola \\t helou - sd"; - xcdr <- 1 + 2; - self;} - }; - }; - """ - -# Give the lexer some input -lexer.input(data) - -# Tokenize -while True: - tok = lexer.token() - if not tok: - break # No more input - print(tok) +# data = """ +# class Cons inherits List{ +# --class Cons super important comment +# xcar : Int ; +# xcdr : List ; +# ascommenterdnsideerdajajajaaquiiiedsacommentjajajaed(): Bool{true}; +# isNill () : Bool{ +# false}; + +# init (hd : Int, tl : List) : Cons{ +# { xcar <- "hola \\t helou +# sd"; +# xcdr <- 1 + 2; +# self;} +# }; +# }; +# """ + # Compute column. # input is the input text string # token is a token instance def find_column(input, token): - line_start = input.rfind('\n', 0, token.lexpos) + 1 - return (token.lexpos - line_start) + 1 \ No newline at end of file + line_start = input.rfind("\n", 0, token.lexpos) + 1 + return (token.lexpos - line_start) + 1 diff --git a/src/main.py b/src/main.py index 0b87d3b0c..e1264d9c1 100644 --- a/src/main.py +++ b/src/main.py @@ -1,4 +1,4 @@ -from src.cool_tokenizer import tokenize_cool_text +from src.lexical_analizer import tokenize_cool_text from src.cool_grammar import define_cool_grammar from src.cool_visitor import FormatVisitor @@ -13,18 +13,19 @@ from src.errors import parsing_table_error, Error from src.cmp.evaluation import evaluate_reverse_parse - + def run_pipeline(text): # define grammar - grammar, idx, num = define_cool_grammar() - - # tokenize text - tokens = tokenize_cool_text(grammar, text, idx, num) + grammar, idx, num = define_cool_grammar() # try: + # tokens = tokenize_cool_text(grammar, text, idx, num) + tokens = tokenize_cool_text(grammar, text) + parser = LR1Parser(grammar) parse, operations = parser([t.token_type for t in tokens]) + # print("\n".join(repr(x) for x in parse)) # print(operations) @@ -63,14 +64,15 @@ def run_pipeline(text): checker = TypeChecker(context, errors) checker.visit(ast, None) - # formatter = FormatVisitor() - # tree = formatter.visit(ast) - # print(tree) - # derivation_list = parser(text) - # derivation_tree_aut = DerivationTree(derivation_list[0], G) - # except Error as err: - # print(err) +# formatter = FormatVisitor() +# tree = formatter.visit(ast) +# print(tree) +# derivation_list = parser(text) +# derivation_tree_aut = DerivationTree(derivation_list[0], G) + +# except Error as err: +# print(err) # def run_pipeline_cmp_tools(text): @@ -96,4 +98,24 @@ def run_pipeline(text): # print(tree) -# run_pipeline_cmp_tools(text) \ No newline at end of file +# run_pipeline_cmp_tools(text) +data = """ + class Cons inherits List { + xcar : Int ; + xcdr : List ; + + isNill ( ) : Bool { + false + } ; + + init ( hd : Int , tl : List ) : Cons { + { + xcar <- hd ; + xcdr <- tl ; + self ; + } + } ; + } ; + """ + +run_pipeline(data) diff --git a/src/shift_reduce_parsers.py b/src/shift_reduce_parsers.py index 80b644e5b..c05a00ec4 100644 --- a/src/shift_reduce_parsers.py +++ b/src/shift_reduce_parsers.py @@ -5,7 +5,7 @@ ) from src.methods import compute_firsts, compute_local_first, compute_follows from src.cmp.automata import State -from src.errors import shift_reduce_error, invalid_sentence_error +from src.rors import shift_reduce_error, invalid_sentence_error class ShiftReduceParser: @@ -38,6 +38,7 @@ def __call__(self, w): # Detect error try: action, tag = self.action[state, lookahead] + except KeyError: raise invalid_sentence_error( w, diff --git a/src/tokens_rules.py b/src/tokens_rules.py index b8cd87a41..976f03ff4 100644 --- a/src/tokens_rules.py +++ b/src/tokens_rules.py @@ -1,156 +1,128 @@ # https://www.dabeaz.com/ply/ply.html # file for PLY rules -# import ply.lex as lex # Declare the state -states = ( - ('comments','exclusive'), -) +states = (("comments", "exclusive"),) # All lexers must provide a list tokens that defines all of the possible token names # that can be produced by the lexer. first_tokens = [ - 'SEMI', - 'COLON', - 'COMMA', - 'DOT', - 'OPAR', - 'CPAR', - 'OCUR', - 'CCUR', - 'AT', - 'LARROW', - 'RARROW', - 'PLUS', - 'MINUS', - 'STAR', - 'DIV', - 'LESS', - 'EQUAL', - 'LESSEQUAL', - 'NEG', - 'ID', - 'NUM', - 'STRING', + "larrow", + "rarrow", + "lessequal", + "id", + "int", + "string", ] reserved = { - 'class':'CLASS', - 'inherits':'INHERITS', - 'not':'NOT', - 'isvoid':'ISVOID', - 'let':'LET', - 'in':'IN', - 'if' : 'IF', - 'then' : 'THEN', - 'else' : 'ELSE', - 'fi':'FI', - 'loop':'LOOP', - 'pool':'POOL', - 'case':'CASE', - 'of':'OF', - 'esac':'ESAC', - 'while' : 'WHILE', - 'new' : 'NEW', - 'true' : 'TRUE', - 'false' : 'FALSE' + "class": "class", + "inherits": "inherits", + "not": "not", + "isvoid": "isvoid", + "let": "let", + "in": "in", + "if": "if", + "then": "then", + "else": "else", + "fi": "fi", + "loop": "loop", + "pool": "pool", + "case": "case", + "of": "of", + "esac": "esac", + "while": "while", + "new": "new", + "true": "true", + "false": "false", } - + +literals = [ + ";", + ":", + ",", + ".", + "(", + ")", + "{", + "}", + "@", + "+", + "-", + "*", + "/", + "<", + "=", + "~", +] + tokens = first_tokens + list(reserved.values()) # Match the first (*. Enter comments state. def t_comments(t): - r'\(\*' - t.lexer.code_start = t.lexer.lexpos # Record the starting position - t.lexer.level = 1 # Initial level - t.lexer.begin('comments') # Enter 'comments' state - -# # Match the first ". Enter strings state. -# def t_strings(t): -# r'"' -# t.lexer.code_start = t.lexer.lexpos # Record the starting position -# t.lexer.string_list = [] -# t.lexer.begin('strings') # Enter 'strings' state - -# Rules for the strings state -# def t_strings_startsymb(t): -# r'\"' -# t.lexer.level +=1 - -# def t_strings_endsymb(t): -# r'"' -# # t.value = t.lexer.string_list -# t.value = t.lexer.lexdata[t.lexer.code_start:t.lexer.lexpos - 1] -# t.type = "STRING" -# t.lexer.lineno = t.value.count('\n') -# # t.lexer.lineno += t.lexer.lexdata[t.lexer.code_start:t.lexer.lexpos+1].count('\n') -# t.lexer.begin('INITIAL') -# return t - -# # def t_comments_anything(t): -# # r'(?!\(\*|\*\))' - -# # For bad characters, we just skip over it -# def t_strings_error(t): -# t.lexer.skip(1) - -# # EOF handling rule -# def t_strings_eof(t): -# if t.lexer.level > 0:#guardar este error y actuar acorde -# print("Strings can not contain EOF caracter nor cross file boundaries") -# return None + r"\(\*" + t.lexer.code_start = t.lexer.lexpos # Record the starting position + t.lexer.level = 1 # Initial level + t.lexer.begin("comments") # Enter 'comments' state + # Rules for the comments state # Comments starting symbol -def t_comments_opsymb(t): - r'\(\*' - t.lexer.level +=1 +def t_comments_opsymb(t): + r"\(\*" + t.lexer.level += 1 + # Comments closing symbol def t_comments_clsymb(t): - r'\*\)' - t.lexer.level -=1 + r"\*\)" + t.lexer.level -= 1 if t.lexer.level == 0: - t.value = t.lexer.lexdata[t.lexer.code_start:t.lexer.lexpos+1] - t.lexer.lineno += t.value.count('\n') - t.lexer.begin('INITIAL') + t.value = t.lexer.lexdata[t.lexer.code_start : t.lexer.lexpos + 1] + t.lexer.lineno += t.value.count("\n") + t.lexer.begin("INITIAL") # For bad characters. In this case we just skip over everything but (* or *) def t_comments_error(t): t.lexer.skip(1) - + + # EOF handling rule def t_comments_eof(t): - if t.lexer.level > 0:#guardar este error y actuar acorde + if t.lexer.level > 0: # guardar este error y actuar acorde print("Comments can not cross file boundaries") return None - + + # Rules for initial state (default state) -def t_ID(t): - r'[a-zA-Z_][a-zA-Z_0-9]*' - t.type = reserved.get(t.value,'ID') # Check for reserved words. If it isn't a reserved word is categorized as identifier - return t - -#matching int numbers -def t_NUM(t): - r'\d+' +def t_id(t): + r"[a-zA-Z_][a-zA-Z_0-9]*" + t.type = reserved.get( + t.value, "id" + ) # Check for reserved words. If it isn't a reserved word is categorized as identifier + return t + + +# matching int numbers +def t_int(t): + r"\d+" t.value = int(t.value) # r'\d+(\.\d*)?' float numbers - # t.value = float(t.value) + # t.value = float(t.value) return t -def t_COMMENT1(t): - r'\--.*' + +def t_comment1(t): + r"\--.*" pass # No return value. Token discarded -def t_STRING(t): - # r'\"[^\"]*\"' - r'\"' +def t_string(t): + r"\"" string_list = [] # string_to_append = '' text = t.lexer.lexdata @@ -158,38 +130,40 @@ def t_STRING(t): index = t.lexer.lexpos final = len(text) - while(index < final and text[index]!= '"'): - if(text[index] == '\\'): - if(text[index + 1] in ['t','b','f','n']): + while index < final and text[index] != '"': + if text[index] == "\\": + if text[index + 1] in ["t", "b", "f", "n"]: # string_to_append+=f'\\{text[index + 1]}' - string_list.append(text[index:index + 2])#\t,\b,\f - elif(text[index + 1] == '\n'):#non scape \n whith \ before + string_list.append(text[index : index + 2]) # \t,\b,\f + elif text[index + 1] == "\n": # non scape \n whith \ before # string_to_append+='\n' - string_list.append('\n') - elif(text[index + 1] == '0'):#null character \0 is not allowed - print("Illegal character \\0 inside string")#do something about it + string_list.append("\n") + elif text[index + 1] == "0": # null character \0 is not allowed + print("Illegal character \\0 inside string") # do something about it else: - string_list.append(text[index:index + 2])#]character c: take the character in \c + string_list.append( + text[index : index + 2] + ) # ]character c: take the character in \c # string_to_append += text[index + 1] index += 2 - - elif(text[index] == '\n'):#\n whithout and extra \ is not allowed - print("Illegal character \\n inside string")#do something about it + + elif text[index] == "\n": # \n whithout and extra \ is not allowed + print("Illegal character \\n inside string") # do something about it index += 1 else: string_list.append(text[index]) # string_to_append += text[index + 1] index += 1 - if(index == final): - print("String may not cross file boundaries")#do something about it + if index == final: + print("String may not cross file boundaries") # do something about it else: - index+=1 + index += 1 - t.value = ''.join(string_list) - t.type = 'STRING' + t.value = "".join(string_list) + t.type = "string" t.lexer.lexpos += index - initial - t.lexer.lineno += text[initial:index+1].count('\n') + t.lexer.lineno += text[initial : index + 1].count("\n") # print(t.value) # print(string_to_append) return t @@ -197,39 +171,20 @@ def t_STRING(t): # Define a rule so we can track line numbers def t_newline(t): - r'\n+' + r"\n+" t.lexer.lineno += len(t.value) - -t_SEMI = r';' -t_COLON = r':' -t_COMMA = r',' -t_DOT = r'\.' -t_OPAR = r'\(' -t_CPAR = r'\)' -t_OCUR = r'\{' -t_CCUR = r'\}' -t_AT = r'\@' -t_LARROW = r'<-' -t_RARROW = r'=>' - -t_PLUS = r'\+' -t_MINUS = r'-' -t_STAR = r'\*' -t_DIV = r'/' -t_LESS = r'<' -t_EQUAL = r'=' -t_LESSEQUAL = r'<=' -t_NEG = r'~' + +t_larrow = r"<-" +t_rarrow = r"=>" +t_lessequal = r"<=" # A string containing ignored characters (spaces and tabs) -t_ignore = ' \t' - +t_ignore = " \t" + - # Error handling rule +# Error handling rule def t_error(t): print("Illegal character '%s'" % t.value[0]) t.lexer.skip(1) - - From 5c5ca0da5054735c9beb5f90cf58fbbb46a973bd Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Mon, 30 Nov 2020 17:34:49 -0500 Subject: [PATCH 013/162] Add visual and tokenizer --- main.py | 117 ++++++++++++++++++++++++ src/cmp/semantic.py | 2 + src/cool_grammar.py | 6 +- src/cool_visitor.py | 176 ++++++++++++++++++++++++++++++++++++ src/errors.py | 9 ++ src/lexical_analizer.py | 77 +++++++--------- src/main.py | 121 ------------------------- src/shift_reduce_parsers.py | 2 +- src/tokens_rules.py | 36 ++++++-- src/tset.py | 4 +- src/ui.py | 127 ++++++++++++++++++++++++++ test.py | 17 ++++ test/run_pipeline.py | 9 +- test/test_merger.py | 16 ++-- test/test_parser2.py | 2 +- test/test_parser3.py | 2 +- test/test_parser4.py | 1 + test/test_parser6.py | 3 +- test/test_reducer.py | 2 +- test/test_tset_builder.py | 2 +- test/test_type_builder.py | 2 +- test/test_type_checker.py | 2 +- test/test_type_collector.py | 2 +- 23 files changed, 542 insertions(+), 195 deletions(-) create mode 100644 main.py delete mode 100644 src/main.py create mode 100644 src/ui.py create mode 100644 test.py diff --git a/main.py b/main.py new file mode 100644 index 000000000..eb394a959 --- /dev/null +++ b/main.py @@ -0,0 +1,117 @@ +from src.lexical_analizer import tokenize_cool_text +from src.cool_grammar import define_cool_grammar +from src.cool_visitor import FormatVisitorST + +from src.type_collector import TypeCollector +from src.type_builder import TypeBuilder +from src.type_checker import TypeChecker +from src.tset_builder import TSetBuilder +from src.tsets_reducer import TSetReducer +from src.tset_merger import TSetMerger + +from src.shift_reduce_parsers import LR1Parser, DerivationTree +from src.errors import parsing_table_error, Error + +from src.cmp.evaluation import evaluate_reverse_parse + +import streamlit as st +from src.ui import print_array, print_grammar, print_tset + +st.sidebar.header("About") +st.sidebar.subheader("Segundo Proyecto de Compilacion: Cool Intrepreter") +st.sidebar.text("Amalia Ibarra Rodriguez") +st.sidebar.text("Gabriela B. Martinez Giraldo") +st.sidebar.text("Grupo: C-312") +st.sidebar.text("Curso: 2019-2020") + +""" # Cool Intrepreter """ + +data = st.text_area("Type some code", "") +run_analysis = st.button("compile", "") + + +initial_ast = "Initial_AST" +final_ast = "Final_AST" +reduced_sets = "ReducedSets" + + +selected_options = st.multiselect( + "Select what to see", (initial_ast, final_ast, reduced_sets), +) + + +def run_pipeline(text): + # define grammar + grammar, idx, string, num = define_cool_grammar() + + try: + tokens = tokenize_cool_text(grammar, idx, string, num, text) + + parser = LR1Parser(grammar) + parse, operations = parser([t.token_type for t in tokens]) + + # print("\n".join(repr(x) for x in parse)) + # print(operations) + + ast = evaluate_reverse_parse(parse, operations, tokens) + formatter = FormatVisitorST() + tree = formatter.visit(ast) + + if initial_ast in selected_options: + st.header("Initial Tree:") + print_array(tree) + + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + if errors != []: + st.header("Sorry we found some errors in your code:") + print_array(errors) + else: + tset_builder = TSetBuilder(context, errors) + tset = tset_builder.visit(ast, None) + + tset_reducer = TSetReducer(context, errors) + reduced_set = tset_reducer.visit(ast, tset) + + tset_merger = TSetMerger(context, errors) + tset_merger.visit(ast, reduced_set) + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + if reduced_sets in selected_options: + st.header("Reduced Sets") + print_tset(reduced_set) + + if final_ast in selected_options: + tree = formatter.visit(ast) + st.header("Final Tree:") + print_array(tree) + + except Error as error: + st.header("Sorry an error occur while tokenizing text:") + st.write(str(error)) + + +if run_analysis: + run_pipeline(data) + diff --git a/src/cmp/semantic.py b/src/cmp/semantic.py index f4fb7d21a..e28ae6c0d 100644 --- a/src/cmp/semantic.py +++ b/src/cmp/semantic.py @@ -52,6 +52,8 @@ def __init__(self, name: str): def set_parent(self, parent): if self.parent is not None: raise SemanticError(f"Parent type is already set for {self.name}.") + if parent.name == "String" or parent.name == "Bool" or parent.name == "Int": + raise SemanticError(f"Is not possible to inherit from {parent.name}") self.parent = parent def get_attribute(self, name: str): diff --git a/src/cool_grammar.py b/src/cool_grammar.py index 637597ead..fc3035214 100644 --- a/src/cool_grammar.py +++ b/src/cool_grammar.py @@ -58,7 +58,9 @@ def define_cool_grammar(print_grammar=False): semi, colon, comma, dot, opar, cpar, ocur, ccur, at, larrow, rarrow = G.Terminals( "; : , . ( ) { } @ <- =>" ) - plus, minus, star, div, less, equal, lesseq, neg = G.Terminals("+ - * / < = <= ~") + equal, plus, minus, star, div, less, equal, lesseq, neg = G.Terminals( + "= + - * / < = <= ~" + ) idx, num, new, string, true, false = G.Terminals("id int new string true false") # productions @@ -175,4 +177,4 @@ def define_cool_grammar(print_grammar=False): if print_grammar: print(G) - return (G, idx, num) + return (G, idx, string, num) diff --git a/src/cool_visitor.py b/src/cool_visitor.py index a1f04dc75..ec2beb97c 100644 --- a/src/cool_visitor.py +++ b/src/cool_visitor.py @@ -159,3 +159,179 @@ def visit(self, node, tabs=0): expr = self.visit(node.expr, tabs + 1) return f"{ans}\n{expr}" + +class FormatVisitorST(object): + tree = [] + + @visitor.on("node") + def visit(self, node, tabs=0): + pass + + @visitor.when(ProgramNode) + def visit(self, node, tabs=0): + ans = "\\__\\__" * tabs + f"\\__ProgramNode [ ... ]" + self.tree.append(ans) + for child in node.declarations: + self.visit(child, tabs + 1) + return self.tree + + @visitor.when(ClassDeclarationNode) + def visit(self, node, tabs=0): + parent = "" if node.parent is None else f"inherits {node.parent}" + ans = ( + "\\__\\__" * tabs + + f"\\__ClassDeclarationNode: class {node.id} {parent} {{ ... }}" + ) + self.tree.append(ans) + for child in node.features: + self.visit(child, tabs + 1) + return + + @visitor.when(AttrDeclarationNode) + def visit(self, node, tabs=0): + ans = ( + "\\__\\__" * tabs + + f"\\__AttrDeclarationNode: {node.id} : {node.type} <- " + ) + exp = "\\__\\__" * (tabs + 1) + "\\__NONE" + self.tree.append(ans) + if not node.init_exp is None: + self.visit(node.init_exp, tabs + 1) + else: + self.tree.append(exp) + + return + + @visitor.when(VarDeclarationNode) + def visit(self, node, tabs=0): + ans = ( + "\\__\\__" * tabs + + f"\\__VarDeclarationNode: {node.id} : {node.type} <- " + ) + expr = "\\__\\__" * (tabs + 1) + "\\__NONE" + self.tree.append(ans) + + if not node.expr is None: + expr = self.visit(node.expr, tabs + 1) + self.tree.append(expr) + + return + + @visitor.when(AssignNode) + def visit(self, node, tabs=0): + ans = "\\__\\__" * tabs + f"\\__AssignNode: {node.id} <- " + self.tree.append(ans) + self.visit(node.expr, tabs + 1) + return + + @visitor.when(FuncDeclarationNode) + def visit(self, node, tabs=0): + params = ", ".join(":".join(param) for param in node.params) + ans = ( + "\\__\\__" * tabs + + f"\\__FuncDeclarationNode: {node.id}({params}) : {node.type} -> " + ) + self.tree.append(ans) + self.visit(node.body, tabs + 1) + return + + @visitor.when(BinaryNode) + def visit(self, node, tabs=0): + ans = "\\__\\__" * tabs + f"\\__ {node.__class__.__name__} " + self.tree.append(ans) + self.visit(node.left, tabs + 1) + self.visit(node.right, tabs + 1) + return + + @visitor.when(AtomicNode) + def visit(self, node, tabs=0): + ans = "\\__\\__" * tabs + f"\\__ {node.__class__.__name__}: {node.lex}" + self.tree.append(ans) + return + + @visitor.when(UnaryNode) + def visit(self, node, tabs=0): + class_name = node.__class__.__name__.split("Node")[0] + ans = "\\__\\__" * tabs + f"\\__ {node.__class__.__name__}: {class_name} " + self.tree.append(ans) + self.visit(node.expr, tabs + 1) + return + + @visitor.when(CallNode) + def visit(self, node, tabs=0): + if not node.obj is None: + if not node.at_type is None: + ans = ( + "\\__\\__" * tabs + + f"\\__CallNode: @{node.at_type}.{node.id}(, ..., )" + ) + else: + ans = ( + "\\__\\__" * tabs + + f"\\__CallNode: .{node.id}(, ..., )" + ) + self.tree.append(ans) + self.visit(node.obj, tabs + 1) + else: + ans = "\\__\\__" * tabs + f"\\__CallNode: {node.id}(, ..., )" + self.tree.append(ans) + for arg in node.args: + self.visit(arg, tabs + 1) + return + + @visitor.when(InstantiateNode) + def visit(self, node, tabs=0): + ans = "\\__\\__" * tabs + f"\\__ InstantiateNode: new {node.lex}()" + self.tree.append(ans) + return + + @visitor.when(BlockNode) + def visit(self, node, tabs=0): + ans = "\\__\\__" * tabs + f"\\__BlockNode: {{; ... ;}}" + self.tree.append(ans) + for child in node.expression_list: + self.visit(child, tabs + 1) + return + + @visitor.when(IfNode) + def visit(self, node, tabs=0): + ans = "\\__\\__" * tabs + f"\\__IfNode: if then else fi" + self.tree.append(ans) + self.visit(node.if_expr, tabs + 1) + self.visit(node.then_expr, tabs + 1) + self.visit(node.else_expr, tabs + 1) + return + + @visitor.when(WhileNode) + def visit(self, node, tabs=0): + ans = "\\__\\__" * tabs + f"\\__WhileNode: while loop pool" + self.tree.append(ans) + self.visit(node.condition, tabs + 1) + self.visit(node.body, tabs + 1) + return + + @visitor.when(LetNode) + def visit(self, node, tabs=0): + ans = "\\__\\__" * tabs + f"\\__LetNode: let in " + self.tree.append(ans) + for child in node.identifiers: + self.visit(child, tabs + 1) + self.visit(node.body, tabs + 1) + return + + @visitor.when(CaseNode) + def visit(self, node, tabs=0): + ans = "\\__\\__" * tabs + f"\\__LetNode: case of esac" + self.tree.append(ans) + self.visit(node.expr, tabs + 1) + for child in node.case_items: + self.visit(child, tabs + 1) + return + + @visitor.when(CaseItemNode) + def visit(self, node, tabs=0): + ans = "\\__\\__" * tabs + f"\\__CaseItemNode: {node.id} : {node.type} => ;" + self.tree.append(ans) + self.visit(node.expr, tabs + 1) + return + diff --git a/src/errors.py b/src/errors.py index 2dbf47918..14c9922a5 100644 --- a/src/errors.py +++ b/src/errors.py @@ -3,6 +3,15 @@ class Error(Exception): pass +class tokenizer_error(Error): + "raised when tokenizer got unespected sequences of characters" + + def __init__(self, text, line): + Error.__init__( + self, f"Got {text} while analizing line {line}", + ) + + class parsing_table_error(Error): "raised when T[X,t] possess more than one production" diff --git a/src/lexical_analizer.py b/src/lexical_analizer.py index 02c736362..a0e3a9a1c 100644 --- a/src/lexical_analizer.py +++ b/src/lexical_analizer.py @@ -1,15 +1,35 @@ import ply.lex as lex -import src.tokens_rules +import src.tokens_rules as tokens_rules from src.cmp.utils import Token -def tokenize_cool_text(grammar, data, printing=False): +def pprint_tokens(tokens): + indent = 0 + pending = [] + for token in tokens: + pending.append(token) + if token.lex in {"{", "}", ";"}: + if token.lex == "}": + indent -= 1 + print(" " * indent + " ".join(str(t.token_type) for t in pending)) + pending.clear() + if token.lex == "{": + indent += 1 + print(" ".join([str(t.token_type) for t in pending])) + + +def tokenize_cool_text(grammar, idx, string, num, data, printing=False): lexer = lex.lex(module=tokens_rules) # Give the lexer some input lexer.input(data) - fixed_tokens = {t.Name: Token(t.Name, t) for t in grammar.terminals} + fixed_tokens = { + t.Name: Token(t.Name, t) + for t in grammar.terminals + if t not in {idx, string, num} + } + tokens = [] # Tokenize while True: @@ -18,49 +38,20 @@ def tokenize_cool_text(grammar, data, printing=False): tokens.append(Token("$", grammar.EOF)) break # No more input else: - # tokens.append(tok) try: tokens.append(fixed_tokens[tok.type]) except: - tokens.append(fixed_tokens[tok.value]) + try: # for <=, ->, <- + tokens.append(fixed_tokens[tok.value]) + except: + if tok.type == "string": + tokens.append(Token(tok.value, string)) + elif tok.type == "id": + tokens.append(Token(tok.value, idx)) + else: + tokens.append(Token(tok.value, num)) + if printing: - print(tokens) + pprint_tokens(tokens) return tokens - -# To use the lexer, you first need to feed it some input text using its input() method. -# After that, repeated calls to token() produce tokens. The following code shows how this -# works: - - -# Test it out -# data = ''' -# 3 + 4 * 10 -# + -20 *2 -# ''' - -# data = """ -# class Cons inherits List{ -# --class Cons super important comment -# xcar : Int ; -# xcdr : List ; -# ascommenterdnsideerdajajajaaquiiiedsacommentjajajaed(): Bool{true}; -# isNill () : Bool{ -# false}; - -# init (hd : Int, tl : List) : Cons{ -# { xcar <- "hola \\t helou -# sd"; -# xcdr <- 1 + 2; -# self;} -# }; -# }; -# """ - - -# Compute column. -# input is the input text string -# token is a token instance -def find_column(input, token): - line_start = input.rfind("\n", 0, token.lexpos) + 1 - return (token.lexpos - line_start) + 1 diff --git a/src/main.py b/src/main.py deleted file mode 100644 index e1264d9c1..000000000 --- a/src/main.py +++ /dev/null @@ -1,121 +0,0 @@ -from src.lexical_analizer import tokenize_cool_text -from src.cool_grammar import define_cool_grammar -from src.cool_visitor import FormatVisitor - -from src.type_collector import TypeCollector -from src.type_builder import TypeBuilder -from src.type_checker import TypeChecker -from src.tset_builder import TSetBuilder -from src.tsets_reducer import TSetReducer -from src.tset_merger import TSetMerger - -from src.shift_reduce_parsers import LR1Parser, DerivationTree -from src.errors import parsing_table_error, Error - -from src.cmp.evaluation import evaluate_reverse_parse - - -def run_pipeline(text): - # define grammar - grammar, idx, num = define_cool_grammar() - - # try: - # tokens = tokenize_cool_text(grammar, text, idx, num) - tokens = tokenize_cool_text(grammar, text) - - parser = LR1Parser(grammar) - parse, operations = parser([t.token_type for t in tokens]) - - # print("\n".join(repr(x) for x in parse)) - # print(operations) - - ast = evaluate_reverse_parse(parse, operations, tokens) - - errors = [] - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - tset_builder = TSetBuilder(context, errors) - tset = tset_builder.visit(ast, None) - - tset_reducer = TSetReducer(context, errors) - reduced_set = tset_reducer.visit(ast, tset) - - tset_merger = TSetMerger(context, errors) - tset_merger.visit(ast, reduced_set) - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - -# formatter = FormatVisitor() -# tree = formatter.visit(ast) -# print(tree) -# derivation_list = parser(text) -# derivation_tree_aut = DerivationTree(derivation_list[0], G) - -# except Error as err: -# print(err) - - -# def run_pipeline_cmp_tools(text): -# # only for testing -# # define grammar -# grammar, idx, num = define_cool_grammar() - -# # tokenizer -# tokens = tokenize_cool_text(grammar, text, idx, num) - -# # lexical an -# from src.cmp.tools.parsing import LR1Parser - -# parser = LR1Parser(grammar) -# parse, operations = parser([t.token_type for t in tokens], get_shift_reduce=True) -# print("\n".join(repr(x) for x in parse)) -# # print(operations) - -# ast = evaluate_reverse_parse(parse, operations, tokens) - -# formatter = FormatVisitor() -# tree = formatter.visit(ast) -# print(tree) - - -# run_pipeline_cmp_tools(text) -data = """ - class Cons inherits List { - xcar : Int ; - xcdr : List ; - - isNill ( ) : Bool { - false - } ; - - init ( hd : Int , tl : List ) : Cons { - { - xcar <- hd ; - xcdr <- tl ; - self ; - } - } ; - } ; - """ - -run_pipeline(data) diff --git a/src/shift_reduce_parsers.py b/src/shift_reduce_parsers.py index c05a00ec4..3501302b1 100644 --- a/src/shift_reduce_parsers.py +++ b/src/shift_reduce_parsers.py @@ -5,7 +5,7 @@ ) from src.methods import compute_firsts, compute_local_first, compute_follows from src.cmp.automata import State -from src.rors import shift_reduce_error, invalid_sentence_error +from src.errors import shift_reduce_error, invalid_sentence_error class ShiftReduceParser: diff --git a/src/tokens_rules.py b/src/tokens_rules.py index 976f03ff4..b00583675 100644 --- a/src/tokens_rules.py +++ b/src/tokens_rules.py @@ -1,7 +1,17 @@ # https://www.dabeaz.com/ply/ply.html # file for PLY rules -# Declare the state +from src.errors import tokenizer_error + + +# def find_column(input, lexpos): +# # line_start = input.rfind("\n", 0, lexpos) + 1 +# # return (lexpos - line_start) + 1 +# line_numbers = input.rfind("\n", 0, lexpos) + 1 +# return (lexpos // line_numbers) + (lexpos % line_numbers) + + +# Declare the states states = (("comments", "exclusive"),) @@ -93,7 +103,8 @@ def t_comments_error(t): # EOF handling rule def t_comments_eof(t): if t.lexer.level > 0: # guardar este error y actuar acorde - print("Comments can not cross file boundaries") + print(f"code_start{t.lexer.code_start}") + raise tokenizer_error("Comments can not cross file boundaries", t.lexer.lineno) return None @@ -124,7 +135,6 @@ def t_comment1(t): def t_string(t): r"\"" string_list = [] - # string_to_append = '' text = t.lexer.lexdata initial = t.lexer.lexpos index = t.lexer.lexpos @@ -139,7 +149,11 @@ def t_string(t): # string_to_append+='\n' string_list.append("\n") elif text[index + 1] == "0": # null character \0 is not allowed - print("Illegal character \\0 inside string") # do something about it + # print("Illegal character \\0 inside string") # do something about it + raise tokenizer_error( + "Illegal character \\0 inside string", + t.lexer.lineno + text[initial : index + 1].count("\n"), + ) else: string_list.append( text[index : index + 2] @@ -148,7 +162,11 @@ def t_string(t): index += 2 elif text[index] == "\n": # \n whithout and extra \ is not allowed - print("Illegal character \\n inside string") # do something about it + # print("Illegal character \\n inside string") # do something about it + raise tokenizer_error( + "Illegal character \\n inside string", + t.lexer.lineno + text[initial : index + 1].count("\n"), + ) index += 1 else: string_list.append(text[index]) @@ -156,7 +174,11 @@ def t_string(t): index += 1 if index == final: - print("String may not cross file boundaries") # do something about it + # print("String may not cross file boundaries") # do something about it + raise tokenizer_error( + "String may not cross file boundaries", + t.lexer.lineno + text[initial : index + 1].count("\n"), + ) else: index += 1 @@ -186,5 +208,5 @@ def t_newline(t): # Error handling rule def t_error(t): - print("Illegal character '%s'" % t.value[0]) + raise tokenizer_error(f"Illegal character {t.value[0]}", t.lexer.lineno) t.lexer.skip(1) diff --git a/src/tset.py b/src/tset.py index 684b58d74..4258080d4 100644 --- a/src/tset.py +++ b/src/tset.py @@ -22,14 +22,14 @@ def __str__(self): for key, value in self.locals.items(): output += "\t" + str(key) + ":" + str(value) + "\n" - for key, chil in self.children.items(): + for key, child in self.children.items(): output += "\n" try: output += key.id + "--->" except AttributeError: output += "let or case --->" output += "\n" - output += str(chil) + output += str(child) return output def clone(self): diff --git a/src/ui.py b/src/ui.py new file mode 100644 index 000000000..beb66f666 --- /dev/null +++ b/src/ui.py @@ -0,0 +1,127 @@ +from src.cmp.pycompiler import ( + Symbol, + NonTerminal, + Terminal, + EOF, + Sentence, + SentenceList, + Epsilon, + Production, + Grammar, +) +import graphviz +import streamlit as st +from pandas import DataFrame +from src.shift_reduce_parsers import ShiftReduceParser + + +def print_array(array): + for item in array: + st.write(item) + + +def print_tset(tset): + output = [] + + for key, value in tset.locals.items(): + # output.append("\_" + str(key) + ":" + str(value) + "\n") + # output.append(f"\\__ {key} : {value} aaa") + + st.write("\\__" + str(key) + ":" + str(value)) + for key, child in tset.children.items(): + # output += "\n" + try: + # output.append(key.id + "--->") + # output.append(f"{key.id}---> eee") + st.write(key.id + "--->") + except AttributeError: + # output.append("let or case --->iii") + st.write("let or case --->") + # output += "\n" + # output.append(str(chil)) + # output.append(f"{print_tset(child)} ooo") + print_tset(child) + + # st.write(str(chil)) + # for item in output: + # st.write(item) + + +def print_grammar(G): + st.subheader("Simbolo distinguido") + st.write(G.startSymbol.Name) + + st.subheader("Terminales") + for t in G.terminals: + st.write(t.Name) + + st.subheader("No Terminales") + for nt in G.nonTerminals: + st.write(nt.Name) + + st.subheader("Producciones") + for p in G.Productions: + st.write(p.__repr__()) + + +def table_to_dataframe_ll(table): + d = {} + for (state, symbol), value in table.items(): + # value = encode_value(value) + try: + d[state][symbol] = value.__repr__() + except KeyError: + d[state] = {symbol: value.__repr__()} + + return DataFrame.from_dict(d, orient="index", dtype=str) + + +def encode_value(value): + try: + action, tag = value + if action == ShiftReduceParser.SHIFT: + return "S" + str(tag) + elif action == ShiftReduceParser.REDUCE: + return repr(tag) + elif action == ShiftReduceParser.OK: + return action + else: + return value + except TypeError: + return value + + +def table_to_dataframe(table): + d = {} + for (state, symbol), value in table.items(): + value = encode_value(value) + try: + d[state][symbol] = value + except KeyError: + d[state] = {symbol: value} + + return DataFrame.from_dict(d, orient="index", dtype=str) + + +# def print_automaton(nfa): +# graph = graphviz.Digraph() + +# if nfa.start not in nfa.finals: +# graph.attr("node", shape="diamond") +# graph.node(str(nfa.start)) + +# graph.attr("node", shape="doublecircle") +# for f in nfa.finals: +# graph.node(str(f)) + +# graph.attr("node", shape="circle") +# for (start, tran), destination in nfa.map.items(): +# tran = "e" if tran == "" else tran +# for state in destination: +# if tran == "%" or tran == "none": +# continue +# graph.edge( +# str(start), str(state), label=tran, +# ) + +# st.graphviz_chart(graph) diff --git a/test.py b/test.py new file mode 100644 index 000000000..0d18fc788 --- /dev/null +++ b/test.py @@ -0,0 +1,17 @@ +data = """ +class Cons { +xcar : Int ; +xcdr : String ; + +isNill ( ) : Bool { + false +} ; + +init ( hd : Int , tl : String ) : String { + { + xcar <- (* ; + xcdr <- tl ; + } +} ; +} ; + """ diff --git a/test/run_pipeline.py b/test/run_pipeline.py index e2f00737b..cd653c2ab 100644 --- a/test/run_pipeline.py +++ b/test/run_pipeline.py @@ -1,4 +1,5 @@ -from src.cool_tokenizer import tokenize_cool_text +# from src.cool_tokenizer import tokenize_cool_text +from src.lexical_analizer import tokenize_cool_text from src.cool_grammar import define_cool_grammar from src.cool_visitor import FormatVisitor @@ -10,10 +11,12 @@ def run_pipeline(text): # define grammar - grammar, idx, num = define_cool_grammar() + grammar, idx, string, num = define_cool_grammar() # tokenize text - tokens = tokenize_cool_text(grammar, text, idx, num, True) + # tokens = tokenize_cool_text(grammar, text, idx, num, True) + tokens = tokenize_cool_text(grammar, idx, string, num, text, True) + # print(tokens) # try: parser = LR1Parser(grammar) diff --git a/test/test_merger.py b/test/test_merger.py index a20211872..ad2366ff0 100644 --- a/test/test_merger.py +++ b/test/test_merger.py @@ -10,12 +10,12 @@ def test(): text = """ - - class A { + + class A { a : String ; b : AUTO_TYPE ; c : AUTO_TYPE <- 0 ; - d : Object <- while c loop c + 1 pool ; *first and second errors* + d : Object <- while c loop c + 1 pool ; (*first and second errors*) j : AUTO_TYPE ; l : AUTO_TYPE ; fact ( n : AUTO_TYPE ) : AUTO_TYPE { if n < 0 then 1 else n + fact ( n - 1 ) fi } ; @@ -23,13 +23,12 @@ class A { b <- { p + 5 ; - j <- p ; *third error* + j <- p ; (*third error*) p <- false ; isvoid d ; - l @ Point . main ( ) ; - } + } } ; } ; class Point inherits A { @@ -37,7 +36,7 @@ class Point inherits A { k : AUTO_TYPE ; main ( ) : AUTO_TYPE { let i : AUTO_TYPE <- new A in { - isvoid i ; *Puede lanzar error semantico* + isvoid i ; (*Puede lanzar error semantico*) } } ; ackermann ( m : AUTO_TYPE , n : AUTO_TYPE ) : AUTO_TYPE { @@ -48,7 +47,7 @@ class Point inherits A { fi } ; } ; - + """ ast = run_pipeline(text) @@ -67,6 +66,7 @@ class Point inherits A { print(errors) if errors != []: + print(errors) assert False tset_builder = TSetBuilder(context, errors) diff --git a/test/test_parser2.py b/test/test_parser2.py index 7375d1697..bc4909d2b 100644 --- a/test/test_parser2.py +++ b/test/test_parser2.py @@ -33,5 +33,5 @@ class Cons inherits List { assert ( tree - == "__ProgramNode [ ... ]__ClassDeclarationNode: class Cons inherits List { ... }__AttrDeclarationNode: xcar : String <- __NONE__AttrDeclarationNode: xcdr : List <- __NONE__FuncDeclarationNode: isNill() : Bool -> __ BooleanNode: false__FuncDeclarationNode: init(hd:Int, tl:List) : Cons -> __BlockNode: {; ... ;}__AssignNode: xcar <- __ StringNode: testing strings __AssignNode: xcdr <- __ VariableNode: tl__ VariableNode: self" + == "__ProgramNode [ ... ]__ClassDeclarationNode: class Cons inherits List { ... }__AttrDeclarationNode: xcar : String <- __NONE__AttrDeclarationNode: xcdr : List <- __NONE__FuncDeclarationNode: isNill() : Bool -> __ BooleanNode: false__FuncDeclarationNode: init(hd:Int, tl:List) : Cons -> __BlockNode: {; ... ;}__AssignNode: xcar <- __ StringNode: testing strings __AssignNode: xcdr <- __ VariableNode: tl__ VariableNode: self" ) diff --git a/test/test_parser3.py b/test/test_parser3.py index e575c8f70..dfbec2c30 100644 --- a/test/test_parser3.py +++ b/test/test_parser3.py @@ -26,6 +26,6 @@ class Main inherits IO { assert ( tree - == "__ProgramNode [ ... ]__ClassDeclarationNode: class Main inherits IO { ... }__FuncDeclarationNode: main() : AUTO_TYPE -> __LetNode: let in __VarDeclarationNode: x : AUTO_TYPE <- __ PlusNode __ ConstantNumNode: 3__ ConstantNumNode: 2__BlockNode: {; ... ;}__LetNode: case of esac__ VariableNode: x__CaseItemNode: y : Int => ;__CallNode: out_string(, ..., )__ StringNode: Ok " + == "__ProgramNode [ ... ]__ClassDeclarationNode: class Main inherits IO { ... }__FuncDeclarationNode: main() : AUTO_TYPE -> __LetNode: let in __VarDeclarationNode: x : AUTO_TYPE <- __ PlusNode __ ConstantNumNode: 3__ ConstantNumNode: 2__BlockNode: {; ... ;}__LetNode: case of esac__ VariableNode: x__CaseItemNode: y : Int => ;__CallNode: out_string(, ..., )__ StringNode: Ok " ) diff --git a/test/test_parser4.py b/test/test_parser4.py index 1ef6a2312..e2539718b 100644 --- a/test/test_parser4.py +++ b/test/test_parser4.py @@ -23,6 +23,7 @@ class Point { tree = tree.replace("\t", "") tree = tree.replace("\n", "") tree = tree.replace("\\", "") + assert ( tree == "__ProgramNode [ ... ]__ClassDeclarationNode: class Point { ... }__AttrDeclarationNode: x : AUTO_TYPE <- __NONE__AttrDeclarationNode: y : AUTO_TYPE <- __NONE__FuncDeclarationNode: init(n:Int, m:Int) : SELF_TYPE -> __BlockNode: {; ... ;}__AssignNode: x <- __ VariableNode: n__AssignNode: y <- __ VariableNode: m" diff --git a/test/test_parser6.py b/test/test_parser6.py index 5b4da6605..4276bbd6e 100644 --- a/test/test_parser6.py +++ b/test/test_parser6.py @@ -8,7 +8,7 @@ class Point { step ( p : AUTO_TYPE ) : AUTO_TYPE { p . translate ( 1 , 1 ) } ; main ( ) : Object { let p : AUTO_TYPE <- new Point in { - step ( p ) ; *Puede lanzar error semantico* + step ( p ) ; (*Puede lanzar error semantico*) } } ; } ; @@ -22,6 +22,7 @@ class Point { tree = tree.replace("\t", "") tree = tree.replace("\n", "") tree = tree.replace("\\", "") + assert ( tree == "__ProgramNode [ ... ]__ClassDeclarationNode: class Point { ... }__FuncDeclarationNode: step(p:AUTO_TYPE) : AUTO_TYPE -> __CallNode: .translate(, ..., )__ VariableNode: p__ ConstantNumNode: 1__ ConstantNumNode: 1__FuncDeclarationNode: main() : Object -> __LetNode: let in __VarDeclarationNode: p : AUTO_TYPE <- __ InstantiateNode: new Point()__BlockNode: {; ... ;}__CallNode: step(, ..., )__ VariableNode: p" diff --git a/test/test_reducer.py b/test/test_reducer.py index 0c1ede562..c40c1d52a 100644 --- a/test/test_reducer.py +++ b/test/test_reducer.py @@ -35,7 +35,7 @@ class Point inherits A { k : AUTO_TYPE ; main ( ) : AUTO_TYPE { let i : AUTO_TYPE <- new A in { - isvoid i ; *Puede lanzar error semantico* + isvoid i ; (*Puede lanzar error semantico*) } } ; ackermann ( m : AUTO_TYPE , n : AUTO_TYPE ) : AUTO_TYPE { diff --git a/test/test_tset_builder.py b/test/test_tset_builder.py index 082b6da37..c2795d0c0 100644 --- a/test/test_tset_builder.py +++ b/test/test_tset_builder.py @@ -19,7 +19,7 @@ class Point { step ( p : AUTO_TYPE ) : AUTO_TYPE { p . translate ( 1 , 1 ) } ; main ( ) : Object { let p : AUTO_TYPE <- new Point in { - step ( p ) ; *Puede lanzar error semantico* + step ( p ) ; (*Puede lanzar error semantico*) } } ; } ; diff --git a/test/test_type_builder.py b/test/test_type_builder.py index 492b481fd..049bf89f2 100644 --- a/test/test_type_builder.py +++ b/test/test_type_builder.py @@ -15,7 +15,7 @@ class Point { step ( p : AUTO_TYPE ) : AUTO_TYPE { p . translate ( 1 , 1 ) } ; main ( ) : Object { let p : AUTO_TYPE <- new Point in { - step ( p ) ; *Puede lanzar error semantico* + step ( p ) ; (*Puede lanzar error semantico*) } } ; } ; diff --git a/test/test_type_checker.py b/test/test_type_checker.py index 969d56f6a..1cffb87de 100644 --- a/test/test_type_checker.py +++ b/test/test_type_checker.py @@ -18,7 +18,7 @@ class Point { step ( p : AUTO_TYPE ) : AUTO_TYPE { p . translate ( 1 , 1 ) } ; main ( ) : Object { let p : AUTO_TYPE <- new Point in { - step ( p ) ; *Puede lanzar error semantico* + step ( p ) ; (*Puede lanzar error semantico*) } } ; } ; diff --git a/test/test_type_collector.py b/test/test_type_collector.py index 5f90576a4..a94e8cf8e 100644 --- a/test/test_type_collector.py +++ b/test/test_type_collector.py @@ -9,7 +9,7 @@ class Point { step ( p : AUTO_TYPE ) : AUTO_TYPE { p . translate ( 1 , 1 ) } ; main ( ) : Object { let p : AUTO_TYPE <- new Point in { - step ( p ) ; *Puede lanzar error semantico* + step ( p ) ; (*Puede lanzar error semantico*) } } ; } ; From 21a696998688f4433cc52ab5c81c55fe9332a28a Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Mon, 30 Nov 2020 18:46:14 -0500 Subject: [PATCH 014/162] Add self type checking --- main.py | 4 ++++ src/type_checker.py | 19 ++++++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/main.py b/main.py index eb394a959..36d1ddd88 100644 --- a/main.py +++ b/main.py @@ -98,6 +98,10 @@ def run_pipeline(text): checker = TypeChecker(context, errors) checker.visit(ast, None) + if errors != []: + st.header("Sorry we found some errors in your code:") + print_array(errors) + if reduced_sets in selected_options: st.header("Reduced Sets") print_tset(reduced_set) diff --git a/src/type_checker.py b/src/type_checker.py index 6bf2dcbb6..fbb769d37 100644 --- a/src/type_checker.py +++ b/src/type_checker.py @@ -87,6 +87,9 @@ def visit(self, node, scope): self.errors.append(e) return ErrorType() + if typex.name == "SELF_TYPE": + typex = self.current_type + if node.init_exp != None: init_expr_type = self.visit(node.init_exp, scope) if not init_expr_type.conforms_to(typex): @@ -97,6 +100,9 @@ def visit(self, node, scope): @visitor.when(FuncDeclarationNode) def visit(self, node, scope): self.current_method = self.current_type.get_method(node.id) + method_return_type = self.current_method.return_type + if method_return_type.name == "SELF_TYPE": + method_return_type = self.current_type child_scope = scope.create_child() @@ -107,10 +113,9 @@ def visit(self, node, scope): body_type = self.visit(node.body, child_scope) - if not body_type.conforms_to(self.current_method.return_type): + if not body_type.conforms_to(method_return_type): self.errors.append( - INCOMPATIBLE_TYPES - % (body_type.name, self.current_method.return_type.name) + INCOMPATIBLE_TYPES % (body_type.name, method_return_type.name) ) if self.current_type.parent is not None: @@ -125,6 +130,9 @@ def visit(self, node, scope): try: return_type = self.context.get_type(node.type) + if return_type.name == "SELF_TYPE": + return self.current_type + return return_type except SemanticError as e: @@ -268,6 +276,8 @@ def visit(self, node, scope): static_type = None try: static_type = self.context.get_type(node.type) + if static_type.name == "SELF_TYPE": + static_type = self.current_type scope.define_variable(node.id, static_type) except SemanticError as e: @@ -312,6 +322,9 @@ def visit(self, node, scope): def visit(self, node, scope): try: typex = self.context.get_type(node.lex) + if typex.name == "SELF_TYPE": + return self.current_type + return typex except SemanticError as error: self.errors.append(error.text) From 29b3bfba1ffd6c3e9fb515557193cb2d0669135e Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Mon, 7 Dec 2020 17:07:08 -0500 Subject: [PATCH 015/162] Add IO. Fix Case bug --- src/cmp/semantic.py | 9 +++++++++ src/tsets_reducer.py | 26 +++++++++++++++++--------- src/type_builder.py | 18 ++++++++++++++++++ src/type_collector.py | 4 ++++ 4 files changed, 48 insertions(+), 9 deletions(-) diff --git a/src/cmp/semantic.py b/src/cmp/semantic.py index e28ae6c0d..b6f4b4ab6 100644 --- a/src/cmp/semantic.py +++ b/src/cmp/semantic.py @@ -210,6 +210,15 @@ def __init__(self): Type.__init__(self, "SELF_TYPE") +# Despues de entregar!!!! +class IOType(Type): + def __init__(self): + Type.__init__(self, "IO") + + +# --------------------------- + + class Context: def __init__(self): self.types = {} diff --git a/src/tsets_reducer.py b/src/tsets_reducer.py index a4b9e7711..d511a5bf6 100644 --- a/src/tsets_reducer.py +++ b/src/tsets_reducer.py @@ -161,20 +161,23 @@ def visit(self, node, tset): item_set = self.visit(item, tset.children[item]) union_set = union(union_set, item_set) - current_type = None - for item in union_set: - if item == "!static_type_declared": - continue - item_type = self.context.get_type(item) - current_type = find_least_type([current_type, item_type], self.context) + # current_type = None + # for item in union_set: + # if item == "!static_type_declared": + # continue + # item_type = self.context.get_type(item) + # current_type = find_least_type(current_type, item_type, self.context) + + # return {current_type.name} - return {current_type.name} + return union_set @visitor.when(CaseItemNode) def visit(self, node, tset): expr_tset = self.visit(node.expr, tset) - tset.locals[node.id] = reduce_set(tset.locals[node.id], expr_tset) - return tset.locals[node.id] + # tset.locals[node.id] = reduce_set(tset.locals[node.id], expr_tset) + # return tset.locals[node.id] + return expr_tset @visitor.when(CallNode) def visit(self, node, tset): @@ -223,6 +226,11 @@ def visit(self, node, tset): for typex in method.tset: return_types.add(typex) + # ------- Despues de la entrega!!!!!!! + if "SELF_TYPE" in return_types: + return_types.remove("SELF_TYPE") + return_types = union(return_types, {self.current_type.name}) + # ------------------------------- return return_types @visitor.when(BlockNode) diff --git a/src/type_builder.py b/src/type_builder.py index f3a47d6f8..3ec60da90 100644 --- a/src/type_builder.py +++ b/src/type_builder.py @@ -23,6 +23,24 @@ def visit(self, node): @visitor.when(ProgramNode) def visit(self, node): + # Despues de entregar!!!!!! + io_type = self.context.get_type("IO") + self_type = self.context.get_type("SELF_TYPE") + int_type = self.context.get_type("Int") + string_type = self.context.get_type("String") + + method = io_type.define_method("out_string", ["x"], [string_type], self_type) + method.tset = {"SELF_TYPE"} + + method = io_type.define_method("out_int", ["x"], [int_type], self_type) + method.tset = {"SELF_TYPE"} + + method = io_type.define_method("in_string", [], [], string_type) + method.tset = {"String"} + + method = io_type.define_method("in_int", [], [], int_type) + method.tset = {"Int"} + # ---------------------------------------------------- for declaration in node.declarations: self.visit(declaration) diff --git a/src/type_collector.py b/src/type_collector.py index 6418886ea..f57d94527 100644 --- a/src/type_collector.py +++ b/src/type_collector.py @@ -9,6 +9,7 @@ AutoType, ObjectType, SelfType, + IOType, ) from src.cmp.semantic import Context from src.ast_nodes import ProgramNode, ClassDeclarationNode @@ -33,6 +34,9 @@ def visit(self, node): self.context.types["Bool"] = BoolType() self.context.types["AUTO_TYPE"] = AutoType() self.context.types["SELF_TYPE"] = SelfType() + # Despues de entregar!!!!! + self.context.types["IO"] = IOType() + # ------------------- object_type = self.context.get_type("Object") for typex in self.context.types.values(): From 7962d57f1b05868d17743dccb751da38d8c0a87c Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Tue, 8 Dec 2020 15:13:08 -0500 Subject: [PATCH 016/162] Print clean AST. Add self variable in every tset. Modify src/type_builder.py to catch all semantic errors. --- src/cool_visitor.py | 3 ++- src/tsets_reducer.py | 3 ++- src/type_builder.py | 9 ++++----- src/ui.py | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/cool_visitor.py b/src/cool_visitor.py index ec2beb97c..358821746 100644 --- a/src/cool_visitor.py +++ b/src/cool_visitor.py @@ -169,7 +169,8 @@ def visit(self, node, tabs=0): @visitor.when(ProgramNode) def visit(self, node, tabs=0): - ans = "\\__\\__" * tabs + f"\\__ProgramNode [ ... ]" + self.tree = [] + ans = "\\__\\__" * tabs + f"\\__ProgramNode [< class > ... < class >]" self.tree.append(ans) for child in node.declarations: self.visit(child, tabs + 1) diff --git a/src/tsets_reducer.py b/src/tsets_reducer.py index d511a5bf6..cf8bc2564 100644 --- a/src/tsets_reducer.py +++ b/src/tsets_reducer.py @@ -76,6 +76,7 @@ def visit(self, node, tset): @visitor.when(ClassDeclarationNode) def visit(self, node, tset): + tset.locals["self"] = {node.id} self.current_type = self.context.get_type(node.id) for feature in node.features: self.visit(feature, tset) @@ -229,7 +230,7 @@ def visit(self, node, tset): # ------- Despues de la entrega!!!!!!! if "SELF_TYPE" in return_types: return_types.remove("SELF_TYPE") - return_types = union(return_types, {self.current_type.name}) + return_types = union(return_types, expr_set) # ------------------------------- return return_types diff --git a/src/type_builder.py b/src/type_builder.py index 3ec60da90..61c32c6aa 100644 --- a/src/type_builder.py +++ b/src/type_builder.py @@ -49,8 +49,8 @@ def visit(self, node): self.current_type = self.context.get_type(node.id) if node.parent is not None: - parent_type = self.get_type(node.parent) try: + parent_type = self.get_type(node.parent) self.current_type.set_parent(parent_type) except SemanticError as error: self.errors.append(error.text) @@ -67,10 +67,10 @@ def visit(self, node): @visitor.when(FuncDeclarationNode) def visit(self, node): param_names = [fname for fname, ftype in node.params] - param_types = [self.get_type(ftype) for fname, ftype in node.params] - return_type = self.get_type(node.type) try: + param_types = [self.get_type(ftype) for fname, ftype in node.params] + return_type = self.get_type(node.type) self.current_type.define_method( node.id, param_names, param_types, return_type ) @@ -79,9 +79,8 @@ def visit(self, node): @visitor.when(AttrDeclarationNode) def visit(self, node): - attr_type = self.get_type(node.type) - try: + attr_type = self.get_type(node.type) self.current_type.define_attribute(node.id, attr_type) except SemanticError as error: self.errors.append(error.text) diff --git a/src/ui.py b/src/ui.py index beb66f666..d0ceb8102 100644 --- a/src/ui.py +++ b/src/ui.py @@ -17,7 +17,7 @@ def print_array(array): for item in array: - st.write(item) + st.write(str(item)) def print_tset(tset): From 7575f210a40aa8f8590d538a0b97fa11ec40452c Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Thu, 10 Dec 2020 10:27:52 -0500 Subject: [PATCH 017/162] Reduce param set using argument set and viceversa. tset property in methods is now an actual Tset instead of a set with the method's return types. Added a few more tests. --- src/tset_builder.py | 4 +- src/tsets_reducer.py | 24 ++++++---- src/type_builder.py | 18 ++++++-- test/test_1.py | 71 ++++++++++++++++++++++++++++ test/test_10.py | 107 +++++++++++++++++++++++++++++++++++++++++++ test/test_11.py | 81 ++++++++++++++++++++++++++++++++ test/test_12.py | 96 ++++++++++++++++++++++++++++++++++++++ test/test_2.py | 73 +++++++++++++++++++++++++++++ test/test_3.py | 69 ++++++++++++++++++++++++++++ test/test_4.py | 71 ++++++++++++++++++++++++++++ test/test_5.py | 81 ++++++++++++++++++++++++++++++++ test/test_6.py | 80 ++++++++++++++++++++++++++++++++ test/test_7.py | 81 ++++++++++++++++++++++++++++++++ test/test_8.py | 83 +++++++++++++++++++++++++++++++++ test/test_9.py | 80 ++++++++++++++++++++++++++++++++ test/test_IO.py | 74 ++++++++++++++++++++++++++++++ test/test_merger.py | 1 + 17 files changed, 1080 insertions(+), 14 deletions(-) create mode 100644 test/test_1.py create mode 100644 test/test_10.py create mode 100644 test/test_11.py create mode 100644 test/test_12.py create mode 100644 test/test_2.py create mode 100644 test/test_3.py create mode 100644 test/test_4.py create mode 100644 test/test_5.py create mode 100644 test/test_6.py create mode 100644 test/test_7.py create mode 100644 test/test_8.py create mode 100644 test/test_9.py create mode 100644 test/test_IO.py diff --git a/src/tset_builder.py b/src/tset_builder.py index 549e4aee4..3ff33d27d 100644 --- a/src/tset_builder.py +++ b/src/tset_builder.py @@ -92,10 +92,10 @@ def visit(self, node, tset): else: tset.locals[node.id] = {node.type, "!static_type_declared"} + child_set = tset.create_child(node) method = self.current_type.get_method(node.id) - method.tset = tset.locals[node.id] + method.tset = child_set - child_set = tset.create_child(node) for param in node.params: typex = self.context.get_type(param[1]) if typex.name == "AUTO_TYPE": diff --git a/src/tsets_reducer.py b/src/tsets_reducer.py index cf8bc2564..55f2acb0a 100644 --- a/src/tsets_reducer.py +++ b/src/tsets_reducer.py @@ -98,7 +98,7 @@ def visit(self, node, tset): current_tset = tset.children[node] body_set = self.visit(node.body, current_tset) tset.locals[node.id] = reduce_set(tset.locals[node.id], body_set) - method.tset = tset.locals[node.id] + method.tset = current_tset @visitor.when(AssignNode) def visit(self, node, tset): @@ -182,8 +182,9 @@ def visit(self, node, tset): @visitor.when(CallNode) def visit(self, node, tset): + args_set = {} for expr in node.args: - self.visit(expr, tset) + args_set[expr] = self.visit(expr, tset) if node.obj is not None: expr_set = self.visit(node.obj, tset) @@ -191,8 +192,10 @@ def visit(self, node, tset): expr_set = {self.current_type.name} types_with_method = set() + method = None if node.at_type is not None: types_with_method.add(node.at_type) + method = self.context.get_type(node.at_type).get_method(node.id) else: for typex in self.context.types.values(): @@ -203,11 +206,16 @@ def visit(self, node, tset): except SemanticError: continue - # DUDA!!!! - # if len(types_with_method) == 0: - # raise SemanticError( - # f"There is no method named {node.id} that takes {len(node.args)} arguments" - # ) + if len(types_with_method) == 1: + for arg, param in zip(node.args, method.param_names): + method.tset.locals[param] = reduce_set( + method.tset.locals[param], args_set[arg] + ) + if isinstance(arg, VariableNode): + arg_locals = tset.find_set(arg.lex) + arg_locals[arg.lex] = reduce_set( + arg_locals[arg.lex], method.tset.locals[param] + ) if isinstance(node.obj, VariableNode): node_id = node.obj.lex @@ -224,7 +232,7 @@ def visit(self, node, tset): for item in types_reduced: item_type = self.context.get_type(item) method = item_type.get_method(node.id) - for typex in method.tset: + for typex in method.tset.parent.locals[node.id]: return_types.add(typex) # ------- Despues de la entrega!!!!!!! diff --git a/src/type_builder.py b/src/type_builder.py index 61c32c6aa..a6a103058 100644 --- a/src/type_builder.py +++ b/src/type_builder.py @@ -9,6 +9,7 @@ FuncDeclarationNode, ) import src.cmp.visitor as visitor +from src.tset import Tset class TypeBuilder: @@ -29,17 +30,26 @@ def visit(self, node): int_type = self.context.get_type("Int") string_type = self.context.get_type("String") + parent_tset = Tset() + parent_tset.locals["out_string"] = {"SELF_TYPE"} + parent_tset.locals["out_int"] = {"SELF_TYPE"} + parent_tset.locals["in_string"] = {"String"} + parent_tset.locals["in_int"] = {"Int"} + method = io_type.define_method("out_string", ["x"], [string_type], self_type) - method.tset = {"SELF_TYPE"} + method.tset = Tset(parent_tset) + method.tset.locals["x"] = {"String"} method = io_type.define_method("out_int", ["x"], [int_type], self_type) - method.tset = {"SELF_TYPE"} + method.tset = Tset(parent_tset) + method.tset.locals["x"] = {"Int"} method = io_type.define_method("in_string", [], [], string_type) - method.tset = {"String"} + method.tset = Tset(parent_tset) method = io_type.define_method("in_int", [], [], int_type) - method.tset = {"Int"} + method.tset = Tset(parent_tset) + # ---------------------------------------------------- for declaration in node.declarations: self.visit(declaration) diff --git a/test/test_1.py b/test/test_1.py new file mode 100644 index 000000000..9b893e76a --- /dev/null +++ b/test/test_1.py @@ -0,0 +1,71 @@ +from run_pipeline import run_pipeline +from src.type_collector import TypeCollector +from src.type_builder import TypeBuilder +from src.type_checker import TypeChecker +from src.tset_builder import TSetBuilder +from src.tsets_reducer import TSetReducer +from src.tset_merger import TSetMerger +from src.cool_visitor import FormatVisitor + + +def test(): + text = """ + + class Main { + pp : AUTO_TYPE; + main() : AUTO_TYPE { + pp <- self + }; +}; + + """ + + ast = run_pipeline(text) + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + print(errors) + if errors != []: + print(errors) + assert False + + tset_builder = TSetBuilder(context, errors) + tset = tset_builder.visit(ast, None) + + tset_reducer = TSetReducer(context, errors) + reduced_set = tset_reducer.visit(ast, tset) + + tset_merger = TSetMerger(context, errors) + tset_merger.visit(ast, reduced_set) + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + formatter = FormatVisitor() + tree = formatter.visit(ast) + + print("Errors:", errors) + print("Context:") + print(context) + print(reduced_set) + print(tree) + + assert errors == [] diff --git a/test/test_10.py b/test/test_10.py new file mode 100644 index 000000000..1ce7ad84a --- /dev/null +++ b/test/test_10.py @@ -0,0 +1,107 @@ +from run_pipeline import run_pipeline +from src.type_collector import TypeCollector +from src.type_builder import TypeBuilder +from src.type_checker import TypeChecker +from src.tset_builder import TSetBuilder +from src.tsets_reducer import TSetReducer +from src.tset_merger import TSetMerger +from src.cool_visitor import FormatVisitor + + +def test(): + text = """ +class Main inherits IO { + main(): IO { + let vector: AUTO_TYPE <- (new Vector2).init(0, 0) in + vector.print_vector() + }; +}; + +class Vector2 { + x: AUTO_TYPE; + y: AUTO_TYPE; + + init(x_: AUTO_TYPE, y_: AUTO_TYPE): AUTO_TYPE { { + x <- x_; + y <- y_; + self; + } }; + + + get_x(): AUTO_TYPE { + x + }; + + get_y(): AUTO_TYPE { + y + }; + + add(v: Vector2): AUTO_TYPE { + (new Vector2).init(x + v.get_x(), y + v.get_y()) + }; + + print_vector(): AUTO_TYPE { + let io: IO <- new IO in { + io.out_string(" ( "); + io.out_int(get_x()); + io.out_string("; "); + io.out_int(get_y()); + io.out_string(" ) "); + } + }; + + clone_vector(): AUTO_TYPE { + (new Vector2).init(x, y) + }; +}; + """ + + ast = run_pipeline(text) + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + print(errors) + if errors != []: + print(errors) + assert False + + tset_builder = TSetBuilder(context, errors) + tset = tset_builder.visit(ast, None) + + tset_reducer = TSetReducer(context, errors) + reduced_set = tset_reducer.visit(ast, tset) + + tset_merger = TSetMerger(context, errors) + tset_merger.visit(ast, reduced_set) + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + formatter = FormatVisitor() + tree = formatter.visit(ast) + + print("Errors:", errors) + print("Context:") + print(context) + print(reduced_set) + print(tree) + + assert errors == [] diff --git a/test/test_11.py b/test/test_11.py new file mode 100644 index 000000000..b3f747da5 --- /dev/null +++ b/test/test_11.py @@ -0,0 +1,81 @@ +from run_pipeline import run_pipeline +from src.type_collector import TypeCollector +from src.type_builder import TypeBuilder +from src.type_checker import TypeChecker +from src.tset_builder import TSetBuilder +from src.tsets_reducer import TSetReducer +from src.tset_merger import TSetMerger +from src.cool_visitor import FormatVisitor + + +def test(): + text = """ +(* This program prints the first 10 numbers of fibonacci *) +class Main { + + main(): Object { + let total: AUTO_TYPE <- 10, + i: AUTO_TYPE <- 1 , + io: AUTO_TYPE <- new IO in + while i <= total loop { + io.out_int(fibonacci(i)); + io.out_string("n"); + i <- i + 1; + } + pool + }; + + fibonacci (n: AUTO_TYPE): AUTO_TYPE { + if n <= 2 then 1 else fibonacci(n - 1) + fibonacci(n - 2) fi + }; +}; """ + + ast = run_pipeline(text) + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + print(errors) + if errors != []: + print(errors) + assert False + + tset_builder = TSetBuilder(context, errors) + tset = tset_builder.visit(ast, None) + + tset_reducer = TSetReducer(context, errors) + reduced_set = tset_reducer.visit(ast, tset) + + tset_merger = TSetMerger(context, errors) + tset_merger.visit(ast, reduced_set) + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + formatter = FormatVisitor() + tree = formatter.visit(ast) + + print("Errors:", errors) + print("Context:") + print(context) + print(reduced_set) + print(tree) + + assert errors == [] diff --git a/test/test_12.py b/test/test_12.py new file mode 100644 index 000000000..7ed78cb81 --- /dev/null +++ b/test/test_12.py @@ -0,0 +1,96 @@ +from run_pipeline import run_pipeline +from src.type_collector import TypeCollector +from src.type_builder import TypeBuilder +from src.type_checker import TypeChecker +from src.tset_builder import TSetBuilder +from src.tsets_reducer import TSetReducer +from src.tset_merger import TSetMerger +from src.cool_visitor import FormatVisitor + + +def test(): + text = """ +(* Testing IO *) +class Main inherits IO { + + main(): Object { + let id: AUTO_TYPE, name: AUTO_TYPE, email: AUTO_TYPE in { + out_string("Introduzca su id: "); + id <- self.in_int(); + out_string("Introduzca su nombre: "); + name <- self.in_string(); + out_string("Introduzca su email: "); + email <- self.in_string(); + let user: AUTO_TYPE <- (new User).init(id, name, email) in + out_string("Created user: "); + } + }; +}; + +class User { + id: AUTO_TYPE; + name: AUTO_TYPE; + email: AUTO_TYPE; + + init(id_: AUTO_TYPE, name_: AUTO_TYPE, email_: AUTO_TYPE): AUTO_TYPE { { + id <- id_; + name <- name_; + email <- email_; + self; + } }; + + get_name(): AUTO_TYPE { + name + }; +}; + """ + + ast = run_pipeline(text) + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + print(errors) + if errors != []: + print(errors) + assert False + + tset_builder = TSetBuilder(context, errors) + tset = tset_builder.visit(ast, None) + + tset_reducer = TSetReducer(context, errors) + reduced_set = tset_reducer.visit(ast, tset) + + tset_merger = TSetMerger(context, errors) + tset_merger.visit(ast, reduced_set) + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + formatter = FormatVisitor() + tree = formatter.visit(ast) + + print("Errors:", errors) + print("Context:") + print(context) + print(reduced_set) + print(tree) + + assert errors == [] diff --git a/test/test_2.py b/test/test_2.py new file mode 100644 index 000000000..a2e9a01b0 --- /dev/null +++ b/test/test_2.py @@ -0,0 +1,73 @@ +from run_pipeline import run_pipeline +from src.type_collector import TypeCollector +from src.type_builder import TypeBuilder +from src.type_checker import TypeChecker +from src.tset_builder import TSetBuilder +from src.tsets_reducer import TSetReducer +from src.tset_merger import TSetMerger +from src.cool_visitor import FormatVisitor + + +def test(): + text = """ + + class Main{ + main() : AUTO_TYPE { + let x : AUTO_TYPE <- 3 in + case x of + y : Int => "Ok"; + esac + }; +}; + + """ + + ast = run_pipeline(text) + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + print(errors) + if errors != []: + print(errors) + assert False + + tset_builder = TSetBuilder(context, errors) + tset = tset_builder.visit(ast, None) + + tset_reducer = TSetReducer(context, errors) + reduced_set = tset_reducer.visit(ast, tset) + + tset_merger = TSetMerger(context, errors) + tset_merger.visit(ast, reduced_set) + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + formatter = FormatVisitor() + tree = formatter.visit(ast) + + print("Errors:", errors) + print("Context:") + print(context) + print(reduced_set) + print(tree) + + assert errors == [] diff --git a/test/test_3.py b/test/test_3.py new file mode 100644 index 000000000..4adf7bd7e --- /dev/null +++ b/test/test_3.py @@ -0,0 +1,69 @@ +from run_pipeline import run_pipeline +from src.type_collector import TypeCollector +from src.type_builder import TypeBuilder +from src.type_checker import TypeChecker +from src.tset_builder import TSetBuilder +from src.tsets_reducer import TSetReducer +from src.tset_merger import TSetMerger +from src.cool_visitor import FormatVisitor + + +def test(): + text = """ +class Main { + main() : AUTO_TYPE { + let x : AUTO_TYPE <- 3 in "Ok" + }; +}; + + """ + + ast = run_pipeline(text) + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + print(errors) + if errors != []: + print(errors) + assert False + + tset_builder = TSetBuilder(context, errors) + tset = tset_builder.visit(ast, None) + + tset_reducer = TSetReducer(context, errors) + reduced_set = tset_reducer.visit(ast, tset) + + tset_merger = TSetMerger(context, errors) + tset_merger.visit(ast, reduced_set) + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + formatter = FormatVisitor() + tree = formatter.visit(ast) + + print("Errors:", errors) + print("Context:") + print(context) + print(reduced_set) + print(tree) + + assert errors == [] diff --git a/test/test_4.py b/test/test_4.py new file mode 100644 index 000000000..5532ad6f7 --- /dev/null +++ b/test/test_4.py @@ -0,0 +1,71 @@ +from run_pipeline import run_pipeline +from src.type_collector import TypeCollector +from src.type_builder import TypeBuilder +from src.type_checker import TypeChecker +from src.tset_builder import TSetBuilder +from src.tsets_reducer import TSetReducer +from src.tset_merger import TSetMerger +from src.cool_visitor import FormatVisitor + + +def test(): + text = """ +class Main { + main(a : AUTO_TYPE) : AUTO_TYPE { + let x : AUTO_TYPE <- 3 in + case x of + y : IO => y.out_string(a); + esac + }; +}; + """ + + ast = run_pipeline(text) + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + print(errors) + if errors != []: + print(errors) + assert False + + tset_builder = TSetBuilder(context, errors) + tset = tset_builder.visit(ast, None) + + tset_reducer = TSetReducer(context, errors) + reduced_set = tset_reducer.visit(ast, tset) + + tset_merger = TSetMerger(context, errors) + tset_merger.visit(ast, reduced_set) + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + formatter = FormatVisitor() + tree = formatter.visit(ast) + + print("Errors:", errors) + print("Context:") + print(context) + print(reduced_set) + print(tree) + + assert errors == [] diff --git a/test/test_5.py b/test/test_5.py new file mode 100644 index 000000000..3e4e21342 --- /dev/null +++ b/test/test_5.py @@ -0,0 +1,81 @@ +from run_pipeline import run_pipeline +from src.type_collector import TypeCollector +from src.type_builder import TypeBuilder +from src.type_checker import TypeChecker +from src.tset_builder import TSetBuilder +from src.tsets_reducer import TSetReducer +from src.tset_merger import TSetMerger +from src.cool_visitor import FormatVisitor + + +def test(): + text = """ + + class Main { + main (): Object { + 0 + }; +}; + +class Point { + x: AUTO_TYPE; + y: AUTO_TYPE; + + init(x0: Int, y0: Int): AUTO_TYPE {{ + x <- x0; + y <- y0; + self; + }}; +}; + + """ + + ast = run_pipeline(text) + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + print(errors) + if errors != []: + print(errors) + assert False + + tset_builder = TSetBuilder(context, errors) + tset = tset_builder.visit(ast, None) + + tset_reducer = TSetReducer(context, errors) + reduced_set = tset_reducer.visit(ast, tset) + + tset_merger = TSetMerger(context, errors) + tset_merger.visit(ast, reduced_set) + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + formatter = FormatVisitor() + tree = formatter.visit(ast) + + print("Errors:", errors) + print("Context:") + print(context) + print(reduced_set) + print(tree) + + assert errors == [] diff --git a/test/test_6.py b/test/test_6.py new file mode 100644 index 000000000..250f8592b --- /dev/null +++ b/test/test_6.py @@ -0,0 +1,80 @@ +from run_pipeline import run_pipeline +from src.type_collector import TypeCollector +from src.type_builder import TypeBuilder +from src.type_checker import TypeChecker +from src.tset_builder import TSetBuilder +from src.tsets_reducer import TSetReducer +from src.tset_merger import TSetMerger +from src.cool_visitor import FormatVisitor + + +def test(): + text = """ + + class Main { + main (): Object { + 0 + }; +}; + +class Ackermann { + ackermann(m: AUTO_TYPE, n: AUTO_TYPE): AUTO_TYPE { + if m = 0 then n + 1 else + if n = 0 then ackermann(m - 1, 1) else + ackermann(m - 1, ackermann(m, n - 1)) + fi + fi + }; +}; + + """ + + ast = run_pipeline(text) + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + print(errors) + if errors != []: + print(errors) + assert False + + tset_builder = TSetBuilder(context, errors) + tset = tset_builder.visit(ast, None) + + tset_reducer = TSetReducer(context, errors) + reduced_set = tset_reducer.visit(ast, tset) + + tset_merger = TSetMerger(context, errors) + tset_merger.visit(ast, reduced_set) + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + formatter = FormatVisitor() + tree = formatter.visit(ast) + + print("Errors:", errors) + print("Context:") + print(context) + print(reduced_set) + print(tree) + + assert errors == [] diff --git a/test/test_7.py b/test/test_7.py new file mode 100644 index 000000000..d273f8d1a --- /dev/null +++ b/test/test_7.py @@ -0,0 +1,81 @@ +from run_pipeline import run_pipeline +from src.type_collector import TypeCollector +from src.type_builder import TypeBuilder +from src.type_checker import TypeChecker +from src.tset_builder import TSetBuilder +from src.tsets_reducer import TSetReducer +from src.tset_merger import TSetMerger +from src.cool_visitor import FormatVisitor + + +def test(): + text = """ + + class Main { + main (): Object { + 0 + }; + + f(a: AUTO_TYPE, b: AUTO_TYPE): AUTO_TYPE { + if a = 1 then b else + g(a + 1, b / 1) + fi + }; + + g(a: AUTO_TYPE, b: AUTO_TYPE): AUTO_TYPE { + if b = 1 then a else + f(a / 2, b + 1) + fi + }; +}; + """ + + ast = run_pipeline(text) + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + print(errors) + if errors != []: + print(errors) + assert False + + tset_builder = TSetBuilder(context, errors) + tset = tset_builder.visit(ast, None) + + tset_reducer = TSetReducer(context, errors) + reduced_set = tset_reducer.visit(ast, tset) + + tset_merger = TSetMerger(context, errors) + tset_merger.visit(ast, reduced_set) + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + formatter = FormatVisitor() + tree = formatter.visit(ast) + + print("Errors:", errors) + print("Context:") + print(context) + print(reduced_set) + print(tree) + + assert errors == [] diff --git a/test/test_8.py b/test/test_8.py new file mode 100644 index 000000000..b8a821b5c --- /dev/null +++ b/test/test_8.py @@ -0,0 +1,83 @@ +from run_pipeline import run_pipeline +from src.type_collector import TypeCollector +from src.type_builder import TypeBuilder +from src.type_checker import TypeChecker +from src.tset_builder import TSetBuilder +from src.tsets_reducer import TSetReducer +from src.tset_merger import TSetMerger +from src.cool_visitor import FormatVisitor + + +def test(): + text = """ + + class Main { + main (): Object { + 0 + }; +}; + +class Point { + x: Int; + y: Int; + + init(x0: AUTO_TYPE, y0: AUTO_TYPE): AUTO_TYPE { { + x <- x0; + y <- y0; + self; + } }; +}; + """ + + ast = run_pipeline(text) + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + print(errors) + if errors != []: + print(errors) + assert False + + tset_builder = TSetBuilder(context, errors) + tset = tset_builder.visit(ast, None) + + tset_reducer = TSetReducer(context, errors) + reduced_set = tset_reducer.visit(ast, tset) + + tset_merger = TSetMerger(context, errors) + tset_merger.visit(ast, reduced_set) + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + formatter = FormatVisitor() + tree = formatter.visit(ast) + + print("Errors:", errors) + print("Context:") + print(context) + print(reduced_set) + print(tree) + + assert errors == [ + 'Cannot convert "Object" into "Int".', + 'Cannot convert "Object" into "Int".', + ] diff --git a/test/test_9.py b/test/test_9.py new file mode 100644 index 000000000..f51f3d79e --- /dev/null +++ b/test/test_9.py @@ -0,0 +1,80 @@ +from run_pipeline import run_pipeline +from src.type_collector import TypeCollector +from src.type_builder import TypeBuilder +from src.type_checker import TypeChecker +from src.tset_builder import TSetBuilder +from src.tsets_reducer import TSetReducer +from src.tset_merger import TSetMerger +from src.cool_visitor import FormatVisitor + + +def test(): + text = """ + + class Main { + main (): Object { + 0 + }; + + f (a: AUTO_TYPE, b: AUTO_TYPE, c: AUTO_TYPE, d: AUTO_TYPE): AUTO_TYPE { + { + a <- b; + b <- c; + c <- d; + d <- a; + d + 1; + a; + } + }; +}; + """ + + ast = run_pipeline(text) + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + print(errors) + if errors != []: + print(errors) + assert False + + tset_builder = TSetBuilder(context, errors) + tset = tset_builder.visit(ast, None) + + tset_reducer = TSetReducer(context, errors) + reduced_set = tset_reducer.visit(ast, tset) + + tset_merger = TSetMerger(context, errors) + tset_merger.visit(ast, reduced_set) + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + formatter = FormatVisitor() + tree = formatter.visit(ast) + + print("Errors:", errors) + print("Context:") + print(context) + print(reduced_set) + print(tree) + + assert errors == [] diff --git a/test/test_IO.py b/test/test_IO.py new file mode 100644 index 000000000..a51ff44b1 --- /dev/null +++ b/test/test_IO.py @@ -0,0 +1,74 @@ +from run_pipeline import run_pipeline +from src.type_collector import TypeCollector +from src.type_builder import TypeBuilder +from src.type_checker import TypeChecker +from src.tset_builder import TSetBuilder +from src.tsets_reducer import TSetReducer +from src.tset_merger import TSetMerger +from src.cool_visitor import FormatVisitor + + +def test(): + text = """ + + class Main inherits IO { + main() : AUTO_TYPE { + let x : AUTO_TYPE <- 3 + (let y: AUTO_TYPE <- 8 in y ) in + case x of + y: Int => out_string("ok"); + esac + }; + }; + + + """ + + ast = run_pipeline(text) + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + print(errors) + if errors != []: + print(errors) + assert False + + tset_builder = TSetBuilder(context, errors) + tset = tset_builder.visit(ast, None) + + tset_reducer = TSetReducer(context, errors) + reduced_set = tset_reducer.visit(ast, tset) + + tset_merger = TSetMerger(context, errors) + tset_merger.visit(ast, reduced_set) + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + formatter = FormatVisitor() + tree = formatter.visit(ast) + + print("Errors:", errors) + print("Context:") + print(context) + print(reduced_set) + print(tree) + + assert errors == [] diff --git a/test/test_merger.py b/test/test_merger.py index ad2366ff0..b96ced14d 100644 --- a/test/test_merger.py +++ b/test/test_merger.py @@ -28,6 +28,7 @@ class A { isvoid d ; l @ Point . main ( ) ; + l.main(); } } ; } ; From 61741fcedbba3de20cb193560c681c6d096c404c Mon Sep 17 00:00:00 2001 From: Gaby Date: Sun, 13 Dec 2020 14:40:43 -0500 Subject: [PATCH 018/162] Modify cool_visitor --- src/cool_visitor.py | 11 +++--- test/test_adr.py | 92 ++++++++++++++++++++++++++++++++++++++++++++ test/test_parser1.py | 2 +- test/test_parser2.py | 2 +- test/test_parser3.py | 2 +- test/test_parser4.py | 2 +- test/test_parser5.py | 2 +- test/test_parser6.py | 2 +- 8 files changed, 104 insertions(+), 11 deletions(-) create mode 100644 test/test_adr.py diff --git a/src/cool_visitor.py b/src/cool_visitor.py index 358821746..8dab5b918 100644 --- a/src/cool_visitor.py +++ b/src/cool_visitor.py @@ -70,7 +70,7 @@ def visit(self, node, tabs=0): params = ", ".join(":".join(param) for param in node.params) ans = ( "\t" * tabs - + f"\\__FuncDeclarationNode: {node.id}({params}) : {node.type} -> " + + f"\\__FuncDeclarationNode: {node.id}({params}) : {node.type} {{ }}" ) body = self.visit(node.body, tabs + 1) return f"{ans}\n{body}" @@ -148,7 +148,7 @@ def visit(self, node, tabs=0): @visitor.when(CaseNode) def visit(self, node, tabs=0): - ans = "\t" * tabs + f"\\__LetNode: case of esac" + ans = "\t" * tabs + f"\\__CaseNode: case of esac" case_block = "\n".join(self.visit(child, tabs + 1) for child in node.case_items) expr = self.visit(node.expr, tabs + 1) return f"{ans}\n{expr}\n{case_block}" @@ -214,7 +214,8 @@ def visit(self, node, tabs=0): if not node.expr is None: expr = self.visit(node.expr, tabs + 1) - self.tree.append(expr) + else: # esto estaba antes sin el else + self.tree.append(expr) return @@ -230,7 +231,7 @@ def visit(self, node, tabs=0): params = ", ".join(":".join(param) for param in node.params) ans = ( "\\__\\__" * tabs - + f"\\__FuncDeclarationNode: {node.id}({params}) : {node.type} -> " + + f"\\__FuncDeclarationNode: {node.id}({params}) : {node.type} {{ }}" ) self.tree.append(ans) self.visit(node.body, tabs + 1) @@ -322,7 +323,7 @@ def visit(self, node, tabs=0): @visitor.when(CaseNode) def visit(self, node, tabs=0): - ans = "\\__\\__" * tabs + f"\\__LetNode: case of esac" + ans = "\\__\\__" * tabs + f"\\__CaseNode: case of esac" self.tree.append(ans) self.visit(node.expr, tabs + 1) for child in node.case_items: diff --git a/test/test_adr.py b/test/test_adr.py new file mode 100644 index 000000000..a62cc1c42 --- /dev/null +++ b/test/test_adr.py @@ -0,0 +1,92 @@ +from run_pipeline import run_pipeline +from src.type_collector import TypeCollector +from src.type_builder import TypeBuilder +from src.type_checker import TypeChecker +from src.tset_builder import TSetBuilder +from src.tsets_reducer import TSetReducer +from src.tset_merger import TSetMerger +from src.cool_visitor import FormatVisitor + + +def test(): + text = """ + + class Main { + a : AUTO_TYPE<- "Hola"; + main ( ) : Int { { + case {let i: AUTO_TYPE <- 12 in {let i: AUTO_TYPE <- "Hola" in {"Hi"; + case 12 of + x : Int => x; + y : AUTO_TYPE => y; + z: String => let i : AUTO_TYPE in { + i<- case self of + x: Int => 12; + x: AUTO_TYPE => if 12<12 then x else "Hola" fi ; + esac + ;}; + esac + ;};};} of + x : Int => 12; + y : AUTO_TYPE => let i: AUTO_TYPE <- y in y ; + esac ; + a.length();} } ; + } ; + + """ + + ast = run_pipeline(text) + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + # print(errors) + # if errors != []: + # print(errors) + # assert False + + tset_builder = TSetBuilder(context, errors) + tset = tset_builder.visit(ast, None) + + tset_reducer = TSetReducer(context, errors) + reduced_set = tset_reducer.visit(ast, tset) + + tset_merger = TSetMerger(context, errors) + tset_merger.visit(ast, reduced_set) + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + formatter = FormatVisitor() + tree = formatter.visit(ast) + + # print("Errors:", errors) + # print("Context:") + # print(context) + # print(reduced_set) + # print(tree) + + final_tree = """__ProgramNode [ ... ]__ClassDeclarationNode: class Main { ... }__AttrDeclarationNode: a : String <- __ StringNode: Hola__FuncDeclarationNode: main() : Int { }__BlockNode: {; ... ;}__CaseNode: case of esac__BlockNode: {; ... ;}__LetNode: let in __VarDeclarationNode: i : Int <- __ ConstantNumNode: 12__BlockNode: {; ... ;}__LetNode: let in __VarDeclarationNode: i : String <- __ StringNode: Hola__BlockNode: {; ... ;}__ StringNode: Hi__CaseNode: case of esac__ ConstantNumNode: 12__CaseItemNode: x : Int => ;__ VariableNode: x__CaseItemNode: y : Object => ;__ VariableNode: y__CaseItemNode: z : String => ;__LetNode: let in __VarDeclarationNode: i : Object <- __NONE__BlockNode: {; ... ;}__AssignNode: i <- __CaseNode: case of esac__ VariableNode: self__CaseItemNode: x : Int => ;__ ConstantNumNode: 12__CaseItemNode: x : Object => ;__IfNode: if then else fi__ LessNode __ ConstantNumNode: 12__ ConstantNumNode: 12__ VariableNode: x__ StringNode: Hola__CaseItemNode: x : Int => ;__ ConstantNumNode: 12__CaseItemNode: y : Object => ;__LetNode: let in __VarDeclarationNode: i : Object <- __ VariableNode: y__ VariableNode: y__CallNode: .length(, ..., )__ VariableNode: a""" + + tree = tree.replace("\t", "") + tree = tree.replace("\n", "") + tree = tree.replace("\\", "") + + assert tree == final_tree + assert errors == ['Method "length" is not defined in String.'] diff --git a/test/test_parser1.py b/test/test_parser1.py index 203c70bef..5e00d43b9 100644 --- a/test/test_parser1.py +++ b/test/test_parser1.py @@ -33,5 +33,5 @@ class Cons inherits List { assert ( tree - == "__ProgramNode [ ... ]__ClassDeclarationNode: class Cons inherits List { ... }__AttrDeclarationNode: xcar : Int <- __NONE__AttrDeclarationNode: xcdr : List <- __NONE__FuncDeclarationNode: isNill() : Bool -> __ BooleanNode: false__FuncDeclarationNode: init(hd:Int, tl:List) : Cons -> __BlockNode: {; ... ;}__AssignNode: xcar <- __ VariableNode: hd__AssignNode: xcdr <- __ VariableNode: tl__ VariableNode: self" + == "__ProgramNode [ ... ]__ClassDeclarationNode: class Cons inherits List { ... }__AttrDeclarationNode: xcar : Int <- __NONE__AttrDeclarationNode: xcdr : List <- __NONE__FuncDeclarationNode: isNill() : Bool { }__ BooleanNode: false__FuncDeclarationNode: init(hd:Int, tl:List) : Cons { }__BlockNode: {; ... ;}__AssignNode: xcar <- __ VariableNode: hd__AssignNode: xcdr <- __ VariableNode: tl__ VariableNode: self" ) diff --git a/test/test_parser2.py b/test/test_parser2.py index bc4909d2b..579bcf56b 100644 --- a/test/test_parser2.py +++ b/test/test_parser2.py @@ -33,5 +33,5 @@ class Cons inherits List { assert ( tree - == "__ProgramNode [ ... ]__ClassDeclarationNode: class Cons inherits List { ... }__AttrDeclarationNode: xcar : String <- __NONE__AttrDeclarationNode: xcdr : List <- __NONE__FuncDeclarationNode: isNill() : Bool -> __ BooleanNode: false__FuncDeclarationNode: init(hd:Int, tl:List) : Cons -> __BlockNode: {; ... ;}__AssignNode: xcar <- __ StringNode: testing strings __AssignNode: xcdr <- __ VariableNode: tl__ VariableNode: self" + == "__ProgramNode [ ... ]__ClassDeclarationNode: class Cons inherits List { ... }__AttrDeclarationNode: xcar : String <- __NONE__AttrDeclarationNode: xcdr : List <- __NONE__FuncDeclarationNode: isNill() : Bool { }__ BooleanNode: false__FuncDeclarationNode: init(hd:Int, tl:List) : Cons { }__BlockNode: {; ... ;}__AssignNode: xcar <- __ StringNode: testing strings __AssignNode: xcdr <- __ VariableNode: tl__ VariableNode: self" ) diff --git a/test/test_parser3.py b/test/test_parser3.py index dfbec2c30..ff92d22fb 100644 --- a/test/test_parser3.py +++ b/test/test_parser3.py @@ -26,6 +26,6 @@ class Main inherits IO { assert ( tree - == "__ProgramNode [ ... ]__ClassDeclarationNode: class Main inherits IO { ... }__FuncDeclarationNode: main() : AUTO_TYPE -> __LetNode: let in __VarDeclarationNode: x : AUTO_TYPE <- __ PlusNode __ ConstantNumNode: 3__ ConstantNumNode: 2__BlockNode: {; ... ;}__LetNode: case of esac__ VariableNode: x__CaseItemNode: y : Int => ;__CallNode: out_string(, ..., )__ StringNode: Ok " + == "__ProgramNode [ ... ]__ClassDeclarationNode: class Main inherits IO { ... }__FuncDeclarationNode: main() : AUTO_TYPE { }__LetNode: let in __VarDeclarationNode: x : AUTO_TYPE <- __ PlusNode __ ConstantNumNode: 3__ ConstantNumNode: 2__BlockNode: {; ... ;}__CaseNode: case of esac__ VariableNode: x__CaseItemNode: y : Int => ;__CallNode: out_string(, ..., )__ StringNode: Ok " ) diff --git a/test/test_parser4.py b/test/test_parser4.py index e2539718b..50975bd99 100644 --- a/test/test_parser4.py +++ b/test/test_parser4.py @@ -26,5 +26,5 @@ class Point { assert ( tree - == "__ProgramNode [ ... ]__ClassDeclarationNode: class Point { ... }__AttrDeclarationNode: x : AUTO_TYPE <- __NONE__AttrDeclarationNode: y : AUTO_TYPE <- __NONE__FuncDeclarationNode: init(n:Int, m:Int) : SELF_TYPE -> __BlockNode: {; ... ;}__AssignNode: x <- __ VariableNode: n__AssignNode: y <- __ VariableNode: m" + == "__ProgramNode [ ... ]__ClassDeclarationNode: class Point { ... }__AttrDeclarationNode: x : AUTO_TYPE <- __NONE__AttrDeclarationNode: y : AUTO_TYPE <- __NONE__FuncDeclarationNode: init(n:Int, m:Int) : SELF_TYPE { }__BlockNode: {; ... ;}__AssignNode: x <- __ VariableNode: n__AssignNode: y <- __ VariableNode: m" ) diff --git a/test/test_parser5.py b/test/test_parser5.py index c50ba7b97..009a531da 100644 --- a/test/test_parser5.py +++ b/test/test_parser5.py @@ -20,5 +20,5 @@ class Point { assert ( tree - == "__ProgramNode [ ... ]__ClassDeclarationNode: class Point { ... }__FuncDeclarationNode: succ(n:Int) : AUTO_TYPE -> __ PlusNode __ VariableNode: n__ ConstantNumNode: 1" + == "__ProgramNode [ ... ]__ClassDeclarationNode: class Point { ... }__FuncDeclarationNode: succ(n:Int) : AUTO_TYPE { }__ PlusNode __ VariableNode: n__ ConstantNumNode: 1" ) diff --git a/test/test_parser6.py b/test/test_parser6.py index 4276bbd6e..5d44a53fb 100644 --- a/test/test_parser6.py +++ b/test/test_parser6.py @@ -25,5 +25,5 @@ class Point { assert ( tree - == "__ProgramNode [ ... ]__ClassDeclarationNode: class Point { ... }__FuncDeclarationNode: step(p:AUTO_TYPE) : AUTO_TYPE -> __CallNode: .translate(, ..., )__ VariableNode: p__ ConstantNumNode: 1__ ConstantNumNode: 1__FuncDeclarationNode: main() : Object -> __LetNode: let in __VarDeclarationNode: p : AUTO_TYPE <- __ InstantiateNode: new Point()__BlockNode: {; ... ;}__CallNode: step(, ..., )__ VariableNode: p" + == "__ProgramNode [ ... ]__ClassDeclarationNode: class Point { ... }__FuncDeclarationNode: step(p:AUTO_TYPE) : AUTO_TYPE { }__CallNode: .translate(, ..., )__ VariableNode: p__ ConstantNumNode: 1__ ConstantNumNode: 1__FuncDeclarationNode: main() : Object { }__LetNode: let in __VarDeclarationNode: p : AUTO_TYPE <- __ InstantiateNode: new Point()__BlockNode: {; ... ;}__CallNode: step(, ..., )__ VariableNode: p" ) From 115e1817bf269ec8d2f1ca847087a260ca2612cd Mon Sep 17 00:00:00 2001 From: Gaby Date: Mon, 14 Dec 2020 06:11:00 -0500 Subject: [PATCH 019/162] Fixe Cyclic Herit bug --- main.py | 12 +++- notes.txt | 4 ++ src/cmp/semantic.py | 4 +- src/notes.txt | 3 - src/type_builder.py | 87 ++++++++++++++++++++++++++- src/type_checker.py | 32 ++++++++-- test.py | 117 ++++++++++++++++++++++++++++++++----- test/test_4.py | 5 +- test/test_cycher.py | 43 ++++++++++++++ test/test_cycher2.py | 45 ++++++++++++++ test/test_cycher3.py | 53 +++++++++++++++++ test/test_main.py | 61 +++++++++++++++++++ test/test_main1.py | 62 ++++++++++++++++++++ test/test_main2.py | 59 +++++++++++++++++++ test/test_merger.py | 5 +- test/test_redefinitions.py | 61 +++++++++++++++++++ test/test_reducer.py | 2 +- test/test_reducer2.py | 2 +- test/test_reducer3.py | 2 +- test/test_tset_builder.py | 2 +- test/test_type_builder.py | 2 +- test/test_type_checker.py | 2 +- 22 files changed, 623 insertions(+), 42 deletions(-) create mode 100644 notes.txt delete mode 100644 src/notes.txt create mode 100644 test/test_cycher.py create mode 100644 test/test_cycher2.py create mode 100644 test/test_cycher3.py create mode 100644 test/test_main.py create mode 100644 test/test_main1.py create mode 100644 test/test_main2.py create mode 100644 test/test_redefinitions.py diff --git a/main.py b/main.py index 36d1ddd88..2195666ea 100644 --- a/main.py +++ b/main.py @@ -41,6 +41,8 @@ def run_pipeline(text): + main_error1 = ["A class Main with a method main most be provided"] + main_error2 = ['"main" method in class Main does not receive any parameters'] # define grammar grammar, idx, string, num = define_cool_grammar() @@ -74,10 +76,16 @@ def run_pipeline(text): checker = TypeChecker(context, errors) checker.visit(ast, None) - if errors != []: + if errors != [] and errors != main_error1 and errors != main_error2: st.header("Sorry we found some errors in your code:") print_array(errors) else: + if errors == main_error1 or errors == main_error2: + st.header("Warning") + st.write("We will continue the analisis but note that:") + st.write(errors[0]) + errors = [] + tset_builder = TSetBuilder(context, errors) tset = tset_builder.visit(ast, None) @@ -98,7 +106,7 @@ def run_pipeline(text): checker = TypeChecker(context, errors) checker.visit(ast, None) - if errors != []: + if errors != [] and errors != main_error1 and errors != main_error2: st.header("Sorry we found some errors in your code:") print_array(errors) diff --git a/notes.txt b/notes.txt new file mode 100644 index 000000000..e19b4d06a --- /dev/null +++ b/notes.txt @@ -0,0 +1,4 @@ +Revisar: + +-Lo mas importante y que puede afectar la inferencia es lo de type builder, +la seccion que annade los metodos de string \ No newline at end of file diff --git a/src/cmp/semantic.py b/src/cmp/semantic.py index b6f4b4ab6..d217c36e6 100644 --- a/src/cmp/semantic.py +++ b/src/cmp/semantic.py @@ -83,11 +83,11 @@ def define_attribute(self, name: str, typex): f'Attribute "{name}" is already defined in {self.name}.' ) - def get_method(self, name: str): + def get_method(self, name: str, non_rec=False): try: return next(method for method in self.methods if method.name == name) except StopIteration: - if self.parent is None: + if non_rec or self.parent is None: raise SemanticError(f'Method "{name}" is not defined in {self.name}.') try: return self.parent.get_method(name) diff --git a/src/notes.txt b/src/notes.txt deleted file mode 100644 index 170b31bac..000000000 --- a/src/notes.txt +++ /dev/null @@ -1,3 +0,0 @@ -Por perfeccionar: --Que el tokenizer reconozca los string( Empiezan y terminan en comillas"), --Ignorar comentarios \ No newline at end of file diff --git a/src/type_builder.py b/src/type_builder.py index a6a103058..6e95d17e6 100644 --- a/src/type_builder.py +++ b/src/type_builder.py @@ -10,6 +10,7 @@ ) import src.cmp.visitor as visitor from src.tset import Tset +from collections import deque class TypeBuilder: @@ -50,12 +51,91 @@ def visit(self, node): method = io_type.define_method("in_int", [], [], int_type) method.tset = Tset(parent_tset) + # # -------String + # parent_tset = Tset() + # parent_tset.locals["concat"] = {"String"} + # parent_tset.locals["substr"] = {"String"} + # parent_tset.locals["length"] = {"Int"} + + # method = string_type.define_method("concat", ["s"], [string_type], string_type) + # method.tset = Tset(parent_tset) + # method.tset.locals["s"] = {"String"} + + # method = string_type.define_method( + # "substr", ["i", "l"], [int_type, int_type], string_type + # ) + # method.tset = Tset(parent_tset) + # method.tset.locals["i"] = {"Int"} + # method.tset.locals["l"] = {"Int"} + + # method = string_type.define_method("length", [], [], int_type) + # method.tset = Tset(parent_tset) + + # -------------------- + + # ------checking for in order definitions and cyclic heritage + parent_child_dict = {} + queue = deque() + visited = {} + not_visited = [] # ++ + + for class_declaration in node.declarations: + not_visited.append(class_declaration) # ++ + parent_type = class_declaration.parent + try: + self.context.get_type(parent_type) + try: + parent_child_dict[parent_type].append(class_declaration) + except: # KeyError + parent_child_dict[parent_type] = [class_declaration] + except SemanticError: # parent is None or not definition provided + queue.append(class_declaration) + + main_round = 0 + while not_visited: # ++ + main_round += 1 + while queue: + class_declaration = queue.popleft() + try: + class_visited, roundn = visited[class_declaration] # .id + + if roundn == main_round: + self.errors.append( + f"{class_declaration.id} is involved in a cyclic heritage" + ) + + except: + not_visited.remove(class_declaration) + try: + children = parent_child_dict[class_declaration.id] + for declaration in children: + queue.append(declaration) + except: # no es padre de nadie + pass + + self.visit(class_declaration) + visited[class_declaration] = (True, main_round) # .id + + if not_visited: + queue.append(not_visited[0]) + + try: + main_meth = self.context.get_type("Main").get_method("main", True) + if len(main_meth.param_names) > 0: + self.errors.append( + '"main" method in class Main does not receive any parameters' + ) + # modify in semantic get_method in order to get some ancestor where the method is already defined + except SemanticError: + self.errors.append("A class Main with a method main most be provided") + # ---------------------------------------------------- - for declaration in node.declarations: - self.visit(declaration) + # for declaration in node.declarations: + # self.visit(declaration) @visitor.when(ClassDeclarationNode) def visit(self, node): + # print(f"------------visiting class {node.id}------------") self.current_type = self.context.get_type(node.id) if node.parent is not None: @@ -69,7 +149,7 @@ def visit(self, node): try: self.current_type.set_parent(object_type) except SemanticError as error: - self.errors.append(error) + self.errors.append(error.text) for feature in node.features: self.visit(feature) @@ -85,6 +165,7 @@ def visit(self, node): node.id, param_names, param_types, return_type ) except SemanticError as error: + # print("--------aqui se esta reportando el error del metodo doble---------") self.errors.append(error.text) @visitor.when(AttrDeclarationNode) diff --git a/src/type_checker.py b/src/type_checker.py index fbb769d37..d8b9cf83e 100644 --- a/src/type_checker.py +++ b/src/type_checker.py @@ -105,11 +105,27 @@ def visit(self, node, scope): method_return_type = self.current_type child_scope = scope.create_child() + # ------------parameters most have differente names------------ + param_names = self.current_method.param_names + param_types = self.current_method.param_types + param_used = {} - for i in range(len(self.current_method.param_names)): - child_scope.define_variable( - self.current_method.param_names[i], self.current_method.param_types[i] - ) + for i, param_name in enumerate(param_names): + try: + param_used[param_name] + self.errors.append( + f"More tan one param in method {node.id} has the name {param_name}" + ) + except: + param_used[param_name] = True + child_scope.define_variable(param_name, param_types[i]) + + # ------------------------------------------------------------- + + # for i in range(len(self.current_method.param_names)): + # child_scope.define_variable( + # self.current_method.param_names[i], self.current_method.param_types[i] + # ) body_type = self.visit(node.body, child_scope) @@ -124,7 +140,13 @@ def visit(self, node, scope): self.current_method.name ) if parent_method != self.current_method: - self.errors.append(WRONG_SIGNATURE % (parent_method.name, "parent")) + self.errors.append( + WRONG_SIGNATURE + % ( + parent_method.name, + f"an ancestor of {self.current_type.name}", + ) + ) except SemanticError: pass diff --git a/test.py b/test.py index 0d18fc788..e60a05ce8 100644 --- a/test.py +++ b/test.py @@ -1,17 +1,102 @@ -data = """ -class Cons { -xcar : Int ; -xcdr : String ; - -isNill ( ) : Bool { - false -} ; - -init ( hd : Int , tl : String ) : String { - { - xcar <- (* ; - xcdr <- tl ; - } -} ; -} ; +from run_pipeline import run_pipeline +from src.type_collector import TypeCollector +from src.type_builder import TypeBuilder +from src.type_checker import TypeChecker +from src.tset_builder import TSetBuilder +from src.tsets_reducer import TSetReducer +from src.tset_merger import TSetMerger +from src.cool_visitor import FormatVisitor + + +def test(): + # text = """ + # class A { + # f ( a : Int , d : Int ) : Int { + # d <- False + # }; + # }; + # class B inherits A { + # f ( a : A , d : Int ) : A { + # d <- True + # }; + # }; + # """ + + text = """ + class Cons { + xcar : Int ; + xcdr : String ; + + isNill ( ) : Bool { + false + } ; + + init ( hd : Int , tl : String ) : String { + { + xcar <- hd ; + xcdr <- tl ; + } + } ; + } ; """ + + print("corriendo") + ast = run_pipeline(text) + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + if errors != []: + print(errors) + assert False + + tset_builder = TSetBuilder(context, errors) + tset = tset_builder.visit(ast, None) + + tset_reducer = TSetReducer(context, errors) + reduced_set = tset_reducer.visit(ast, tset) + + tset_merger = TSetMerger(context, errors) + tset_merger.visit(ast, reduced_set) + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + formatter = FormatVisitor() + tree = formatter.visit(ast) + + if errors != []: + print("Errors:", errors) + print("Context:") + print(context) + print(reduced_set) + print(tree) + assert False + + final_tree = """__ProgramNode [ ... ]__ClassDeclarationNode: class C inherits J { ... }__ClassDeclarationNode: class A inherits B { ... }__ClassDeclarationNode: class B inherits A { ... }__ClassDeclarationNode: class C { ... }__ClassDeclarationNode: class D inherits E { ... }__ClassDeclarationNode: class E inherits F { ... }__ClassDeclarationNode: class F inherits D { ... }__ClassDeclarationNode: class G inherits F { ... }""" + + tree = tree.replace("\t", "") + tree = tree.replace("\n", "") + tree = tree.replace("\\", "") + + assert tree == final_tree + + +test() diff --git a/test/test_4.py b/test/test_4.py index 5532ad6f7..d77f51529 100644 --- a/test/test_4.py +++ b/test/test_4.py @@ -34,8 +34,7 @@ class Main { checker = TypeChecker(context, errors) checker.visit(ast, None) - print(errors) - if errors != []: + if errors != ['"main" method in class Main does not receive any parameters']: print(errors) assert False @@ -68,4 +67,4 @@ class Main { print(reduced_set) print(tree) - assert errors == [] + assert True diff --git a/test/test_cycher.py b/test/test_cycher.py new file mode 100644 index 000000000..eb251e598 --- /dev/null +++ b/test/test_cycher.py @@ -0,0 +1,43 @@ +from run_pipeline import run_pipeline +from src.type_collector import TypeCollector +from src.type_builder import TypeBuilder +from src.type_checker import TypeChecker +from src.tset_builder import TSetBuilder +from src.tsets_reducer import TSetReducer +from src.tset_merger import TSetMerger +from src.cool_visitor import FormatVisitor + + +def test(): + text = """ + class B inherits A { + a : String ; + b : AUTO_TYPE ; + }; + class A inherits B { } ; + """ + + print("corriendo") + ast = run_pipeline(text) + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + if errors != [ + "B is involved in a cyclic heritage", + "A class Main with a method main most be provided", + ]: + print(errors) + assert False + + assert True + diff --git a/test/test_cycher2.py b/test/test_cycher2.py new file mode 100644 index 000000000..e5b79b639 --- /dev/null +++ b/test/test_cycher2.py @@ -0,0 +1,45 @@ +from run_pipeline import run_pipeline +from src.type_collector import TypeCollector +from src.type_builder import TypeBuilder +from src.type_checker import TypeChecker +from src.tset_builder import TSetBuilder +from src.tsets_reducer import TSetReducer +from src.tset_merger import TSetMerger +from src.cool_visitor import FormatVisitor + + +def test(): + text = """ + class B inherits A { + a : String ; + b : AUTO_TYPE ; + }; + class A inherits A { } ; + """ + + print("corriendo") + ast = run_pipeline(text) + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + err = [ + "A is involved in a cyclic heritage", + "A class Main with a method main most be provided", + ] + + if errors != err: + print(errors) + assert False + + assert True + diff --git a/test/test_cycher3.py b/test/test_cycher3.py new file mode 100644 index 000000000..82f546b2c --- /dev/null +++ b/test/test_cycher3.py @@ -0,0 +1,53 @@ +from run_pipeline import run_pipeline +from src.type_collector import TypeCollector +from src.type_builder import TypeBuilder +from src.type_checker import TypeChecker +from src.tset_builder import TSetBuilder +from src.tsets_reducer import TSetReducer +from src.tset_merger import TSetMerger +from src.cool_visitor import FormatVisitor + + +def test(): + text = """ + class C inherits J { } ; + class A inherits B { } ; + class B inherits A { } ; + class C { } ; + class D inherits E { } ; + class E inherits F { } ; + class F inherits D { } ; + class G inherits F { } ; + """ + + ast = run_pipeline(text) + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + err = [ + "Type with the same name (C) already in context.", + 'Type "J" is not defined.', + "Parent type is already set for C.", + "A is involved in a cyclic heritage", + "D is involved in a cyclic heritage", + "A class Main with a method main most be provided", + ] + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + if errors != err: + print(errors) + assert False + + assert True + + +test() diff --git a/test/test_main.py b/test/test_main.py new file mode 100644 index 000000000..02c8b6bd9 --- /dev/null +++ b/test/test_main.py @@ -0,0 +1,61 @@ +from run_pipeline import run_pipeline +from src.type_collector import TypeCollector +from src.type_builder import TypeBuilder +from src.type_checker import TypeChecker +from src.tset_builder import TSetBuilder +from src.tsets_reducer import TSetReducer +from src.tset_merger import TSetMerger +from src.cool_visitor import FormatVisitor + + +def test(): + text = """ + class Main inherits Point { + x : String ; + init ( n : String , m : Int) : Int { + { + n <- "Testing main" ; + m <- 1 + 2 ; + } } ; + } ; + class Point { + x : AUTO_TYPE ; + y : AUTO_TYPE ; + init ( n : String , m : Int ) : Int { + { + x <- n ; + y <- m ; + } } ; + main ( n : String , m : Int ) : Int { + { + x <- n ; + y <- m ; + } } ; + } ; + """ + + ast = run_pipeline(text) + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + err = [ + 'Attribute "x" is already defined in Main.', + "A class Main with a method main most be provided", + ] + + if errors != err: + print(errors) + assert False + + assert True + diff --git a/test/test_main1.py b/test/test_main1.py new file mode 100644 index 000000000..664e79c3f --- /dev/null +++ b/test/test_main1.py @@ -0,0 +1,62 @@ +from run_pipeline import run_pipeline +from src.type_collector import TypeCollector +from src.type_builder import TypeBuilder +from src.type_checker import TypeChecker +from src.tset_builder import TSetBuilder +from src.tsets_reducer import TSetReducer +from src.tset_merger import TSetMerger +from src.cool_visitor import FormatVisitor + + +def test(): + text = """ + class Main inherits Point { + x : String ; + init ( n : String , m : Int) : Int { + { + n <- "Testing main" ; + m <- 1 + 2 ; + } } ; + + main ( n : String , m : Int ) : Int { + { + n <- "Buen dia" ; + m <- 3 ; + } } ; + } ; + class Point { + x : AUTO_TYPE ; + y : AUTO_TYPE ; + init ( n : String , m : Int ) : Int { + { + x <- n ; + y <- m ; + } } ; + } ; + """ + + ast = run_pipeline(text) + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + err = [ + 'Attribute "x" is already defined in Main.', + '"main" method in class Main does not receive any parameters', + ] + + if errors != err: + print(errors) + assert False + + assert True + diff --git a/test/test_main2.py b/test/test_main2.py new file mode 100644 index 000000000..1e62adb0e --- /dev/null +++ b/test/test_main2.py @@ -0,0 +1,59 @@ +from run_pipeline import run_pipeline +from src.type_collector import TypeCollector +from src.type_builder import TypeBuilder +from src.type_checker import TypeChecker +from src.tset_builder import TSetBuilder +from src.tsets_reducer import TSetReducer +from src.tset_merger import TSetMerger +from src.cool_visitor import FormatVisitor + + +def test(): + text = """ + class Main inherits Point { + x : String ; + init ( n : String , m : Int) : Int { + { + n <- "Testing main" ; + m <- 1 + 2 ; + } } ; + + main ( ) : String + { + "Buen dia" + }; + } ; + class Point { + x : AUTO_TYPE ; + y : AUTO_TYPE ; + init ( n : String , m : Int ) : Int { + { + x <- n ; + y <- m ; + } } ; + } ; + """ + + ast = run_pipeline(text) + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + err = [ + 'Attribute "x" is already defined in Main.', + ] + + if errors != err: + print(errors) + assert False + + assert True diff --git a/test/test_merger.py b/test/test_merger.py index b96ced14d..b613b283b 100644 --- a/test/test_merger.py +++ b/test/test_merger.py @@ -65,8 +65,7 @@ class Point inherits A { checker = TypeChecker(context, errors) checker.visit(ast, None) - print(errors) - if errors != []: + if errors != ["A class Main with a method main most be provided"]: print(errors) assert False @@ -100,6 +99,8 @@ class Point inherits A { print(tree) assert errors == [ + "A class Main with a method main most be provided", + "A class Main with a method main most be provided", "Expression after 'while' must be bool, current is Object", 'Operation is not defined between "Object" and "Int".', 'Cannot convert "Object" into "Int".', diff --git a/test/test_redefinitions.py b/test/test_redefinitions.py new file mode 100644 index 000000000..4f5e7560b --- /dev/null +++ b/test/test_redefinitions.py @@ -0,0 +1,61 @@ +from run_pipeline import run_pipeline +from src.type_collector import TypeCollector +from src.type_builder import TypeBuilder +from src.type_checker import TypeChecker +from src.tset_builder import TSetBuilder +from src.tsets_reducer import TSetReducer +from src.tset_merger import TSetMerger +from src.cool_visitor import FormatVisitor + + +def test(): + + text = """ + + class B inherits Point { + x : String ; + init ( n : String , z : Int , z : Int) : Bool { + { + n <- "ok" ; + z <- 1 + 3 ; + } } ; + } ; + class Point { + x : AUTO_TYPE ; + y : AUTO_TYPE ; + init ( n : Int , m : Int ) : Int { + { + x <- n ; + y <- m ; + } } ; + } ; + + """ + + print("corriendo") + ast = run_pipeline(text) + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + default_errs = [ + 'Attribute "x" is already defined in B.', + "A class Main with a method main most be provided", + "More tan one param in method init has the name z", + 'Cannot convert "Int" into "Bool".', + 'Method "init" already defined in "an ancestor of B" with a different signature.', + ] + if errors != default_errs: + print(errors) + assert False + + assert True diff --git a/test/test_reducer.py b/test/test_reducer.py index c40c1d52a..143a70d62 100644 --- a/test/test_reducer.py +++ b/test/test_reducer.py @@ -74,4 +74,4 @@ class Point inherits A { print(context) print(reduced_set) - assert errors == [] + assert errors == ["A class Main with a method main most be provided"] diff --git a/test/test_reducer2.py b/test/test_reducer2.py index 36a4a4982..16516061d 100644 --- a/test/test_reducer2.py +++ b/test/test_reducer2.py @@ -50,4 +50,4 @@ class Point inherits A { print(context) print(reduced_set) - assert errors == [] + assert errors == ["A class Main with a method main most be provided"] diff --git a/test/test_reducer3.py b/test/test_reducer3.py index 6e263a003..8e0fefe96 100644 --- a/test/test_reducer3.py +++ b/test/test_reducer3.py @@ -52,4 +52,4 @@ class Point inherits A { print(context) print(reduced_set) - assert errors == [] + assert errors == ["A class Main with a method main most be provided"] diff --git a/test/test_tset_builder.py b/test/test_tset_builder.py index c2795d0c0..c641539ce 100644 --- a/test/test_tset_builder.py +++ b/test/test_tset_builder.py @@ -76,4 +76,4 @@ class C { print(context) print(tset) - assert errors == [] + assert errors == ["A class Main with a method main most be provided"] diff --git a/test/test_type_builder.py b/test/test_type_builder.py index 049bf89f2..2a8516f83 100644 --- a/test/test_type_builder.py +++ b/test/test_type_builder.py @@ -36,4 +36,4 @@ class Point { print("Context:") print(context) - assert errors == [] + assert errors == ["A class Main with a method main most be provided"] diff --git a/test/test_type_checker.py b/test/test_type_checker.py index 1cffb87de..9bdd5f4c9 100644 --- a/test/test_type_checker.py +++ b/test/test_type_checker.py @@ -72,4 +72,4 @@ class C { print(context) print(scope) - assert errors == [] + assert errors == ["A class Main with a method main most be provided"] From c51f8d4763c29b380d49e447603efa2ec8f93510 Mon Sep 17 00:00:00 2001 From: Gaby Date: Mon, 14 Dec 2020 07:59:06 -0500 Subject: [PATCH 020/162] Add String and Object methods --- notes.txt | 117 +++++++++++++++++++++++++++++++++++++++++++- src/type_builder.py | 55 ++++++++++++++------- test/test_adr.py | 2 +- test/test_let.py | 70 ++++++++++++++++++++++++++ 4 files changed, 223 insertions(+), 21 deletions(-) create mode 100644 test/test_let.py diff --git a/notes.txt b/notes.txt index e19b4d06a..7d86e4caf 100644 --- a/notes.txt +++ b/notes.txt @@ -1,4 +1,119 @@ Revisar: -Lo mas importante y que puede afectar la inferencia es lo de type builder, -la seccion que annade los metodos de string \ No newline at end of file +la seccion que annade los metodos de string y object + +-por que cuando hay dos variables con un mismo nombre en el let no nos quedamos con la ultima? +(probar otros casos de ese archivo let) + +text = ''' + class A { + b : AUTO_TYPE ; + a : AUTO_TYPE ; + + f ( ) : Int { { + let x : String , x : AUTO_TYPE <- a + b in x ; + } } ; + } ; + +''' + +En este caso si lo hace, porque no da error antes con que lo que se devuelve no se conforma: +class A { + b : AUTO_TYPE ; + a : AUTO_TYPE ; + d : AUTO_TYPE ; + + f ( ) : Int { { + d <- let x : String, x : AUTO_TYPE <- a + b , self : AUTO_TYPE , x : AUTO_TYPE <- let c : AUTO_TYPE in a in x ; + a; + } } ; + } ; + +En este tambien porque el tipo de retorno no esta definido explicitamente: + +class A { + b : AUTO_TYPE ; + a : AUTO_TYPE ; + + f ( ) : AUTO_TYPE { { + let x : String , x : AUTO_TYPE <- a + b , self : AUTO_TYPE , x : AUTO_TYPE <- let c : AUTO_TYPE in a in x ; + } } ; + } ; + +-Que hacemos con los void? Creo que deberian utilizarse para la inicializacion +por default para casos como los de let(se dice que cuando no se provee inicializacion +se utiliza la de default de ese tipo) + +-Que se espera con lo siguiente?: +se_jodio_el_self = ''' + class A { + b : AUTO_TYPE ; + a : AUTO_TYPE ; + c : String ; + f ( ) : Int { { + case self of + x : Int => x ; + y : AUTO_TYPE => y ; + esac ; + } } ; + } ; + +-Esto no lo inferimos no? O sea b no se deduce int segun el tipo de retorno de f +class A { + b : AUTO_TYPE ; + a : AUTO_TYPE ; + c : String ; + f ( ) : Int { { + b <- foo ( a ) ; + b ; + } } ; + + foo ( k : AUTO_TYPE ) : AUTO_TYPE { k <- a } ; + } ; + +-Esto siguiente da error por el tema de que en las clases que heredan no se ven los atributos del padre(Probar tambien los otros tres que viene atras en inference.txt de Carmita): + +class B { + k : AUTO_TYPE ; + } ; + + class A inherits B { + b : AUTO_TYPE ; + a : AUTO_TYPE ; + c : String ; + f ( ) : Int { { + b <- k + 1 ; + b ; + } } ; + + foo ( k : AUTO_TYPE ) : AUTO_TYPE { k <- a } ; + } ; + +-En este caso al final init no deberia ser POint en vez de selftype?: +class Point { + x : AUTO_TYPE ; + y : AUTO_TYPE ; + init ( n : Int , m : Int ) : SELF_TYPE { { + x <- n ; + y <- m ; + } } ; +} ; + +-Por que en el ejemplo siguiente main no devuekve Point? +class Point { + succ ( n : AUTO_TYPE ) : AUTO_TYPE { n + 1 } ; + translate ( n : AUTO_TYPE , m : AUTO_TYPE ) : SELF_TYPE { self } ; +} ; + +class Main { + step ( p : AUTO_TYPE ) : AUTO_TYPE { p . translate ( 1 , 1 ) } ; + + main ( ) : Object { + let p : AUTO_TYPE <- new Point in { + step ( p ) ; + } + } ; +} ; + +-Probar test1 \ No newline at end of file diff --git a/src/type_builder.py b/src/type_builder.py index 6e95d17e6..51f94db87 100644 --- a/src/type_builder.py +++ b/src/type_builder.py @@ -30,7 +30,9 @@ def visit(self, node): self_type = self.context.get_type("SELF_TYPE") int_type = self.context.get_type("Int") string_type = self.context.get_type("String") + object_type = self.context.get_type("Object") + # IO parent_tset = Tset() parent_tset.locals["out_string"] = {"SELF_TYPE"} parent_tset.locals["out_int"] = {"SELF_TYPE"} @@ -51,25 +53,40 @@ def visit(self, node): method = io_type.define_method("in_int", [], [], int_type) method.tset = Tset(parent_tset) - # # -------String - # parent_tset = Tset() - # parent_tset.locals["concat"] = {"String"} - # parent_tset.locals["substr"] = {"String"} - # parent_tset.locals["length"] = {"Int"} - - # method = string_type.define_method("concat", ["s"], [string_type], string_type) - # method.tset = Tset(parent_tset) - # method.tset.locals["s"] = {"String"} - - # method = string_type.define_method( - # "substr", ["i", "l"], [int_type, int_type], string_type - # ) - # method.tset = Tset(parent_tset) - # method.tset.locals["i"] = {"Int"} - # method.tset.locals["l"] = {"Int"} - - # method = string_type.define_method("length", [], [], int_type) - # method.tset = Tset(parent_tset) + # -------String + parent_tset = Tset() + parent_tset.locals["concat"] = {"String"} + parent_tset.locals["substr"] = {"String"} + parent_tset.locals["length"] = {"Int"} + + method = string_type.define_method("concat", ["s"], [string_type], string_type) + method.tset = Tset(parent_tset) + method.tset.locals["s"] = {"String"} + + method = string_type.define_method( + "substr", ["i", "l"], [int_type, int_type], string_type + ) + method.tset = Tset(parent_tset) + method.tset.locals["i"] = {"Int"} + method.tset.locals["l"] = {"Int"} + + method = string_type.define_method("length", [], [], int_type) + method.tset = Tset(parent_tset) + + # Object + parent_tset = Tset() + parent_tset.locals["abort"] = {"Object"} + parent_tset.locals["type_name"] = {"String"} + parent_tset.locals["copy"] = {"SELF_TYPE"} + + method = object_type.define_method("abort", [], [], object_type) + method.tset = Tset(parent_tset) + + method = object_type.define_method("type_name", [], [], string_type) + method.tset = Tset(parent_tset) + + method = object_type.define_method("copy", [], [], self_type) + method.tset = Tset(parent_tset) # -------------------- diff --git a/test/test_adr.py b/test/test_adr.py index a62cc1c42..ddfd1a571 100644 --- a/test/test_adr.py +++ b/test/test_adr.py @@ -89,4 +89,4 @@ class Main { tree = tree.replace("\\", "") assert tree == final_tree - assert errors == ['Method "length" is not defined in String.'] + assert errors == [] diff --git a/test/test_let.py b/test/test_let.py new file mode 100644 index 000000000..09d32016b --- /dev/null +++ b/test/test_let.py @@ -0,0 +1,70 @@ +from run_pipeline import run_pipeline +from src.type_collector import TypeCollector +from src.type_builder import TypeBuilder +from src.type_checker import TypeChecker +from src.tset_builder import TSetBuilder +from src.tsets_reducer import TSetReducer +from src.tset_merger import TSetMerger +from src.cool_visitor import FormatVisitor + + +def test(): + text = """ + class A { + b : AUTO_TYPE ; + a : AUTO_TYPE ; + + f ( ) : Int { { + let x : AUTO_TYPE <- a + b in x ; + } }; + }; + """ + + ast = run_pipeline(text) + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + if errors != ["A class Main with a method main most be provided"]: + print(errors) + assert False + + tset_builder = TSetBuilder(context, errors) + tset = tset_builder.visit(ast, None) + + tset_reducer = TSetReducer(context, errors) + reduced_set = tset_reducer.visit(ast, tset) + + tset_merger = TSetMerger(context, errors) + tset_merger.visit(ast, reduced_set) + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + formatter = FormatVisitor() + tree = formatter.visit(ast) + + print("Errors:", errors) + print("Context:") + print(context) + print(reduced_set) + print(tree) + + assert True From 9161d5349a3369d89421e829b77b5047c1918ad5 Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Mon, 14 Dec 2020 11:51:38 -0500 Subject: [PATCH 021/162] Add test description. --- notes.txt | 119 ------------------------------------- test/test_1.py | 5 +- test/test_12.py | 12 +++- test/test_2.py | 6 ++ test/test_4.py | 16 ++++- test/test_6.py | 6 ++ test/test_7.py | 8 +++ test/test_8.py | 3 + test/test_9.py | 2 +- test/test_adr.py | 2 +- test/test_cycher.py | 13 ++-- test/test_cycher2.py | 3 + test/test_cycher3.py | 2 + test/test_let.py | 5 +- test/test_main.py | 8 +-- test/test_main1.py | 9 +-- test/test_main2.py | 8 +-- test/test_redefinitions.py | 6 +- 18 files changed, 71 insertions(+), 162 deletions(-) delete mode 100644 notes.txt diff --git a/notes.txt b/notes.txt deleted file mode 100644 index 7d86e4caf..000000000 --- a/notes.txt +++ /dev/null @@ -1,119 +0,0 @@ -Revisar: - --Lo mas importante y que puede afectar la inferencia es lo de type builder, -la seccion que annade los metodos de string y object - --por que cuando hay dos variables con un mismo nombre en el let no nos quedamos con la ultima? -(probar otros casos de ese archivo let) - -text = ''' - class A { - b : AUTO_TYPE ; - a : AUTO_TYPE ; - - f ( ) : Int { { - let x : String , x : AUTO_TYPE <- a + b in x ; - } } ; - } ; - -''' - -En este caso si lo hace, porque no da error antes con que lo que se devuelve no se conforma: -class A { - b : AUTO_TYPE ; - a : AUTO_TYPE ; - d : AUTO_TYPE ; - - f ( ) : Int { { - d <- let x : String, x : AUTO_TYPE <- a + b , self : AUTO_TYPE , x : AUTO_TYPE <- let c : AUTO_TYPE in a in x ; - a; - } } ; - } ; - -En este tambien porque el tipo de retorno no esta definido explicitamente: - -class A { - b : AUTO_TYPE ; - a : AUTO_TYPE ; - - f ( ) : AUTO_TYPE { { - let x : String , x : AUTO_TYPE <- a + b , self : AUTO_TYPE , x : AUTO_TYPE <- let c : AUTO_TYPE in a in x ; - } } ; - } ; - --Que hacemos con los void? Creo que deberian utilizarse para la inicializacion -por default para casos como los de let(se dice que cuando no se provee inicializacion -se utiliza la de default de ese tipo) - --Que se espera con lo siguiente?: -se_jodio_el_self = ''' - class A { - b : AUTO_TYPE ; - a : AUTO_TYPE ; - c : String ; - f ( ) : Int { { - case self of - x : Int => x ; - y : AUTO_TYPE => y ; - esac ; - } } ; - } ; - --Esto no lo inferimos no? O sea b no se deduce int segun el tipo de retorno de f -class A { - b : AUTO_TYPE ; - a : AUTO_TYPE ; - c : String ; - f ( ) : Int { { - b <- foo ( a ) ; - b ; - } } ; - - foo ( k : AUTO_TYPE ) : AUTO_TYPE { k <- a } ; - } ; - --Esto siguiente da error por el tema de que en las clases que heredan no se ven los atributos del padre(Probar tambien los otros tres que viene atras en inference.txt de Carmita): - -class B { - k : AUTO_TYPE ; - } ; - - class A inherits B { - b : AUTO_TYPE ; - a : AUTO_TYPE ; - c : String ; - f ( ) : Int { { - b <- k + 1 ; - b ; - } } ; - - foo ( k : AUTO_TYPE ) : AUTO_TYPE { k <- a } ; - } ; - --En este caso al final init no deberia ser POint en vez de selftype?: -class Point { - x : AUTO_TYPE ; - y : AUTO_TYPE ; - init ( n : Int , m : Int ) : SELF_TYPE { { - x <- n ; - y <- m ; - } } ; -} ; - --Por que en el ejemplo siguiente main no devuekve Point? -class Point { - succ ( n : AUTO_TYPE ) : AUTO_TYPE { n + 1 } ; - translate ( n : AUTO_TYPE , m : AUTO_TYPE ) : SELF_TYPE { self } ; -} ; - -class Main { - step ( p : AUTO_TYPE ) : AUTO_TYPE { p . translate ( 1 , 1 ) } ; - - main ( ) : Object { - let p : AUTO_TYPE <- new Point in { - step ( p ) ; - } - } ; -} ; - --Probar test1 \ No newline at end of file diff --git a/test/test_1.py b/test/test_1.py index 9b893e76a..4efd04d6b 100644 --- a/test/test_1.py +++ b/test/test_1.py @@ -7,7 +7,10 @@ from src.tset_merger import TSetMerger from src.cool_visitor import FormatVisitor - +# Trabajando con self. Arreglado el error de la primera entrega +# Se infiere: +# main() : Main +# pp : Main def test(): text = """ diff --git a/test/test_12.py b/test/test_12.py index 7ed78cb81..bc2192eae 100644 --- a/test/test_12.py +++ b/test/test_12.py @@ -7,7 +7,17 @@ from src.tset_merger import TSetMerger from src.cool_visitor import FormatVisitor - +# Probando inferir los tipos de los parametros de un metodo a partir de los argumentos con los que se llama +# Se infiere: +# ---En el let de la clase Main ---- +# id : Int por la asignacion id <- self.in_int(); +# name : String por la asignacion name <- self.in_string(); +# email : String por la asignacion email <- self.in_string(); +# --- En el metodo init() de la clase User--- +# id_ : Int porque en el llamado (new User).init(id, name, email) id es de tipo Int +# name_ : String porque en el llamado (new User).init(id, name, email) name es de tipo String +# email_ : String porque en el llamado (new User).init(id, name, email) email_ es de tipo String +# def test(): text = """ (* Testing IO *) diff --git a/test/test_2.py b/test/test_2.py index a2e9a01b0..0a2a282fc 100644 --- a/test/test_2.py +++ b/test/test_2.py @@ -7,6 +7,12 @@ from src.tset_merger import TSetMerger from src.cool_visitor import FormatVisitor +# Infiriendo el tipo de retorno del metodo a partir del body. Probando inicializar variables en el let. Arreglado el error del case. +# Se inferiere: +# main() : String. +# x : Int +# y : Int + def test(): text = """ diff --git a/test/test_4.py b/test/test_4.py index d77f51529..832fd7b4a 100644 --- a/test/test_4.py +++ b/test/test_4.py @@ -7,6 +7,13 @@ from src.tset_merger import TSetMerger from src.cool_visitor import FormatVisitor +# Trabajando con IO. Probando inferir el tipo de 'a' a partir del tipo que recibe el metodo out_string() +# Se infiere: +# main(): IO +# a : String +# x : Int +# y : IO + def test(): text = """ @@ -34,7 +41,9 @@ class Main { checker = TypeChecker(context, errors) checker.visit(ast, None) - if errors != ['"main" method in class Main does not receive any parameters']: + if errors != [ + '"main" method in class Main does not receive any parameters', + ]: print(errors) assert False @@ -67,4 +76,7 @@ class Main { print(reduced_set) print(tree) - assert True + assert errors == [ + '"main" method in class Main does not receive any parameters', + '"main" method in class Main does not receive any parameters', + ] diff --git a/test/test_6.py b/test/test_6.py index 250f8592b..c99a49acb 100644 --- a/test/test_6.py +++ b/test/test_6.py @@ -7,6 +7,12 @@ from src.tset_merger import TSetMerger from src.cool_visitor import FormatVisitor +# Probando inferencia en funciones recursivas +# Se infiere: +# m : Int porque se usa en operacion aritmetica +# n : Int porque se usa en operacion aritmetica +# ackerman() : Int porque es la interseccion entre los tipos que devuelve el then (Int) y los que devuelve el else(todos pues es AUTO_TYPE) + def test(): text = """ diff --git a/test/test_7.py b/test/test_7.py index d273f8d1a..9af43578f 100644 --- a/test/test_7.py +++ b/test/test_7.py @@ -7,6 +7,14 @@ from src.tset_merger import TSetMerger from src.cool_visitor import FormatVisitor +# Probando inferencia en funciones recursivas +# Se infiere: +# a : Int porque se usa en una operacion aritmetica +# b : Int porque se usa en una operacion aritmetica +# f() : Int +# g() : Int +# Una vez inferido el tipo de a y b, en las proximas pasadas se infiere que el if devuelve Int en ambos metodos + def test(): text = """ diff --git a/test/test_8.py b/test/test_8.py index b8a821b5c..f7731ae37 100644 --- a/test/test_8.py +++ b/test/test_8.py @@ -7,6 +7,9 @@ from src.tset_merger import TSetMerger from src.cool_visitor import FormatVisitor +# Aqui no inferimos el tipo de x0 y y0 a partir de x e y. +# En la asignacion solo se reduce la variable al tipo de la expresion que se le esta asinando, no viceversa. + def test(): text = """ diff --git a/test/test_9.py b/test/test_9.py index f51f3d79e..9e7f8e5c1 100644 --- a/test/test_9.py +++ b/test/test_9.py @@ -7,7 +7,7 @@ from src.tset_merger import TSetMerger from src.cool_visitor import FormatVisitor - +# En este caso todas las variables son Int porque d participa en una operacion aritmetica. f tambien se infiere que devuelve Int. def test(): text = """ diff --git a/test/test_adr.py b/test/test_adr.py index ddfd1a571..dea30bbcc 100644 --- a/test/test_adr.py +++ b/test/test_adr.py @@ -7,7 +7,7 @@ from src.tset_merger import TSetMerger from src.cool_visitor import FormatVisitor - +# Probando case y let anidados def test(): text = """ diff --git a/test/test_cycher.py b/test/test_cycher.py index eb251e598..4eec7ecf0 100644 --- a/test/test_cycher.py +++ b/test/test_cycher.py @@ -7,7 +7,7 @@ from src.tset_merger import TSetMerger from src.cool_visitor import FormatVisitor - +# Probando detectar herencia ciclica def test(): text = """ class B inherits A { @@ -31,13 +31,8 @@ class A inherits B { } ; checker = TypeChecker(context, errors) checker.visit(ast, None) - - if errors != [ + print(errors) + assert errors == [ "B is involved in a cyclic heritage", "A class Main with a method main most be provided", - ]: - print(errors) - assert False - - assert True - + ] diff --git a/test/test_cycher2.py b/test/test_cycher2.py index e5b79b639..fc7dcf4ab 100644 --- a/test/test_cycher2.py +++ b/test/test_cycher2.py @@ -8,6 +8,9 @@ from src.cool_visitor import FormatVisitor +# Probando detectar herencia ciclica + + def test(): text = """ class B inherits A { diff --git a/test/test_cycher3.py b/test/test_cycher3.py index 82f546b2c..766a63170 100644 --- a/test/test_cycher3.py +++ b/test/test_cycher3.py @@ -7,6 +7,8 @@ from src.tset_merger import TSetMerger from src.cool_visitor import FormatVisitor +# Probando detectar herencia ciclica + def test(): text = """ diff --git a/test/test_let.py b/test/test_let.py index 09d32016b..777a8017b 100644 --- a/test/test_let.py +++ b/test/test_let.py @@ -67,4 +67,7 @@ class A { print(reduced_set) print(tree) - assert True + assert errors == [ + "A class Main with a method main most be provided", + "A class Main with a method main most be provided", + ] diff --git a/test/test_main.py b/test/test_main.py index 02c8b6bd9..d423a8164 100644 --- a/test/test_main.py +++ b/test/test_main.py @@ -48,14 +48,8 @@ class Point { checker = TypeChecker(context, errors) checker.visit(ast, None) - err = [ + assert errors == [ 'Attribute "x" is already defined in Main.', "A class Main with a method main most be provided", ] - if errors != err: - print(errors) - assert False - - assert True - diff --git a/test/test_main1.py b/test/test_main1.py index 664e79c3f..e70bc933a 100644 --- a/test/test_main1.py +++ b/test/test_main1.py @@ -49,14 +49,7 @@ class Point { checker = TypeChecker(context, errors) checker.visit(ast, None) - err = [ + assert errors == [ 'Attribute "x" is already defined in Main.', '"main" method in class Main does not receive any parameters', ] - - if errors != err: - print(errors) - assert False - - assert True - diff --git a/test/test_main2.py b/test/test_main2.py index 1e62adb0e..74ef06757 100644 --- a/test/test_main2.py +++ b/test/test_main2.py @@ -48,12 +48,6 @@ class Point { checker = TypeChecker(context, errors) checker.visit(ast, None) - err = [ + assert errors == [ 'Attribute "x" is already defined in Main.', ] - - if errors != err: - print(errors) - assert False - - assert True diff --git a/test/test_redefinitions.py b/test/test_redefinitions.py index 4f5e7560b..17549030f 100644 --- a/test/test_redefinitions.py +++ b/test/test_redefinitions.py @@ -47,15 +47,11 @@ class Point { checker = TypeChecker(context, errors) checker.visit(ast, None) - default_errs = [ + assert errors == [ 'Attribute "x" is already defined in B.', "A class Main with a method main most be provided", "More tan one param in method init has the name z", 'Cannot convert "Int" into "Bool".', 'Method "init" already defined in "an ancestor of B" with a different signature.', ] - if errors != default_errs: - print(errors) - assert False - assert True From 7698225a8c54284ddecf384c934bb96d0508bd2c Mon Sep 17 00:00:00 2001 From: Gaby Date: Mon, 14 Dec 2020 15:54:49 -0500 Subject: [PATCH 022/162] Test Self --- notes.txt | 5 ++++- test.py => test/test_0.py | 16 +++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) rename test.py => test/test_0.py (74%) diff --git a/notes.txt b/notes.txt index 7d86e4caf..f41a1f169 100644 --- a/notes.txt +++ b/notes.txt @@ -116,4 +116,7 @@ class Main { } ; } ; --Probar test1 \ No newline at end of file +-Probar test1 + +-probar que no se joda con la herencia ciclica buscando eternamente por emtodos o +atributos que no existen \ No newline at end of file diff --git a/test.py b/test/test_0.py similarity index 74% rename from test.py rename to test/test_0.py index e60a05ce8..753e7810f 100644 --- a/test.py +++ b/test/test_0.py @@ -31,10 +31,11 @@ class Cons { false } ; - init ( hd : Int , tl : String ) : String { + init ( hd : Int , tl : String ) : AUTO_TYPE { { xcar <- hd ; xcdr <- tl ; + self; } } ; } ; @@ -55,7 +56,7 @@ class Cons { checker = TypeChecker(context, errors) checker.visit(ast, None) - if errors != []: + if errors != ["A class Main with a method main most be provided"]: print(errors) assert False @@ -82,7 +83,10 @@ class Cons { formatter = FormatVisitor() tree = formatter.visit(ast) - if errors != []: + if errors != [ + "A class Main with a method main most be provided", + "A class Main with a method main most be provided", + ]: print("Errors:", errors) print("Context:") print(context) @@ -90,13 +94,11 @@ class Cons { print(tree) assert False - final_tree = """__ProgramNode [ ... ]__ClassDeclarationNode: class C inherits J { ... }__ClassDeclarationNode: class A inherits B { ... }__ClassDeclarationNode: class B inherits A { ... }__ClassDeclarationNode: class C { ... }__ClassDeclarationNode: class D inherits E { ... }__ClassDeclarationNode: class E inherits F { ... }__ClassDeclarationNode: class F inherits D { ... }__ClassDeclarationNode: class G inherits F { ... }""" - + final_tree = """__ProgramNode [ ... ]__ClassDeclarationNode: class Cons { ... }__AttrDeclarationNode: xcar : Int <- __NONE__AttrDeclarationNode: xcdr : String <- __NONE__FuncDeclarationNode: isNill() : Bool { }__ BooleanNode: false__FuncDeclarationNode: init(hd:Int, tl:String) : Cons { }__BlockNode: {; ... ;}__AssignNode: xcar <- __ VariableNode: hd__AssignNode: xcdr <- __ VariableNode: tl__ VariableNode: self""" tree = tree.replace("\t", "") tree = tree.replace("\n", "") tree = tree.replace("\\", "") + print(tree) assert tree == final_tree - -test() From 23c814e3de754beb3dd14bb09c2bd9050bb6699b Mon Sep 17 00:00:00 2001 From: Gaby Date: Mon, 14 Dec 2020 18:59:28 -0500 Subject: [PATCH 023/162] Cyclic Heritage Bug Fixed --- src/cmp/semantic.py | 22 +++++++++++++++++---- src/type_builder.py | 2 +- test/test_mnotfound.py | 45 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 5 deletions(-) create mode 100644 test/test_mnotfound.py diff --git a/src/cmp/semantic.py b/src/cmp/semantic.py index d217c36e6..0cd3cfbb7 100644 --- a/src/cmp/semantic.py +++ b/src/cmp/semantic.py @@ -56,16 +56,23 @@ def set_parent(self, parent): raise SemanticError(f"Is not possible to inherit from {parent.name}") self.parent = parent - def get_attribute(self, name: str): + def get_attribute(self, name: str, visited=None): + if visited is None: + visited = [] try: return next(attr for attr in self.attributes if attr.name == name) except StopIteration: + visited.append(self.name) if self.parent is None: raise SemanticError( f'Attribute "{name}" is not defined in {self.name}.' ) try: - return self.parent.get_attribute(name) + if self.parent.name in visited: + raise SemanticError( + f'Attribute "{name}" is not defined in {self.name}.' + ) + return self.parent.get_attribute(name, visited=visited) except SemanticError: raise SemanticError( f'Attribute "{name}" is not defined in {self.name}.' @@ -83,14 +90,21 @@ def define_attribute(self, name: str, typex): f'Attribute "{name}" is already defined in {self.name}.' ) - def get_method(self, name: str, non_rec=False): + def get_method(self, name: str, non_rec=False, visited=None): + if visited is None: + visited = [] try: return next(method for method in self.methods if method.name == name) except StopIteration: + visited.append(self.name) if non_rec or self.parent is None: raise SemanticError(f'Method "{name}" is not defined in {self.name}.') try: - return self.parent.get_method(name) + if self.parent.name in visited: + raise SemanticError( + f'Method "{name}" is not defined in {self.name}.' + ) + return self.parent.get_method(name, visited=visited) except SemanticError: raise SemanticError(f'Method "{name}" is not defined in {self.name}.') diff --git a/src/type_builder.py b/src/type_builder.py index 51f94db87..ed0f0119c 100644 --- a/src/type_builder.py +++ b/src/type_builder.py @@ -137,7 +137,7 @@ def visit(self, node): queue.append(not_visited[0]) try: - main_meth = self.context.get_type("Main").get_method("main", True) + main_meth = self.context.get_type("Main").get_method("main", non_rec=True) if len(main_meth.param_names) > 0: self.errors.append( '"main" method in class Main does not receive any parameters' diff --git a/test/test_mnotfound.py b/test/test_mnotfound.py new file mode 100644 index 000000000..3e93fd2af --- /dev/null +++ b/test/test_mnotfound.py @@ -0,0 +1,45 @@ +from run_pipeline import run_pipeline +from src.type_collector import TypeCollector +from src.type_builder import TypeBuilder +from src.type_checker import TypeChecker +from src.tset_builder import TSetBuilder +from src.tsets_reducer import TSetReducer +from src.tset_merger import TSetMerger +from src.cool_visitor import FormatVisitor + + +def test(): + text = """ + class A inherits B { }; + class B inherits A { + f ( ) : Int { + g() + } ; + } ; + """ + + print("corriendo") + ast = run_pipeline(text) + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + if errors != [ + "A is involved in a cyclic heritage", + "A class Main with a method main most be provided", + 'Method "g" is not defined in B.', + ]: + print(errors) + assert False + + assert True + From 5b49be56c8fbcb0ebf36ad52d53d51e0e793bf67 Mon Sep 17 00:00:00 2001 From: Gaby Date: Mon, 14 Dec 2020 19:43:56 -0500 Subject: [PATCH 024/162] Change names --- main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main.py b/main.py index 2195666ea..8781dd651 100644 --- a/main.py +++ b/main.py @@ -19,8 +19,8 @@ st.sidebar.header("About") st.sidebar.subheader("Segundo Proyecto de Compilacion: Cool Intrepreter") -st.sidebar.text("Amalia Ibarra Rodriguez") -st.sidebar.text("Gabriela B. Martinez Giraldo") +st.sidebar.text("Amalia Ibarra Rodríguez") +st.sidebar.text("Gabriela B. Martínez Giraldo") st.sidebar.text("Grupo: C-312") st.sidebar.text("Curso: 2019-2020") From f57e993ef6edba8be0fc67c312236fcc16f65d8b Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Tue, 13 Apr 2021 11:12:01 -0400 Subject: [PATCH 025/162] Add .directory and informe.pdf --- .directory | 7 +++++++ ...aI_barra_Gabriela_Martinez_c312_informe.pdf | Bin 0 -> 246202 bytes 2 files changed, 7 insertions(+) create mode 100644 .directory create mode 100644 AmaliaI_barra_Gabriela_Martinez_c312_informe.pdf diff --git a/.directory b/.directory new file mode 100644 index 000000000..d0e97ae24 --- /dev/null +++ b/.directory @@ -0,0 +1,7 @@ +[Dolphin] +Timestamp=2021,4,13,11,6,10 +Version=4 +ViewMode=1 + +[Settings] +HiddenFilesShown=true diff --git a/AmaliaI_barra_Gabriela_Martinez_c312_informe.pdf b/AmaliaI_barra_Gabriela_Martinez_c312_informe.pdf new file mode 100644 index 0000000000000000000000000000000000000000..20b458ab95b3d395d14fb21bf85b73300cb4c6ec GIT binary patch literal 246202 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�L>Lw_~e0h#_Wz$NQ4UB-Pmc33a@MsCnwx)eQYg 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 literal 0 HcmV?d00001 From 4627e06c67ace7fe767957fee5e0f11fe81efbdd Mon Sep 17 00:00:00 2001 From: Gaby Date: Fri, 16 Jul 2021 20:43:20 -0400 Subject: [PATCH 026/162] Merged old code with base Cool Cmp 2021 --- {test => customized_tests}/run_pipeline.py | 0 {test => customized_tests}/test_0.py | 0 {test => customized_tests}/test_1.py | 0 {test => customized_tests}/test_10.py | 0 {test => customized_tests}/test_11.py | 0 {test => customized_tests}/test_12.py | 0 {test => customized_tests}/test_2.py | 0 {test => customized_tests}/test_3.py | 0 {test => customized_tests}/test_4.py | 0 {test => customized_tests}/test_5.py | 0 {test => customized_tests}/test_6.py | 0 {test => customized_tests}/test_7.py | 0 {test => customized_tests}/test_8.py | 0 {test => customized_tests}/test_9.py | 0 {test => customized_tests}/test_IO.py | 0 {test => customized_tests}/test_adr.py | 0 {test => customized_tests}/test_cycher.py | 0 {test => customized_tests}/test_cycher2.py | 0 {test => customized_tests}/test_cycher3.py | 0 {test => customized_tests}/test_let.py | 0 {test => customized_tests}/test_main.py | 0 {test => customized_tests}/test_main1.py | 0 {test => customized_tests}/test_main2.py | 0 {test => customized_tests}/test_merger.py | 0 {test => customized_tests}/test_mnotfound.py | 0 {test => customized_tests}/test_parser1.py | 0 {test => customized_tests}/test_parser2.py | 0 {test => customized_tests}/test_parser3.py | 0 {test => customized_tests}/test_parser4.py | 0 {test => customized_tests}/test_parser5.py | 0 {test => customized_tests}/test_parser6.py | 0 {test => customized_tests}/test_redefinitions.py | 0 {test => customized_tests}/test_reducer.py | 0 {test => customized_tests}/test_reducer2.py | 0 {test => customized_tests}/test_reducer3.py | 0 {test => customized_tests}/test_tset_builder.py | 0 {test => customized_tests}/test_type_builder.py | 0 {test => customized_tests}/test_type_checker.py | 0 {test => customized_tests}/test_type_collector.py | 0 39 files changed, 0 insertions(+), 0 deletions(-) rename {test => customized_tests}/run_pipeline.py (100%) rename {test => customized_tests}/test_0.py (100%) rename {test => customized_tests}/test_1.py (100%) rename {test => customized_tests}/test_10.py (100%) rename {test => customized_tests}/test_11.py (100%) rename {test => customized_tests}/test_12.py (100%) rename {test => customized_tests}/test_2.py (100%) rename {test => customized_tests}/test_3.py (100%) rename {test => customized_tests}/test_4.py (100%) rename {test => customized_tests}/test_5.py (100%) rename {test => customized_tests}/test_6.py (100%) rename {test => customized_tests}/test_7.py (100%) rename {test => customized_tests}/test_8.py (100%) rename {test => customized_tests}/test_9.py (100%) rename {test => customized_tests}/test_IO.py (100%) rename {test => customized_tests}/test_adr.py (100%) rename {test => customized_tests}/test_cycher.py (100%) rename {test => customized_tests}/test_cycher2.py (100%) rename {test => customized_tests}/test_cycher3.py (100%) rename {test => customized_tests}/test_let.py (100%) rename {test => customized_tests}/test_main.py (100%) rename {test => customized_tests}/test_main1.py (100%) rename {test => customized_tests}/test_main2.py (100%) rename {test => customized_tests}/test_merger.py (100%) rename {test => customized_tests}/test_mnotfound.py (100%) rename {test => customized_tests}/test_parser1.py (100%) rename {test => customized_tests}/test_parser2.py (100%) rename {test => customized_tests}/test_parser3.py (100%) rename {test => customized_tests}/test_parser4.py (100%) rename {test => customized_tests}/test_parser5.py (100%) rename {test => customized_tests}/test_parser6.py (100%) rename {test => customized_tests}/test_redefinitions.py (100%) rename {test => customized_tests}/test_reducer.py (100%) rename {test => customized_tests}/test_reducer2.py (100%) rename {test => customized_tests}/test_reducer3.py (100%) rename {test => customized_tests}/test_tset_builder.py (100%) rename {test => customized_tests}/test_type_builder.py (100%) rename {test => customized_tests}/test_type_checker.py (100%) rename {test => customized_tests}/test_type_collector.py (100%) diff --git a/test/run_pipeline.py b/customized_tests/run_pipeline.py similarity index 100% rename from test/run_pipeline.py rename to customized_tests/run_pipeline.py diff --git a/test/test_0.py b/customized_tests/test_0.py similarity index 100% rename from test/test_0.py rename to customized_tests/test_0.py diff --git a/test/test_1.py b/customized_tests/test_1.py similarity index 100% rename from test/test_1.py rename to customized_tests/test_1.py diff --git a/test/test_10.py b/customized_tests/test_10.py similarity index 100% rename from test/test_10.py rename to customized_tests/test_10.py diff --git a/test/test_11.py b/customized_tests/test_11.py similarity index 100% rename from test/test_11.py rename to customized_tests/test_11.py diff --git a/test/test_12.py b/customized_tests/test_12.py similarity index 100% rename from test/test_12.py rename to customized_tests/test_12.py diff --git a/test/test_2.py b/customized_tests/test_2.py similarity index 100% rename from test/test_2.py rename to customized_tests/test_2.py diff --git a/test/test_3.py b/customized_tests/test_3.py similarity index 100% rename from test/test_3.py rename to customized_tests/test_3.py diff --git a/test/test_4.py b/customized_tests/test_4.py similarity index 100% rename from test/test_4.py rename to customized_tests/test_4.py diff --git a/test/test_5.py b/customized_tests/test_5.py similarity index 100% rename from test/test_5.py rename to customized_tests/test_5.py diff --git a/test/test_6.py b/customized_tests/test_6.py similarity index 100% rename from test/test_6.py rename to customized_tests/test_6.py diff --git a/test/test_7.py b/customized_tests/test_7.py similarity index 100% rename from test/test_7.py rename to customized_tests/test_7.py diff --git a/test/test_8.py b/customized_tests/test_8.py similarity index 100% rename from test/test_8.py rename to customized_tests/test_8.py diff --git a/test/test_9.py b/customized_tests/test_9.py similarity index 100% rename from test/test_9.py rename to customized_tests/test_9.py diff --git a/test/test_IO.py b/customized_tests/test_IO.py similarity index 100% rename from test/test_IO.py rename to customized_tests/test_IO.py diff --git a/test/test_adr.py b/customized_tests/test_adr.py similarity index 100% rename from test/test_adr.py rename to customized_tests/test_adr.py diff --git a/test/test_cycher.py b/customized_tests/test_cycher.py similarity index 100% rename from test/test_cycher.py rename to customized_tests/test_cycher.py diff --git a/test/test_cycher2.py b/customized_tests/test_cycher2.py similarity index 100% rename from test/test_cycher2.py rename to customized_tests/test_cycher2.py diff --git a/test/test_cycher3.py b/customized_tests/test_cycher3.py similarity index 100% rename from test/test_cycher3.py rename to customized_tests/test_cycher3.py diff --git a/test/test_let.py b/customized_tests/test_let.py similarity index 100% rename from test/test_let.py rename to customized_tests/test_let.py diff --git a/test/test_main.py b/customized_tests/test_main.py similarity index 100% rename from test/test_main.py rename to customized_tests/test_main.py diff --git a/test/test_main1.py b/customized_tests/test_main1.py similarity index 100% rename from test/test_main1.py rename to customized_tests/test_main1.py diff --git a/test/test_main2.py b/customized_tests/test_main2.py similarity index 100% rename from test/test_main2.py rename to customized_tests/test_main2.py diff --git a/test/test_merger.py b/customized_tests/test_merger.py similarity index 100% rename from test/test_merger.py rename to customized_tests/test_merger.py diff --git a/test/test_mnotfound.py b/customized_tests/test_mnotfound.py similarity index 100% rename from test/test_mnotfound.py rename to customized_tests/test_mnotfound.py diff --git a/test/test_parser1.py b/customized_tests/test_parser1.py similarity index 100% rename from test/test_parser1.py rename to customized_tests/test_parser1.py diff --git a/test/test_parser2.py b/customized_tests/test_parser2.py similarity index 100% rename from test/test_parser2.py rename to customized_tests/test_parser2.py diff --git a/test/test_parser3.py b/customized_tests/test_parser3.py similarity index 100% rename from test/test_parser3.py rename to customized_tests/test_parser3.py diff --git a/test/test_parser4.py b/customized_tests/test_parser4.py similarity index 100% rename from test/test_parser4.py rename to customized_tests/test_parser4.py diff --git a/test/test_parser5.py b/customized_tests/test_parser5.py similarity index 100% rename from test/test_parser5.py rename to customized_tests/test_parser5.py diff --git a/test/test_parser6.py b/customized_tests/test_parser6.py similarity index 100% rename from test/test_parser6.py rename to customized_tests/test_parser6.py diff --git a/test/test_redefinitions.py b/customized_tests/test_redefinitions.py similarity index 100% rename from test/test_redefinitions.py rename to customized_tests/test_redefinitions.py diff --git a/test/test_reducer.py b/customized_tests/test_reducer.py similarity index 100% rename from test/test_reducer.py rename to customized_tests/test_reducer.py diff --git a/test/test_reducer2.py b/customized_tests/test_reducer2.py similarity index 100% rename from test/test_reducer2.py rename to customized_tests/test_reducer2.py diff --git a/test/test_reducer3.py b/customized_tests/test_reducer3.py similarity index 100% rename from test/test_reducer3.py rename to customized_tests/test_reducer3.py diff --git a/test/test_tset_builder.py b/customized_tests/test_tset_builder.py similarity index 100% rename from test/test_tset_builder.py rename to customized_tests/test_tset_builder.py diff --git a/test/test_type_builder.py b/customized_tests/test_type_builder.py similarity index 100% rename from test/test_type_builder.py rename to customized_tests/test_type_builder.py diff --git a/test/test_type_checker.py b/customized_tests/test_type_checker.py similarity index 100% rename from test/test_type_checker.py rename to customized_tests/test_type_checker.py diff --git a/test/test_type_collector.py b/customized_tests/test_type_collector.py similarity index 100% rename from test/test_type_collector.py rename to customized_tests/test_type_collector.py From 63a668d435ed22cfb8dbb096bc3c82a34f09517b Mon Sep 17 00:00:00 2001 From: Gaby Date: Fri, 16 Jul 2021 21:58:55 -0400 Subject: [PATCH 027/162] Add report README CMP PRACT LAB --- README CMP PRACTICAS LAB.pdf | Bin 0 -> 173122 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100755 README CMP PRACTICAS LAB.pdf diff --git a/README CMP PRACTICAS LAB.pdf b/README CMP PRACTICAS LAB.pdf new file mode 100755 index 0000000000000000000000000000000000000000..b4e06dec4447c3a30d27d1370d982296741aef52 GIT binary patch literal 173122 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±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%0ANA}pep1|^~ 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

(X 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 z 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 Date: Wed, 9 Feb 2022 15:55:02 -0500 Subject: [PATCH 028/162] feat: add grammar, tokenizer and ast nodes --- doc/.team.yml.kate-swp | Bin 0 -> 2387 bytes src/ast_nodes.py | 175 +++++++++++++++++++ src/cool_grammar.py | 180 +++++++++++++++++++ src/cool_tokenizer.py | 43 +++++ src/cool_visitor.py | 339 ++++++++++++++++++++++++++++++++++++ src/coolc.sh | 2 +- src/errors.py | 70 ++++++++ src/lexical_analizer.py | 57 ++++++ src/parser_automatons.py | 225 ++++++++++++++++++++++++ src/shift_reduce_parsers.py | 274 +++++++++++++++++++++++++++++ src/tokens_rules.py | 212 ++++++++++++++++++++++ 11 files changed, 1576 insertions(+), 1 deletion(-) create mode 100644 doc/.team.yml.kate-swp create mode 100644 src/ast_nodes.py create mode 100644 src/cool_grammar.py create mode 100644 src/cool_tokenizer.py create mode 100644 src/cool_visitor.py create mode 100644 src/errors.py create mode 100644 src/lexical_analizer.py create mode 100644 src/parser_automatons.py create mode 100644 src/shift_reduce_parsers.py create mode 100644 src/tokens_rules.py diff --git a/doc/.team.yml.kate-swp b/doc/.team.yml.kate-swp new file mode 100644 index 0000000000000000000000000000000000000000..cf5a7aabaf35042c795735fb3786f1b602d0d391 GIT binary patch literal 2387 zcmZ9N%T82L5Jm6tEebSEg9@mPi4$MZjuVE)w4|d>xL?p{M@jGzMIp}o0;kUW495;k z{1yEQ&)T=jsyMib%PP(}wRcr@(=`3Z(}UTtJ)FKBKHA%#4M%tGHcd15G2Lx%wl}uF z%uRmY`t|M4*U#U7w>vdb>Ni)v-XuYJFm9dC@&B)a&%@K;d3Zl~0p1HT%!@I%D_UHbb0sJoFEC2DT<@D z_(SkjcosZ_KaC~*vHEYySqY@tK_Fr*2clI!uvc*@5TSd4_^=p=O$&jzINv>sXJk`h znQErPGSy6nWvZDD^Awi_ma8dWu9|Gb<*K<1%hi;hT_rA8%?9{F{b)j5K3>06ESQP~ zQ?ZWaepkF_mwUk~cGMkyqW-zYqYFEh?O+Xvy`8wUwAx^4X>W&hylDYTOKTBWTAH@7 zYe}sz+HJ)3lJaSAmXdTyc@WjWtC60SCS6L`bmk3~(&@Dtpw|)C0HxP!fR5ricsSUa?8F4w2uGi*E)yf((ntWMf*PX45T6N#hH;(0Du*9>WBQEi5=-@nbr;KfVfoY<_ zG|`Se(VksKofOV>`SCVKA9y(5eX?>|${", startSymbol=True) + class_list, def_class = G.NonTerminals(" ") + feature_list, def_attr, def_func = G.NonTerminals( + " " + ) + param_list, param = G.NonTerminals(" ") + expr, comp, arith, term, factor, element, atom = G.NonTerminals( + " " + ) + identifiers_list, identifier_init = G.NonTerminals(" ") + block, case_block, case_item = G.NonTerminals(" ") + func_call, arg_list = G.NonTerminals(" ") + + # terminals + classx, inherits, notx, isvoid = G.Terminals("class inherits not isvoid") + let, inx = G.Terminals("let in") + ifx, then, elsex, fi = G.Terminals("if then else fi") + whilex, loop, pool = G.Terminals("while loop pool") + case, of, esac = G.Terminals("case of esac") + semi, colon, comma, dot, opar, cpar, ocur, ccur, at, larrow, rarrow = G.Terminals( + "; : , . ( ) { } @ <- =>" + ) + equal, plus, minus, star, div, less, equal, lesseq, neg = G.Terminals( + "= + - * / < = <= ~" + ) + idx, num, new, string, true, false = G.Terminals("id int new string true false") + + # productions + program %= class_list, lambda h, s: ProgramNode(s[1]) + + class_list %= def_class + class_list, lambda h, s: [s[1]] + s[2] + class_list %= def_class, lambda h, s: [s[1]] + + def_class %= ( + classx + idx + ocur + feature_list + ccur + semi, + lambda h, s: ClassDeclarationNode(s[2], s[4]), + ) + def_class %= ( + classx + idx + inherits + idx + ocur + feature_list + ccur + semi, + lambda h, s: ClassDeclarationNode(s[2], s[6], s[4]), + ) + + feature_list %= def_attr + semi + feature_list, lambda h, s: [s[1]] + s[3] + feature_list %= def_func + semi + feature_list, lambda h, s: [s[1]] + s[3] + feature_list %= G.Epsilon, lambda h, s: [] + + def_attr %= ( + idx + colon + idx + larrow + expr, + lambda h, s: AttrDeclarationNode(s[1], s[3], s[5]), + ) + def_attr %= idx + colon + idx, lambda h, s: AttrDeclarationNode(s[1], s[3]) + + def_func %= ( + idx + opar + param_list + cpar + colon + idx + ocur + expr + ccur, + lambda h, s: FuncDeclarationNode(s[1], s[3], s[6], s[8]), + ) + + param_list %= param + comma + param_list, lambda h, s: [s[1]] + s[3] + param_list %= param, lambda h, s: [s[1]] + param_list %= G.Epsilon, lambda h, s: [] + + param %= idx + colon + idx, lambda h, s: (s[1], s[3]) + + expr %= idx + larrow + expr, lambda h, s: AssignNode(s[1], s[3]) + expr %= let + identifiers_list + inx + expr, lambda h, s: LetNode(s[2], s[4]) + expr %= ( + ifx + expr + then + expr + elsex + expr + fi, + lambda h, s: IfNode(s[2], s[4], s[6]), + ) + expr %= whilex + expr + loop + expr + pool, lambda h, s: WhileNode(s[2], s[4]) + expr %= case + expr + of + case_block + esac, lambda h, s: CaseNode(s[2], s[4]) + expr %= notx + expr, lambda h, s: NotNode(s[2]) + expr %= comp, lambda h, s: s[1] + + identifiers_list %= ( + identifier_init + comma + identifiers_list, + lambda h, s: [s[1]] + s[3], + ) + identifiers_list %= identifier_init, lambda h, s: [s[1]] + + identifier_init %= ( + idx + colon + idx + larrow + expr, + lambda h, s: VarDeclarationNode(s[1], s[3], s[5]), + ) + identifier_init %= idx + colon + idx, lambda h, s: VarDeclarationNode(s[1], s[3]) + + case_block %= case_item + case_block, lambda h, s: [s[1]] + s[2] + case_block %= case_item, lambda h, s: [s[1]] + case_item %= ( + idx + colon + idx + rarrow + expr + semi, + lambda h, s: CaseItemNode(s[1], s[3], s[5]), + ) + + comp %= comp + less + arith, lambda h, s: LessNode(s[1], s[3]) + comp %= comp + equal + arith, lambda h, s: EqualNode(s[1], s[3]) + comp %= comp + lesseq + arith, lambda h, s: LessEqualNode(s[1], s[3]) + comp %= arith, lambda h, s: s[1] + + arith %= arith + plus + term, lambda h, s: PlusNode(s[1], s[3]) + arith %= arith + minus + term, lambda h, s: MinusNode(s[1], s[3]) + arith %= term, lambda h, s: s[1] + + term %= term + star + factor, lambda h, s: StarNode(s[1], s[3]) + term %= term + div + factor, lambda h, s: DivNode(s[1], s[3]) + term %= factor, lambda h, s: s[1] + + factor %= isvoid + element, lambda h, s: IsvoidNode(s[2]) + factor %= neg + element, lambda h, s: NegNode(s[2]) + factor %= new + idx, lambda h, s: InstantiateNode(s[2]) + factor %= element, lambda h, s: s[1] + + element %= opar + expr + cpar, lambda h, s: s[2] + element %= ocur + block + ccur, lambda h, s: BlockNode(s[2]) + element %= (element + dot + func_call, lambda h, s: CallNode(*s[3], obj=s[1])) + element %= ( + element + at + idx + dot + func_call, + lambda h, s: CallNode(*s[5], obj=s[1], at_type=s[3]), + ) + element %= func_call, lambda h, s: CallNode(*s[1]) + element %= atom, lambda h, s: s[1] + + atom %= num, lambda h, s: ConstantNumNode(s[1]) + atom %= idx, lambda h, s: VariableNode(s[1]) + atom %= ( + true, + lambda h, s: BooleanNode(s[1]), + ) + atom %= false, lambda h, s: BooleanNode(s[1]) + atom %= string, lambda h, s: StringNode(s[1]) + + block %= expr + semi, lambda h, s: [s[1]] + block %= expr + semi + block, lambda h, s: [s[1]] + s[3] + + func_call %= idx + opar + arg_list + cpar, lambda h, s: (s[1], s[3]) + + arg_list %= expr + comma + arg_list, lambda h, s: [s[1]] + s[3] + arg_list %= expr, lambda h, s: [s[1]] + arg_list %= G.Epsilon, lambda h, s: [] + + if print_grammar: + print(G) + return (G, idx, string, num) diff --git a/src/cool_tokenizer.py b/src/cool_tokenizer.py new file mode 100644 index 000000000..90178fc09 --- /dev/null +++ b/src/cool_tokenizer.py @@ -0,0 +1,43 @@ +from src.cmp.utils import Token, tokenizer + + +def tokenize_cool_text(G, text, idx, num, print_tokens=False): + fixed_tokens = { + t.Name: Token(t.Name, t) for t in G.terminals if t not in {idx, num} + } + + @tokenizer(G, fixed_tokens) + def tokenize_text(token): + lex = token.lex + try: + float(lex) + return token.transform_to(num) + except ValueError: # verificar los string + return token.transform_to(idx) + + # (do something like if(lex[0] == " and lex[-1] ==")) + tokens = tokenize_text(text) + if print_tokens: + pprint_tokens(tokens) + return tokens + + +# pie co los lex, arreglar como toca +def pprint_tokens(tokens): + indent = 0 + pending = [] + for token in tokens: + pending.append(token) + if token.lex in {"{", "}", ";"}: + if token.lex == "}": + indent -= 1 + print(" " * indent + " ".join(str(t.token_type) for t in pending)) + pending.clear() + if token.lex == "{": + indent += 1 + print(" ".join([str(t.token_type) for t in pending])) + + +# if __name__ == "__main__": +# pprint_tokens(tokens) + diff --git a/src/cool_visitor.py b/src/cool_visitor.py new file mode 100644 index 000000000..8dab5b918 --- /dev/null +++ b/src/cool_visitor.py @@ -0,0 +1,339 @@ +import src.cmp.visitor as visitor +from src.ast_nodes import ( + ProgramNode, + ClassDeclarationNode, + FuncDeclarationNode, + AttrDeclarationNode, + IfNode, + WhileNode, + LetNode, + CaseNode, + AssignNode, + VarDeclarationNode, + CaseItemNode, + InstantiateNode, + BlockNode, + CallNode, + BinaryNode, + AtomicNode, + UnaryNode, +) + + +class FormatVisitor(object): + @visitor.on("node") + def visit(self, node, tabs=0): + pass + + @visitor.when(ProgramNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__ProgramNode [ ... ]" + statements = "\n".join( + self.visit(child, tabs + 1) for child in node.declarations + ) + return f"{ans}\n{statements}" + + @visitor.when(ClassDeclarationNode) + def visit(self, node, tabs=0): + parent = "" if node.parent is None else f"inherits {node.parent}" + ans = ( + "\t" * tabs + + f"\\__ClassDeclarationNode: class {node.id} {parent} {{ ... }}" + ) + features = "\n".join(self.visit(child, tabs + 1) for child in node.features) + return f"{ans}\n{features}" + + @visitor.when(AttrDeclarationNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__AttrDeclarationNode: {node.id} : {node.type} <- " + exp = "\t" * (tabs + 1) + "__NONE" + if not node.init_exp is None: + exp = "\n".join(self.visit(node.init_exp, tabs + 1)) + return f"{ans}\n{exp}" + + @visitor.when(VarDeclarationNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__VarDeclarationNode: {node.id} : {node.type} <- " + expr = "\t" * (tabs + 1) + "__NONE" + if not node.expr is None: + expr = self.visit(node.expr, tabs + 1) + return f"{ans}\n{expr}" + + @visitor.when(AssignNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__AssignNode: {node.id} <- " + expr = self.visit(node.expr, tabs + 1) + return f"{ans}\n{expr}" + + @visitor.when(FuncDeclarationNode) + def visit(self, node, tabs=0): + params = ", ".join(":".join(param) for param in node.params) + ans = ( + "\t" * tabs + + f"\\__FuncDeclarationNode: {node.id}({params}) : {node.type} {{ }}" + ) + body = self.visit(node.body, tabs + 1) + return f"{ans}\n{body}" + + @visitor.when(BinaryNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__ {node.__class__.__name__} " + left = self.visit(node.left, tabs + 1) + right = self.visit(node.right, tabs + 1) + return f"{ans}\n{left}\n{right}" + + @visitor.when(AtomicNode) + def visit(self, node, tabs=0): + return "\t" * tabs + f"\\__ {node.__class__.__name__}: {node.lex}" + + @visitor.when(UnaryNode) + def visit(self, node, tabs=0): + class_name = node.__class__.__name__.split("Node")[0] + ans = "\t" * tabs + f"\\__ {node.__class__.__name__}: {class_name} " + expr = self.visit(node.expr, tabs + 1) + return f"{ans}\n{expr}" + + @visitor.when(CallNode) + def visit(self, node, tabs=0): + args = "\n".join(self.visit(arg, tabs + 1) for arg in node.args) + if not node.obj is None: + obj = self.visit(node.obj, tabs + 1) + if not node.at_type is None: + ans = ( + "\t" * tabs + + f"\\__CallNode: @{node.at_type}.{node.id}(, ..., )" + ) + else: + ans = ( + "\t" * tabs + f"\\__CallNode: .{node.id}(, ..., )" + ) + return f"{ans}\n{obj}\n{args}" + else: + ans = "\t" * tabs + f"\\__CallNode: {node.id}(, ..., )" + return f"{ans}\n{args}" + + @visitor.when(InstantiateNode) + def visit(self, node, tabs=0): + return "\t" * tabs + f"\\__ InstantiateNode: new {node.lex}()" + + @visitor.when(BlockNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__BlockNode: {{; ... ;}}" + body = "\n".join(self.visit(child, tabs + 1) for child in node.expression_list) + return f"{ans}\n{body}" + + @visitor.when(IfNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__IfNode: if then else fi" + if_expr = self.visit(node.if_expr, tabs + 1) + then_expr = self.visit(node.then_expr, tabs + 1) + else_expr = self.visit(node.else_expr, tabs + 1) + return f"{ans}\n{if_expr}\n{then_expr}\n{else_expr}" + + @visitor.when(WhileNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__WhileNode: while loop pool" + condition = self.visit(node.condition, tabs + 1) + body = self.visit(node.body, tabs + 1) + return f"{ans}\n{condition}\n{body}" + + @visitor.when(LetNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__LetNode: let in " + ident_list = "\n".join( + self.visit(child, tabs + 1) for child in node.identifiers + ) + body = self.visit(node.body, tabs + 1) + return f"{ans}\n{ident_list}\n{body}" + + @visitor.when(CaseNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__CaseNode: case of esac" + case_block = "\n".join(self.visit(child, tabs + 1) for child in node.case_items) + expr = self.visit(node.expr, tabs + 1) + return f"{ans}\n{expr}\n{case_block}" + + @visitor.when(CaseItemNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__CaseItemNode: {node.id} : {node.type} => ;" + expr = self.visit(node.expr, tabs + 1) + return f"{ans}\n{expr}" + + +class FormatVisitorST(object): + tree = [] + + @visitor.on("node") + def visit(self, node, tabs=0): + pass + + @visitor.when(ProgramNode) + def visit(self, node, tabs=0): + self.tree = [] + ans = "\\__\\__" * tabs + f"\\__ProgramNode [< class > ... < class >]" + self.tree.append(ans) + for child in node.declarations: + self.visit(child, tabs + 1) + return self.tree + + @visitor.when(ClassDeclarationNode) + def visit(self, node, tabs=0): + parent = "" if node.parent is None else f"inherits {node.parent}" + ans = ( + "\\__\\__" * tabs + + f"\\__ClassDeclarationNode: class {node.id} {parent} {{ ... }}" + ) + self.tree.append(ans) + for child in node.features: + self.visit(child, tabs + 1) + return + + @visitor.when(AttrDeclarationNode) + def visit(self, node, tabs=0): + ans = ( + "\\__\\__" * tabs + + f"\\__AttrDeclarationNode: {node.id} : {node.type} <- " + ) + exp = "\\__\\__" * (tabs + 1) + "\\__NONE" + self.tree.append(ans) + if not node.init_exp is None: + self.visit(node.init_exp, tabs + 1) + else: + self.tree.append(exp) + + return + + @visitor.when(VarDeclarationNode) + def visit(self, node, tabs=0): + ans = ( + "\\__\\__" * tabs + + f"\\__VarDeclarationNode: {node.id} : {node.type} <- " + ) + expr = "\\__\\__" * (tabs + 1) + "\\__NONE" + self.tree.append(ans) + + if not node.expr is None: + expr = self.visit(node.expr, tabs + 1) + else: # esto estaba antes sin el else + self.tree.append(expr) + + return + + @visitor.when(AssignNode) + def visit(self, node, tabs=0): + ans = "\\__\\__" * tabs + f"\\__AssignNode: {node.id} <- " + self.tree.append(ans) + self.visit(node.expr, tabs + 1) + return + + @visitor.when(FuncDeclarationNode) + def visit(self, node, tabs=0): + params = ", ".join(":".join(param) for param in node.params) + ans = ( + "\\__\\__" * tabs + + f"\\__FuncDeclarationNode: {node.id}({params}) : {node.type} {{ }}" + ) + self.tree.append(ans) + self.visit(node.body, tabs + 1) + return + + @visitor.when(BinaryNode) + def visit(self, node, tabs=0): + ans = "\\__\\__" * tabs + f"\\__ {node.__class__.__name__} " + self.tree.append(ans) + self.visit(node.left, tabs + 1) + self.visit(node.right, tabs + 1) + return + + @visitor.when(AtomicNode) + def visit(self, node, tabs=0): + ans = "\\__\\__" * tabs + f"\\__ {node.__class__.__name__}: {node.lex}" + self.tree.append(ans) + return + + @visitor.when(UnaryNode) + def visit(self, node, tabs=0): + class_name = node.__class__.__name__.split("Node")[0] + ans = "\\__\\__" * tabs + f"\\__ {node.__class__.__name__}: {class_name} " + self.tree.append(ans) + self.visit(node.expr, tabs + 1) + return + + @visitor.when(CallNode) + def visit(self, node, tabs=0): + if not node.obj is None: + if not node.at_type is None: + ans = ( + "\\__\\__" * tabs + + f"\\__CallNode: @{node.at_type}.{node.id}(, ..., )" + ) + else: + ans = ( + "\\__\\__" * tabs + + f"\\__CallNode: .{node.id}(, ..., )" + ) + self.tree.append(ans) + self.visit(node.obj, tabs + 1) + else: + ans = "\\__\\__" * tabs + f"\\__CallNode: {node.id}(, ..., )" + self.tree.append(ans) + for arg in node.args: + self.visit(arg, tabs + 1) + return + + @visitor.when(InstantiateNode) + def visit(self, node, tabs=0): + ans = "\\__\\__" * tabs + f"\\__ InstantiateNode: new {node.lex}()" + self.tree.append(ans) + return + + @visitor.when(BlockNode) + def visit(self, node, tabs=0): + ans = "\\__\\__" * tabs + f"\\__BlockNode: {{; ... ;}}" + self.tree.append(ans) + for child in node.expression_list: + self.visit(child, tabs + 1) + return + + @visitor.when(IfNode) + def visit(self, node, tabs=0): + ans = "\\__\\__" * tabs + f"\\__IfNode: if then else fi" + self.tree.append(ans) + self.visit(node.if_expr, tabs + 1) + self.visit(node.then_expr, tabs + 1) + self.visit(node.else_expr, tabs + 1) + return + + @visitor.when(WhileNode) + def visit(self, node, tabs=0): + ans = "\\__\\__" * tabs + f"\\__WhileNode: while loop pool" + self.tree.append(ans) + self.visit(node.condition, tabs + 1) + self.visit(node.body, tabs + 1) + return + + @visitor.when(LetNode) + def visit(self, node, tabs=0): + ans = "\\__\\__" * tabs + f"\\__LetNode: let in " + self.tree.append(ans) + for child in node.identifiers: + self.visit(child, tabs + 1) + self.visit(node.body, tabs + 1) + return + + @visitor.when(CaseNode) + def visit(self, node, tabs=0): + ans = "\\__\\__" * tabs + f"\\__CaseNode: case of esac" + self.tree.append(ans) + self.visit(node.expr, tabs + 1) + for child in node.case_items: + self.visit(child, tabs + 1) + return + + @visitor.when(CaseItemNode) + def visit(self, node, tabs=0): + ans = "\\__\\__" * tabs + f"\\__CaseItemNode: {node.id} : {node.type} => ;" + self.tree.append(ans) + self.visit(node.expr, tabs + 1) + return + diff --git a/src/coolc.sh b/src/coolc.sh index 3088de4f9..57da22e35 100755 --- a/src/coolc.sh +++ b/src/coolc.sh @@ -5,7 +5,7 @@ OUTPUT_FILE=${INPUT_FILE:0: -2}mips # Si su compilador no lo hace ya, aquí puede imprimir la información de contacto echo "LINEA_CON_NOMBRE_Y_VERSION_DEL_COMPILADOR" # TODO: Recuerde cambiar estas -echo "Copyright (c) 2019: Nombre1, Nombre2, Nombre3" # TODO: líneas a los valores correctos +echo "Copyright (c) 2022: Amalia_Ibarra, Sandra_Martos, Gabriela_Martinez" # TODO: líneas a los valores correctos # Llamar al compilador echo "Compiling $INPUT_FILE into $OUTPUT_FILE" diff --git a/src/errors.py b/src/errors.py new file mode 100644 index 000000000..14c9922a5 --- /dev/null +++ b/src/errors.py @@ -0,0 +1,70 @@ +class Error(Exception): + "Base class for exceptions" + pass + + +class tokenizer_error(Error): + "raised when tokenizer got unespected sequences of characters" + + def __init__(self, text, line): + Error.__init__( + self, f"Got {text} while analizing line {line}", + ) + + +class parsing_table_error(Error): + "raised when T[X,t] possess more than one production" + + def __init__(self, production1, production2, invalid_sentence): + Error.__init__( + self, + f"conflict betweeen {production1} and {production2}, invalid sentence: {invalid_sentence}", + ) + + +class shift_reduce_error(Error): + "raised when goto or action table in shift reduce parsers possess more than one production" + + def __init__(self, action1, action2, grammar, key=None): + if action1[0] == action2[0] == "REDUCE": + conflict = "Reduce-Reduce" + else: + conflict = "Shift-Reduce" + + Error.__init__( + self, + f"When analizing {key}, {conflict} conflict!!! betweeen {action1} and {action2}. Grammar given is not {grammar}", + ) + + +class invalid_sentence_error(Error): + "raised when w is not in G" + + def __init__( + self, + w, + pos, + actual_token, + expected_token=None, + message="", + output=None, + operations=None, + ): + if expected_token != None: + Error.__init__( + self, + f"Invalid sentence {w}. Expected {expected_token} at position {pos} but received {actual_token} instead. {message}", + ) + else: + Error.__init__( + self, + f"Unexpected token {actual_token} at position {pos}. Invalid sentence {w}. {message}. Secuencia de derivaciones: {output}. Operaciones: {operations}", + ) + + +class non_regular_production_error(Error): + def __init__(self, production): + Error.__init__( + self, + f"production {production} most be of the form: A -> a, A -> e or A -> aX", + ) diff --git a/src/lexical_analizer.py b/src/lexical_analizer.py new file mode 100644 index 000000000..a0e3a9a1c --- /dev/null +++ b/src/lexical_analizer.py @@ -0,0 +1,57 @@ +import ply.lex as lex +import src.tokens_rules as tokens_rules +from src.cmp.utils import Token + + +def pprint_tokens(tokens): + indent = 0 + pending = [] + for token in tokens: + pending.append(token) + if token.lex in {"{", "}", ";"}: + if token.lex == "}": + indent -= 1 + print(" " * indent + " ".join(str(t.token_type) for t in pending)) + pending.clear() + if token.lex == "{": + indent += 1 + print(" ".join([str(t.token_type) for t in pending])) + + +def tokenize_cool_text(grammar, idx, string, num, data, printing=False): + lexer = lex.lex(module=tokens_rules) + + # Give the lexer some input + lexer.input(data) + + fixed_tokens = { + t.Name: Token(t.Name, t) + for t in grammar.terminals + if t not in {idx, string, num} + } + + tokens = [] + # Tokenize + while True: + tok = lexer.token() + if not tok: + tokens.append(Token("$", grammar.EOF)) + break # No more input + else: + try: + tokens.append(fixed_tokens[tok.type]) + except: + try: # for <=, ->, <- + tokens.append(fixed_tokens[tok.value]) + except: + if tok.type == "string": + tokens.append(Token(tok.value, string)) + elif tok.type == "id": + tokens.append(Token(tok.value, idx)) + else: + tokens.append(Token(tok.value, num)) + + if printing: + pprint_tokens(tokens) + return tokens + diff --git a/src/parser_automatons.py b/src/parser_automatons.py new file mode 100644 index 000000000..6fce5323d --- /dev/null +++ b/src/parser_automatons.py @@ -0,0 +1,225 @@ +from src.cmp.pycompiler import Item +from src.cmp.automata import State, lr0_formatter, multiline_formatter +from src.cmp.utils import ContainerSet +from src.methods import compute_firsts, compute_local_first, compute_follows + +# LR0 automaton -> for SLR and LALR parsers +def build_LR0_automaton(G): + assert len(G.startSymbol.productions) == 1, "Grammar must be augmented" + + start_production = G.startSymbol.productions[0] + start_item = Item(start_production, 0) + + automaton = State(start_item, True) + + pending = [start_item] + visited = {start_item: automaton} + + while pending: + current_item = pending.pop() + if current_item.IsReduceItem: + continue + + # (Decide which transitions to add) + # agregar las epsilon transiciones + # a estados donde el item posee producciones a partir del simbolo actual en la posicion 0 + # y agregar la transicion a partir del simbolo siguiente + + next_item = current_item.NextItem() + try: + next_state = visited[next_item] + except KeyError: + next_state = State(next_item, True) + visited[next_item] = next_state + pending.append(next_item) + + if current_item.NextSymbol.IsNonTerminal: + epsilon_productions = current_item.NextSymbol.productions + else: + epsilon_productions = None + + current_state = visited[current_item] + # (Adding the decided transitions) + current_state.add_transition(current_item.NextSymbol.Name, next_state) + + if epsilon_productions: + for eproduction in epsilon_productions: + epItem = Item(eproduction, 0) + try: + epState = visited[epItem] + except KeyError: + epState = State(epItem, True) + visited[epItem] = epState + pending.append(epItem) + current_state.add_epsilon_transition(epState) + + return automaton + + +# LR1 automaton +def expand(item, firsts): + next_symbol = item.NextSymbol + if next_symbol is None or not next_symbol.IsNonTerminal: + return [] + + lookaheads = ContainerSet() + # (Compute lookahead for child items) + previews = item.Preview() + for preview in previews: + lookaheads.update(compute_local_first(firsts, preview)) + + assert not lookaheads.contains_epsilon + # (Build and return child items) + items = [] + for production in next_symbol.productions: + items.append(Item(production, 0, lookaheads)) + + return items + + +def compress(items): + centers = {} + + for item in items: + center = item.Center() + try: + lookaheads = centers[center] + except KeyError: + centers[center] = lookaheads = set() + lookaheads.update(item.lookaheads) + + return { + Item(x.production, x.pos, set(lookahead)) for x, lookahead in centers.items() + } + + +def closure_lr1(items, firsts): + closure = ContainerSet(*items) + + changed = True + while changed: + changed = False + + new_items = ContainerSet() + # Your code here!!! + for item in closure: + new_items.extend(expand(item, firsts)) + + changed = closure.update(new_items) + + return compress(closure) + + +def goto_lr1(items, symbol, firsts=None, just_kernel=False): + assert ( + just_kernel or firsts is not None + ), "`firsts` must be provided if `just_kernel=False`" + items = frozenset(item.NextItem() for item in items if item.NextSymbol == symbol) + return items if just_kernel else closure_lr1(items, firsts) + + +def build_LR1_automaton(G): + assert len(G.startSymbol.productions) == 1, "Grammar must be augmented" + + firsts = compute_firsts(G) + firsts[G.EOF] = ContainerSet(G.EOF) + + start_production = G.startSymbol.productions[0] + start_item = Item(start_production, 0, lookaheads=(G.EOF,)) + start = frozenset([start_item]) # como cabecera solo queda el kernel + + closure = closure_lr1(start, firsts) + automaton = State( + frozenset(closure), True + ) # en visited si se guarda el estado completo + + pending = [start] + visited = {start: automaton} + + while pending: + current = pending.pop() + current_state = visited[current] + + closure = closure_lr1(current, firsts) + for symbol in G.terminals + G.nonTerminals: + # (Get/Build `next_state`) + # closure = closure_lr1(current,firsts) + goto = goto_lr1(closure, symbol, firsts, True) + + if not goto: + continue + + try: + next_state = visited[goto] + except KeyError: + next_state = visited[goto] = State( + frozenset(closure_lr1(goto, firsts)), True + ) + pending.append(goto) + + current_state.add_transition(symbol.Name, next_state) + + automaton.set_formatter(multiline_formatter) + return automaton + + +def build_LALR_automaton(G): + assert len(G.startSymbol.productions) == 1, "Grammar must be augmented" + + lr1_automaton = build_LR1_automaton(G) + + same_kernel = {} + for node in lr1_automaton: + just_center = frozenset([item.Center() for item in node.state]) + try: + same_kernel[just_center].append(node) + except KeyError: + same_kernel[just_center] = [node] + + start = frozenset( + [item.Center() for item in lr1_automaton.state] + ) # como cabecera solo quedan los items sin lookahead + automaton = State( + lr1_automaton.state, True + ) # en visited se guarda el estado que corresponde a la fusion de estaods ocn el mismo nucleo + + pending = [start] + visited = {start: automaton} + + while pending: + current = pending.pop() + current_state = visited[current] # se van a actualizar + # todos los estados con los que el estado actual tiene alguna transicion + lr1_state = same_kernel[current][0] + + # chequear que cada estado del cjto analizado tenga esa transicion + for symbol in G.terminals + G.nonTerminals: + if lr1_state.has_transition(symbol.Name): + state = lr1_state.transitions[symbol.Name][0] + center_items = frozenset([item.Center() for item in state.state]) + try: + next_state = visited[center_items] + except KeyError: + kernel_set = same_kernel[center_items] + items_with_lookahead = {} + for node in kernel_set: + for item in node.state: + try: + current_item = items_with_lookahead[item.Center()] + except KeyError: + current_item = items_with_lookahead[ + item.Center() + ] = set() + current_item.update(item.lookaheads) + completed_items = [ + Item(item.production, item.pos, lookaheads) + for item, lookaheads in items_with_lookahead.items() + ] + next_state = State(frozenset(completed_items), True) + visited[center_items] = next_state + pending.append(center_items) + + current_state.add_transition(symbol.Name, next_state) + + automaton.set_formatter(multiline_formatter) + return automaton diff --git a/src/shift_reduce_parsers.py b/src/shift_reduce_parsers.py new file mode 100644 index 000000000..3501302b1 --- /dev/null +++ b/src/shift_reduce_parsers.py @@ -0,0 +1,274 @@ +from src.parser_automatons import ( + build_LR0_automaton, + build_LR1_automaton, + build_LALR_automaton, +) +from src.methods import compute_firsts, compute_local_first, compute_follows +from src.cmp.automata import State +from src.errors import shift_reduce_error, invalid_sentence_error + + +class ShiftReduceParser: + SHIFT = "SHIFT" + REDUCE = "REDUCE" + OK = "OK" + + def __init__(self, G, verbose=False): + self.G = G + self.verbose = verbose + self.action = {} + self.goto = {} + self.automaton = self._build_parsing_table() + + def _build_parsing_table(self): + raise NotImplementedError() + + def __call__(self, w): + stack = [0] + cursor = 0 + output = [] + operations = [] + + while True: + state = stack[-1] + lookahead = w[cursor] + if self.verbose: + print(stack, "<---||--->", w[cursor:]) + + # Detect error + try: + action, tag = self.action[state, lookahead] + + except KeyError: + raise invalid_sentence_error( + w, + cursor, + lookahead, + None, + "No transition available. Sentence given does not belong to the grammar", + output, + operations, + ) + # Exception( + # "No transition available" + # ) # string does not belong to this grammar + + # Shift case + if action == self.SHIFT: + operations.append(action) + stack.append(tag) + cursor += 1 + + # Reduce case + elif action == self.REDUCE: + operations.append(action) + for _ in range(len(tag.Right)): + stack.pop() + output.append(tag) + stack.append(self.goto[stack[-1], tag.Left]) + + # OK case + elif action == self.OK: + return output, operations + # Invalid case + else: + raise invalid_sentence_error( + w, + cursor, + lookahead, + None, + "Invalid case. Sentence given does not belong to the grammar", + ) + # raise Exception("Invalid case") + # break + + if cursor >= len(w): # or not stack + raise invalid_sentence_error( + w, + cursor - 1, + lookahead, + None, + "Exceed word length while looking for a viable derivation. Sentence given does not belong to the grammar", + ) + # raise Exception("Invalid sentence") + + +class SLR1Parser(ShiftReduceParser): + def _build_parsing_table(self): + G = self.G.AugmentedGrammar(True) + firsts = compute_firsts(G) + follows = compute_follows(G, firsts) + + automaton = build_LR0_automaton(G).to_deterministic() + for i, node in enumerate(automaton): + if self.verbose: + print(i, "\t", "\n\t ".join(str(x) for x in node.state), "\n") + node.idx = i + + for node in automaton: + idx = node.idx + for state in node.state: + item = state.state + # - Filling `self.Action` and `self.Goto` according to `item`) + # - Using `self._register(...)`) + if item.IsReduceItem: + if item.production.Left == G.startSymbol: + self._register(self.action, (idx, G.EOF), (self.OK, None)) + else: + for symbol in follows[item.production.Left]: + self._register( + self.action, + (idx, symbol), + (self.REDUCE, item.production), + ) + else: + if item.NextSymbol.IsTerminal: + self._register( + self.action, + (idx, item.NextSymbol), + (self.SHIFT, node[item.NextSymbol.Name][0].idx), + ) + else: + self._register( + self.goto, + (idx, item.NextSymbol), + node[item.NextSymbol.Name][0].idx, + ) + return automaton + + @staticmethod + def _register(table, key, value): + # assert ( + # key not in table or table[key] == value + # ), "Shift-Reduce or Reduce-Reduce conflict!!!" + if key in table and table[key] != value: + raise shift_reduce_error(table[key], value, "SLR") + table[key] = value + + +class LR1Parser(ShiftReduceParser): + def _build_parsing_table(self): + G = self.G.AugmentedGrammar(True) + + automaton = build_LR1_automaton(G) + for i, node in enumerate(automaton): + if self.verbose: + print(i, "\t", "\n\t ".join(str(x) for x in node.state), "\n") + node.idx = i + + # print("automatons states") + for node in automaton: + idx = node.idx + for item in node.state: + # print("item", item) + # - Fill `self.Action` and `self.Goto` according to `item`) + # - Feel free to use `self._register(...)`) + if item.IsReduceItem: + if item.production.Left == G.startSymbol: + self._register(self.action, (idx, G.EOF), (self.OK, None)) + else: + for symbol in item.lookaheads: + self._register( + self.action, + (idx, symbol), + (self.REDUCE, item.production), + ) + else: + if item.NextSymbol.IsTerminal: + self._register( + self.action, + (idx, item.NextSymbol), + (self.SHIFT, node[item.NextSymbol.Name][0].idx), + ) + else: + self._register( + self.goto, + (idx, item.NextSymbol), + node[item.NextSymbol.Name][0].idx, + ) + return automaton + + @staticmethod + def _register(table, key, value): + if key in table and table[key] != value: + raise shift_reduce_error(table[key], value, "LR", key) + table[key] = value + + +class LALR_Parser(ShiftReduceParser): + def _build_parsing_table(self): + G = self.G.AugmentedGrammar(True) + + automaton = build_LALR_automaton(G) + + for i, node in enumerate(automaton): + if self.verbose: + print(i, "\t", "\n\t ".join(str(x) for x in node.state), "\n") + node.idx = i + + for node in automaton: + idx = node.idx + for item in node.state: + # - Fill `self.Action` and `self.Goto` according to `item`) + # - Feel free to use `self._register(...)`) + if item.IsReduceItem: + if item.production.Left == G.startSymbol: + self._register(self.action, (idx, G.EOF), (self.OK, None)) + else: + for symbol in item.lookaheads: + self._register( + self.action, + (idx, symbol), + (self.REDUCE, item.production), + ) + else: + if item.NextSymbol.IsTerminal: + self._register( + self.action, + (idx, item.NextSymbol), + (self.SHIFT, node[item.NextSymbol.Name][0].idx), + ) + else: + self._register( + self.goto, + (idx, item.NextSymbol), + node[item.NextSymbol.Name][0].idx, + ) + + return automaton + + @staticmethod + def _register(table, key, value): + if key in table and table[key] != value: + raise shift_reduce_error(table[key], value, "LALR") + table[key] = value + + +# ----------------------derivation tree-------------------------# +def DerivationTree(derivation, G): + lent = len(derivation) + + nonTerminalstack = [] + root = State(G.startSymbol.Name) + nonTerminalstack.append(root) + + while lent > 0: + lent -= 1 + next_production = derivation[lent] + print("next_production", next_production) + currentNode = nonTerminalstack.pop() + # assert currentNode.state == next_production.Left.Name, "Wrong derivation" + + if next_production.IsEpsilon: + currentNode.add_transition(" ", State("epsilon", True)) + + for symbol in next_production.Right: + if symbol.IsTerminal: + currentNode.add_transition(" ", State(symbol.Name, True)) + else: + nonTerminalstack.append(State(symbol.Name)) + currentNode.add_transition( + " ", nonTerminalstack[len(nonTerminalstack) - 1] + ) + + return root diff --git a/src/tokens_rules.py b/src/tokens_rules.py new file mode 100644 index 000000000..b00583675 --- /dev/null +++ b/src/tokens_rules.py @@ -0,0 +1,212 @@ +# https://www.dabeaz.com/ply/ply.html +# file for PLY rules + +from src.errors import tokenizer_error + + +# def find_column(input, lexpos): +# # line_start = input.rfind("\n", 0, lexpos) + 1 +# # return (lexpos - line_start) + 1 +# line_numbers = input.rfind("\n", 0, lexpos) + 1 +# return (lexpos // line_numbers) + (lexpos % line_numbers) + + +# Declare the states +states = (("comments", "exclusive"),) + + +# All lexers must provide a list tokens that defines all of the possible token names +# that can be produced by the lexer. +first_tokens = [ + "larrow", + "rarrow", + "lessequal", + "id", + "int", + "string", +] + +reserved = { + "class": "class", + "inherits": "inherits", + "not": "not", + "isvoid": "isvoid", + "let": "let", + "in": "in", + "if": "if", + "then": "then", + "else": "else", + "fi": "fi", + "loop": "loop", + "pool": "pool", + "case": "case", + "of": "of", + "esac": "esac", + "while": "while", + "new": "new", + "true": "true", + "false": "false", +} + +literals = [ + ";", + ":", + ",", + ".", + "(", + ")", + "{", + "}", + "@", + "+", + "-", + "*", + "/", + "<", + "=", + "~", +] + +tokens = first_tokens + list(reserved.values()) + +# Match the first (*. Enter comments state. +def t_comments(t): + r"\(\*" + t.lexer.code_start = t.lexer.lexpos # Record the starting position + t.lexer.level = 1 # Initial level + t.lexer.begin("comments") # Enter 'comments' state + + +# Rules for the comments state +# Comments starting symbol +def t_comments_opsymb(t): + r"\(\*" + t.lexer.level += 1 + + +# Comments closing symbol +def t_comments_clsymb(t): + r"\*\)" + t.lexer.level -= 1 + + if t.lexer.level == 0: + t.value = t.lexer.lexdata[t.lexer.code_start : t.lexer.lexpos + 1] + t.lexer.lineno += t.value.count("\n") + t.lexer.begin("INITIAL") + + +# For bad characters. In this case we just skip over everything but (* or *) +def t_comments_error(t): + t.lexer.skip(1) + + +# EOF handling rule +def t_comments_eof(t): + if t.lexer.level > 0: # guardar este error y actuar acorde + print(f"code_start{t.lexer.code_start}") + raise tokenizer_error("Comments can not cross file boundaries", t.lexer.lineno) + return None + + +# Rules for initial state (default state) +def t_id(t): + r"[a-zA-Z_][a-zA-Z_0-9]*" + t.type = reserved.get( + t.value, "id" + ) # Check for reserved words. If it isn't a reserved word is categorized as identifier + return t + + +# matching int numbers +def t_int(t): + r"\d+" + t.value = int(t.value) + # r'\d+(\.\d*)?' float numbers + # t.value = float(t.value) + return t + + +def t_comment1(t): + r"\--.*" + pass + # No return value. Token discarded + + +def t_string(t): + r"\"" + string_list = [] + text = t.lexer.lexdata + initial = t.lexer.lexpos + index = t.lexer.lexpos + final = len(text) + + while index < final and text[index] != '"': + if text[index] == "\\": + if text[index + 1] in ["t", "b", "f", "n"]: + # string_to_append+=f'\\{text[index + 1]}' + string_list.append(text[index : index + 2]) # \t,\b,\f + elif text[index + 1] == "\n": # non scape \n whith \ before + # string_to_append+='\n' + string_list.append("\n") + elif text[index + 1] == "0": # null character \0 is not allowed + # print("Illegal character \\0 inside string") # do something about it + raise tokenizer_error( + "Illegal character \\0 inside string", + t.lexer.lineno + text[initial : index + 1].count("\n"), + ) + else: + string_list.append( + text[index : index + 2] + ) # ]character c: take the character in \c + # string_to_append += text[index + 1] + index += 2 + + elif text[index] == "\n": # \n whithout and extra \ is not allowed + # print("Illegal character \\n inside string") # do something about it + raise tokenizer_error( + "Illegal character \\n inside string", + t.lexer.lineno + text[initial : index + 1].count("\n"), + ) + index += 1 + else: + string_list.append(text[index]) + # string_to_append += text[index + 1] + index += 1 + + if index == final: + # print("String may not cross file boundaries") # do something about it + raise tokenizer_error( + "String may not cross file boundaries", + t.lexer.lineno + text[initial : index + 1].count("\n"), + ) + else: + index += 1 + + t.value = "".join(string_list) + t.type = "string" + t.lexer.lexpos += index - initial + t.lexer.lineno += text[initial : index + 1].count("\n") + # print(t.value) + # print(string_to_append) + return t + + +# Define a rule so we can track line numbers +def t_newline(t): + r"\n+" + t.lexer.lineno += len(t.value) + + +t_larrow = r"<-" +t_rarrow = r"=>" +t_lessequal = r"<=" + + +# A string containing ignored characters (spaces and tabs) +t_ignore = " \t" + + +# Error handling rule +def t_error(t): + raise tokenizer_error(f"Illegal character {t.value[0]}", t.lexer.lineno) + t.lexer.skip(1) From 827c82e8cf3245bf58ed66469ef6d422e860925f Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Thu, 10 Feb 2022 19:19:16 -0500 Subject: [PATCH 029/162] feat: add main and cmp --- doc/.team.yml.kate-swp | Bin 2387 -> 0 bytes doc/team.yml | 18 +- src/cmp/__init__.py | 0 src/cmp/ast.py | 69 +++ src/cmp/automata.py | 224 ++++++++ src/cmp/cil.py | 267 +++++++++ src/cmp/evaluation.py | 36 ++ src/cmp/nbpackage.py | 87 +++ src/cmp/pycompiler.py | 512 ++++++++++++++++++ src/cmp/semantic.py | 302 +++++++++++ .../.ipynb_checkpoints/__init__-checkpoint.py | 0 .../.ipynb_checkpoints/automata-checkpoint.py | 3 + .../evaluation-checkpoint.py | 3 + .../.ipynb_checkpoints/parsing-checkpoint.py | 10 + src/cmp/tools/__init__.py | 0 src/cmp/tools/automata.py | 3 + src/cmp/tools/evaluation.py | 3 + src/cmp/tools/parsing.py | 16 + src/cmp/tools/regex.py | 3 + src/cmp/utils.py | 343 ++++++++++++ src/cmp/visitor.py | 80 +++ src/main.py | 99 ++++ src/type_builder.py | 201 +++++++ src/type_checker.py | 455 ++++++++++++++++ src/type_collector.py | 54 ++ 25 files changed, 2779 insertions(+), 9 deletions(-) delete mode 100644 doc/.team.yml.kate-swp create mode 100644 src/cmp/__init__.py create mode 100644 src/cmp/ast.py create mode 100644 src/cmp/automata.py create mode 100644 src/cmp/cil.py create mode 100644 src/cmp/evaluation.py create mode 100644 src/cmp/nbpackage.py create mode 100644 src/cmp/pycompiler.py create mode 100644 src/cmp/semantic.py create mode 100644 src/cmp/tools/.ipynb_checkpoints/__init__-checkpoint.py create mode 100644 src/cmp/tools/.ipynb_checkpoints/automata-checkpoint.py create mode 100644 src/cmp/tools/.ipynb_checkpoints/evaluation-checkpoint.py create mode 100644 src/cmp/tools/.ipynb_checkpoints/parsing-checkpoint.py create mode 100644 src/cmp/tools/__init__.py create mode 100644 src/cmp/tools/automata.py create mode 100644 src/cmp/tools/evaluation.py create mode 100644 src/cmp/tools/parsing.py create mode 100644 src/cmp/tools/regex.py create mode 100644 src/cmp/utils.py create mode 100644 src/cmp/visitor.py create mode 100644 src/main.py create mode 100644 src/type_builder.py create mode 100644 src/type_checker.py create mode 100644 src/type_collector.py diff --git a/doc/.team.yml.kate-swp b/doc/.team.yml.kate-swp deleted file mode 100644 index cf5a7aabaf35042c795735fb3786f1b602d0d391..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2387 zcmZ9N%T82L5Jm6tEebSEg9@mPi4$MZjuVE)w4|d>xL?p{M@jGzMIp}o0;kUW495;k z{1yEQ&)T=jsyMib%PP(}wRcr@(=`3Z(}UTtJ)FKBKHA%#4M%tGHcd15G2Lx%wl}uF z%uRmY`t|M4*U#U7w>vdb>Ni)v-XuYJFm9dC@&B)a&%@K;d3Zl~0p1HT%!@I%D_UHbb0sJoFEC2DT<@D z_(SkjcosZ_KaC~*vHEYySqY@tK_Fr*2clI!uvc*@5TSd4_^=p=O$&jzINv>sXJk`h znQErPGSy6nWvZDD^Awi_ma8dWu9|Gb<*K<1%hi;hT_rA8%?9{F{b)j5K3>06ESQP~ zQ?ZWaepkF_mwUk~cGMkyqW-zYqYFEh?O+Xvy`8wUwAx^4X>W&hylDYTOKTBWTAH@7 zYe}sz+HJ)3lJaSAmXdTyc@WjWtC60SCS6L`bmk3~(&@Dtpw|)C0HxP!fR5ricsSUa?8F4w2uGi*E)yf((ntWMf*PX45T6N#hH;(0Du*9>WBQEi5=-@nbr;KfVfoY<_ zG|`Se(VksKofOV>`SCVKA9y(5eX?>|${ {node.__class__.__name__}" + child = self.visit(node.node, tabs + 1) + return f"{ans}\n{child}" + + @visitor.when(BinaryNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__ {node.__class__.__name__} " + left = self.visit(node.left, tabs + 1) + right = self.visit(node.right, tabs + 1) + return f"{ans}\n{left}\n{right}" + + @visitor.when(AtomicNode) + def visit(self, node, tabs=0): + return "\t" * tabs + f"\\__ {node.__class__.__name__}: {node.lex}" + + printer = PrintVisitor() + return lambda ast: printer.visit(ast) + diff --git a/src/cmp/automata.py b/src/cmp/automata.py new file mode 100644 index 000000000..4d2619364 --- /dev/null +++ b/src/cmp/automata.py @@ -0,0 +1,224 @@ +try: + import pydot +except: + pass + + +class State: + def __init__(self, state, final=False, formatter=lambda x: str(x), shape="circle"): + self.state = state + self.final = final + self.transitions = {} + self.epsilon_transitions = set() + self.tag = None + self.formatter = formatter + self.shape = shape + + # The method name is set this way from compatibility issues. + def set_formatter(self, value, attr="formatter", visited=None): + if visited is None: + visited = set() + elif self in visited: + return + + visited.add(self) + self.__setattr__(attr, value) + for destinations in self.transitions.values(): + for node in destinations: + node.set_formatter(value, attr, visited) + for node in self.epsilon_transitions: + node.set_formatter(value, attr, visited) + return self + + def has_transition(self, symbol): + return symbol in self.transitions + + def add_transition(self, symbol, state): + try: + self.transitions[symbol].append(state) + except: + self.transitions[symbol] = [state] + return self + + def add_epsilon_transition(self, state): + self.epsilon_transitions.add(state) + return self + + def recognize(self, string): + states = self.epsilon_closure + for symbol in string: + states = self.move_by_state(symbol, *states) + states = self.epsilon_closure_by_state(*states) + return any(s.final for s in states) + + def to_deterministic(self, formatter=lambda x: str(x)): + closure = self.epsilon_closure + start = State(tuple(closure), any(s.final for s in closure), formatter) + + closures = [closure] + states = [start] + pending = [start] + + while pending: + state = pending.pop() + symbols = {symbol for s in state.state for symbol in s.transitions} + + for symbol in symbols: + move = self.move_by_state(symbol, *state.state) + closure = self.epsilon_closure_by_state(*move) + + if closure not in closures: + new_state = State( + tuple(closure), any(s.final for s in closure), formatter + ) + closures.append(closure) + states.append(new_state) + pending.append(new_state) + else: + index = closures.index(closure) + new_state = states[index] + + state.add_transition(symbol, new_state) + + return start + + @staticmethod + def from_nfa(nfa, get_states=False): + states = [] + for n in range(nfa.states): + state = State(n, n in nfa.finals) + states.append(state) + + for (origin, symbol), destinations in nfa.map.items(): + origin = states[origin] + origin[symbol] = [states[d] for d in destinations] + + if get_states: + return states[nfa.start], states + return states[nfa.start] + + @staticmethod + def move_by_state(symbol, *states): + return { + s for state in states if state.has_transition(symbol) for s in state[symbol] + } + + @staticmethod + def epsilon_closure_by_state(*states): + closure = {state for state in states} + + l = 0 + while l != len(closure): + l = len(closure) + tmp = [s for s in closure] + for s in tmp: + for epsilon_state in s.epsilon_transitions: + closure.add(epsilon_state) + return closure + + @property + def epsilon_closure(self): + return self.epsilon_closure_by_state(self) + + @property + def name(self): + return self.formatter(self.state) + + def get(self, symbol): + target = self.transitions[symbol] + assert len(target) == 1 + return target[0] + + def __getitem__(self, symbol): + if symbol == "": + return self.epsilon_transitions + try: + return self.transitions[symbol] + except KeyError: + return None + + def __setitem__(self, symbol, value): + if symbol == "": + self.epsilon_transitions = value + else: + self.transitions[symbol] = value + + def __repr__(self): + return str(self) + + def __str__(self): + return str(self.state) + + def __hash__(self): + return hash(self.state) + + def __iter__(self): + yield from self._visit() + + def _visit(self, visited=None): + if visited is None: + visited = set() + elif self in visited: + return + + visited.add(self) + yield self + + for destinations in self.transitions.values(): + for node in destinations: + yield from node._visit(visited) + for node in self.epsilon_transitions: + yield from node._visit(visited) + + def graph(self): + G = pydot.Dot(rankdir="LR", margin=0.1) + G.add_node(pydot.Node("start", shape="plaintext", label="", width=0, height=0)) + + visited = set() + + def visit(start): + ids = id(start) + if ids not in visited: + visited.add(ids) + G.add_node( + pydot.Node( + ids, + label=start.name, + shape=self.shape, + style="bold" if start.final else "", + ) + ) + for tran, destinations in start.transitions.items(): + for end in destinations: + visit(end) + G.add_edge( + pydot.Edge(ids, id(end), label=tran, labeldistance=2) + ) + for end in start.epsilon_transitions: + visit(end) + G.add_edge(pydot.Edge(ids, id(end), label="ε", labeldistance=2)) + + visit(self) + G.add_edge(pydot.Edge("start", id(self), label="", style="dashed")) + + return G + + def _repr_svg_(self): + try: + return self.graph().create_svg().decode("utf8") + except: + pass + + def write_to(self, fname): + return self.graph().write_svg(fname) + + +def multiline_formatter(state): + return "\n".join(str(item) for item in state) + + +def lr0_formatter(state): + try: + return "\n".join(str(item)[:-4] for item in state) + except TypeError: + return str(state)[:-4] diff --git a/src/cmp/cil.py b/src/cmp/cil.py new file mode 100644 index 000000000..5864ccdd0 --- /dev/null +++ b/src/cmp/cil.py @@ -0,0 +1,267 @@ +import src.cmp.visitor as visitor + + +class Node: + pass + + +class ProgramNode(Node): + def __init__(self, dottypes, dotdata, dotcode): + self.dottypes = dottypes + self.dotdata = dotdata + self.dotcode = dotcode + + +class TypeNode(Node): + def __init__(self, name): + self.name = name + self.attributes = [] + self.methods = [] + + +class DataNode(Node): + def __init__(self, vname, value): + self.name = vname + self.value = value + + +class FunctionNode(Node): + def __init__(self, fname, params, localvars, instructions): + self.name = fname + self.params = params + self.localvars = localvars + self.instructions = instructions + + +class ParamNode(Node): + def __init__(self, name): + self.name = name + + +class LocalNode(Node): + def __init__(self, name): + self.name = name + + +class InstructionNode(Node): + pass + + +class AssignNode(InstructionNode): + def __init__(self, dest, source): + self.dest = dest + self.source = source + + +class ArithmeticNode(InstructionNode): + def __init__(self, dest, left, right): + self.dest = dest + self.left = left + self.right = right + + +class PlusNode(ArithmeticNode): + pass + + +class MinusNode(ArithmeticNode): + pass + + +class StarNode(ArithmeticNode): + pass + + +class DivNode(ArithmeticNode): + pass + + +class GetAttribNode(InstructionNode): + pass + + +class SetAttribNode(InstructionNode): + pass + + +class GetIndexNode(InstructionNode): + pass + + +class SetIndexNode(InstructionNode): + pass + + +class AllocateNode(InstructionNode): + def __init__(self, itype, dest): + self.type = itype + self.dest = dest + + +class ArrayNode(InstructionNode): + pass + + +class TypeOfNode(InstructionNode): + def __init__(self, obj, dest): + self.obj = obj + self.dest = dest + + +class LabelNode(InstructionNode): + pass + + +class GotoNode(InstructionNode): + pass + + +class GotoIfNode(InstructionNode): + pass + + +class StaticCallNode(InstructionNode): + def __init__(self, function, dest): + self.function = function + self.dest = dest + + +class DynamicCallNode(InstructionNode): + def __init__(self, xtype, method, dest): + self.type = xtype + self.method = method + self.dest = dest + + +class ArgNode(InstructionNode): + def __init__(self, name): + self.name = name + + +class ReturnNode(InstructionNode): + def __init__(self, value=None): + self.value = value + + +class LoadNode(InstructionNode): + def __init__(self, dest, msg): + self.dest = dest + self.msg = msg + + +class LengthNode(InstructionNode): + pass + + +class ConcatNode(InstructionNode): + pass + + +class PrefixNode(InstructionNode): + pass + + +class SubstringNode(InstructionNode): + pass + + +class ToStrNode(InstructionNode): + def __init__(self, dest, ivalue): + self.dest = dest + self.ivalue = ivalue + + +class ReadNode(InstructionNode): + def __init__(self, dest): + self.dest = dest + + +class PrintNode(InstructionNode): + def __init__(self, str_addr): + self.str_addr = str_addr + + +def get_formatter(): + class PrintVisitor(object): + @visitor.on("node") + def visit(self, node): + pass + + @visitor.when(ProgramNode) + def visit(self, node): + dottypes = "\n".join(self.visit(t) for t in node.dottypes) + dotdata = "\n".join(self.visit(t) for t in node.dotdata) + dotcode = "\n".join(self.visit(t) for t in node.dotcode) + + return f".TYPES\n{dottypes}\n\n.DATA\n{dotdata}\n\n.CODE\n{dotcode}" + + @visitor.when(TypeNode) + def visit(self, node): + attributes = "\n\t".join(f"attribute {x}" for x in node.attributes) + methods = "\n\t".join(f"method {x}: {y}" for x, y in node.methods) + + return f"type {node.name} {{\n\t{attributes}\n\n\t{methods}\n}}" + + @visitor.when(FunctionNode) + def visit(self, node): + params = "\n\t".join(self.visit(x) for x in node.params) + localvars = "\n\t".join(self.visit(x) for x in node.localvars) + instructions = "\n\t".join(self.visit(x) for x in node.instructions) + + return f"function {node.name} {{\n\t{params}\n\n\t{localvars}\n\n\t{instructions}\n}}" + + @visitor.when(ParamNode) + def visit(self, node): + return f"PARAM {node.name}" + + @visitor.when(LocalNode) + def visit(self, node): + return f"LOCAL {node.name}" + + @visitor.when(AssignNode) + def visit(self, node): + return f"{node.dest} = {node.source}" + + @visitor.when(PlusNode) + def visit(self, node): + return f"{node.dest} = {node.left} + {node.right}" + + @visitor.when(MinusNode) + def visit(self, node): + return f"{node.dest} = {node.left} - {node.right}" + + @visitor.when(StarNode) + def visit(self, node): + return f"{node.dest} = {node.left} * {node.right}" + + @visitor.when(DivNode) + def visit(self, node): + return f"{node.dest} = {node.left} / {node.right}" + + @visitor.when(AllocateNode) + def visit(self, node): + return f"{node.dest} = ALLOCATE {node.type}" + + @visitor.when(TypeOfNode) + def visit(self, node): + return f"{node.dest} = TYPEOF {node.type}" + + @visitor.when(StaticCallNode) + def visit(self, node): + return f"{node.dest} = CALL {node.function}" + + @visitor.when(DynamicCallNode) + def visit(self, node): + return f"{node.dest} = VCALL {node.type} {node.method}" + + @visitor.when(ArgNode) + def visit(self, node): + return f"ARG {node.name}" + + @visitor.when(ReturnNode) + def visit(self, node): + return f'RETURN {node.value if node.value is not None else ""}' + + printer = PrintVisitor() + return lambda ast: printer.visit(ast) + diff --git a/src/cmp/evaluation.py b/src/cmp/evaluation.py new file mode 100644 index 000000000..830703efe --- /dev/null +++ b/src/cmp/evaluation.py @@ -0,0 +1,36 @@ +from src.cmp.pycompiler import EOF +from src.shift_reduce_parsers import ShiftReduceParser + + +def evaluate_reverse_parse(right_parse, operations, tokens): + if not right_parse or not operations or not tokens: + return + + right_parse = iter(right_parse) + tokens = iter(tokens) + stack = [] + for operation in operations: + if operation == ShiftReduceParser.SHIFT: + token = next(tokens) + stack.append(token.lex) + elif operation == ShiftReduceParser.REDUCE: + production = next(right_parse) + head, body = production + attributes = production.attributes + assert all( + rule is None for rule in attributes[1:] + ), "There must be only synteticed attributes." + rule = attributes[0] + + if len(body): + synteticed = [None] + stack[-len(body) :] + value = rule(None, synteticed) + stack[-len(body) :] = [value] + else: + stack.append(rule(None, None)) + else: + raise Exception("Invalid action!!!") + + assert len(stack) == 1 + assert isinstance(next(tokens).token_type, EOF) + return stack[0] diff --git a/src/cmp/nbpackage.py b/src/cmp/nbpackage.py new file mode 100644 index 000000000..5458e63b9 --- /dev/null +++ b/src/cmp/nbpackage.py @@ -0,0 +1,87 @@ +import io, os, sys, types + +from IPython import get_ipython +from nbformat import read +from IPython.core.interactiveshell import InteractiveShell + +def find_notebook(fullname, path=None): + """find a notebook, given its fully qualified name and an optional path + + This turns "foo.bar" into "foo/bar.ipynb" + and tries turning "Foo_Bar" into "Foo Bar" if Foo_Bar + does not exist. + """ + name = fullname.rsplit('.', 1)[-1] + if not path: + path = [''] + for d in path: + nb_path = os.path.join(d, name + ".ipynb") + if os.path.isfile(nb_path): + return nb_path + # let import Notebook_Name find "Notebook Name.ipynb" + nb_path = nb_path.replace("_", " ") + if os.path.isfile(nb_path): + return nb_path + +class NotebookLoader(object): + """Module Loader for Jupyter Notebooks""" + def __init__(self, path=None): + self.shell = InteractiveShell.instance() + self.path = path + + def load_module(self, fullname): + """import a notebook as a module""" + path = find_notebook(fullname, self.path) + + print ("importing Jupyter notebook from %s" % path) + + # load the notebook object + with io.open(path, 'r', encoding='utf-8') as f: + nb = read(f, 4) + + + # create the module and add it to sys.modules + # if name in sys.modules: + # return sys.modules[name] + mod = types.ModuleType(fullname) + mod.__file__ = path + mod.__loader__ = self + mod.__dict__['get_ipython'] = get_ipython + sys.modules[fullname] = mod + + # extra work to ensure that magics that would affect the user_ns + # actually affect the notebook module's ns + save_user_ns = self.shell.user_ns + self.shell.user_ns = mod.__dict__ + + try: + for cell in nb.cells: + if cell.cell_type == 'code': + # transform the input to executable Python + code = self.shell.input_transformer_manager.transform_cell(cell.source) + # run the code in themodule + exec(code, mod.__dict__) + finally: + self.shell.user_ns = save_user_ns + return mod + +class NotebookFinder(object): + """Module finder that locates Jupyter Notebooks""" + def __init__(self): + self.loaders = {} + + def find_module(self, fullname, path=None): + nb_path = find_notebook(fullname, path) + if not nb_path: + return + + key = path + if path: + # lists aren't hashable + key = os.path.sep.join(path) + + if key not in self.loaders: + self.loaders[key] = NotebookLoader(path) + return self.loaders[key] + +sys.meta_path.append(NotebookFinder()) \ No newline at end of file diff --git a/src/cmp/pycompiler.py b/src/cmp/pycompiler.py new file mode 100644 index 000000000..b78f03f70 --- /dev/null +++ b/src/cmp/pycompiler.py @@ -0,0 +1,512 @@ +import json + +class Symbol(object): + + def __init__(self, name, grammar): + self.Name = name + self.Grammar = grammar + + def __str__(self): + return self.Name + + def __repr__(self): + return repr(self.Name) + + def __add__(self, other): + if isinstance(other, Symbol): + return Sentence(self, other) + + raise TypeError(other) + + def __or__(self, other): + + if isinstance(other, (Sentence)): + return SentenceList(Sentence(self), other) + + raise TypeError(other) + + @property + def IsEpsilon(self): + return False + + def __len__(self): + return 1 + +class NonTerminal(Symbol): + + + def __init__(self, name, grammar): + super().__init__(name, grammar) + self.productions = [] + + + def __imod__(self, other): + + if isinstance(other, (Sentence)): + p = Production(self, other) + self.Grammar.Add_Production(p) + return self + + if isinstance(other, tuple): + assert len(other) > 1 + + if len(other) == 2: + other += (None,) * len(other[0]) + + assert len(other) == len(other[0]) + 2, "Debe definirse una, y solo una, regla por cada símbolo de la producción" + # assert len(other) == 2, "Tiene que ser una Tupla de 2 elementos (sentence, attribute)" + + if isinstance(other[0], Symbol) or isinstance(other[0], Sentence): + p = AttributeProduction(self, other[0], other[1:]) + else: + raise Exception("") + + self.Grammar.Add_Production(p) + return self + + if isinstance(other, Symbol): + p = Production(self, Sentence(other)) + self.Grammar.Add_Production(p) + return self + + if isinstance(other, SentenceList): + + for s in other: + p = Production(self, s) + self.Grammar.Add_Production(p) + + return self + + raise TypeError(other) + + @property + def IsTerminal(self): + return False + + @property + def IsNonTerminal(self): + return True + + @property + def IsEpsilon(self): + return False + +class Terminal(Symbol): + + def __init__(self, name, grammar): + super().__init__(name, grammar) + + @property + def IsTerminal(self): + return True + + @property + def IsNonTerminal(self): + return False + + @property + def IsEpsilon(self): + return False + +class EOF(Terminal): + + def __init__(self, Grammar): + super().__init__('$', Grammar) + +class Sentence(object): + + def __init__(self, *args): + self._symbols = tuple(x for x in args if not x.IsEpsilon) + self.hash = hash(self._symbols) + + def __len__(self): + return len(self._symbols) + + def __add__(self, other): + if isinstance(other, Symbol): + return Sentence(*(self._symbols + (other,))) + + if isinstance(other, Sentence): + return Sentence(*(self._symbols + other._symbols)) + + raise TypeError(other) + + def __or__(self, other): + if isinstance(other, Sentence): + return SentenceList(self, other) + + if isinstance(other, Symbol): + return SentenceList(self, Sentence(other)) + + raise TypeError(other) + + def __repr__(self): + return str(self) + + def __str__(self): + return ("%s " * len(self._symbols) % tuple(self._symbols)).strip() + + def __iter__(self): + return iter(self._symbols) + + def __getitem__(self, index): + return self._symbols[index] + + def __eq__(self, other): + return self._symbols == other._symbols + + def __hash__(self): + return self.hash + + @property + def IsEpsilon(self): + return False + +class SentenceList(object): + + def __init__(self, *args): + self._sentences = list(args) + + def Add(self, symbol): + if not symbol and (symbol is None or not symbol.IsEpsilon): + raise ValueError(symbol) + + self._sentences.append(symbol) + + def __iter__(self): + return iter(self._sentences) + + def __or__(self, other): + if isinstance(other, Sentence): + self.Add(other) + return self + + if isinstance(other, Symbol): + return self | Sentence(other) + + +class Epsilon(Terminal, Sentence): + + def __init__(self, grammar): + super().__init__('epsilon', grammar) + + + def __str__(self): + return "e" + + def __repr__(self): + return 'epsilon' + + def __iter__(self): + yield from () + + def __len__(self): + return 0 + + def __add__(self, other): + return other + + def __eq__(self, other): + return isinstance(other, (Epsilon,)) + + def __hash__(self): + return hash("") + + @property + def IsEpsilon(self): + return True + +class Production(object): + + def __init__(self, nonTerminal, sentence): + + self.Left = nonTerminal + self.Right = sentence + + def __str__(self): + + return '%s := %s' % (self.Left, self.Right) + + def __repr__(self): + return '%s -> %s' % (self.Left, self.Right) + + def __iter__(self): + yield self.Left + yield self.Right + + def __eq__(self, other): + return isinstance(other, Production) and self.Left == other.Left and self.Right == other.Right + + def __hash__(self): + return hash((self.Left, self.Right)) + + @property + def IsEpsilon(self): + return self.Right.IsEpsilon + +class AttributeProduction(Production): + + def __init__(self, nonTerminal, sentence, attributes): + if not isinstance(sentence, Sentence) and isinstance(sentence, Symbol): + sentence = Sentence(sentence) + super(AttributeProduction, self).__init__(nonTerminal, sentence) + + self.attributes = attributes + + def __str__(self): + return '%s := %s' % (self.Left, self.Right) + + def __repr__(self): + return '%s -> %s' % (self.Left, self.Right) + + def __iter__(self): + yield self.Left + yield self.Right + + + @property + def IsEpsilon(self): + return self.Right.IsEpsilon + + # sintetizar en ingles??????, pending aggrement + def syntetice(self): + pass + +class Grammar(): + + def __init__(self): + + self.Productions = [] + self.nonTerminals = [] + self.terminals = [] + self.startSymbol = None + # production type + self.pType = None + self.Epsilon = Epsilon(self) + self.EOF = EOF(self) + + self.symbDict = { '$': self.EOF } + + def NonTerminal(self, name, startSymbol = False): + + name = name.strip() + if not name: + raise Exception("Empty name") + + term = NonTerminal(name,self) + + if startSymbol: + + if self.startSymbol is None: + self.startSymbol = term + else: + raise Exception("Cannot define more than one start symbol.") + + self.nonTerminals.append(term) + self.symbDict[name] = term + return term + + def NonTerminals(self, names): + + ans = tuple((self.NonTerminal(x) for x in names.strip().split())) + + return ans + + + def Add_Production(self, production): + + if len(self.Productions) == 0: + self.pType = type(production) + + assert type(production) == self.pType, "The Productions most be of only 1 type." + + production.Left.productions.append(production) + self.Productions.append(production) + + + def Terminal(self, name): + + name = name.strip() + if not name: + raise Exception("Empty name") + + term = Terminal(name, self) + self.terminals.append(term) + self.symbDict[name] = term + return term + + def Terminals(self, names): + + ans = tuple((self.Terminal(x) for x in names.strip().split())) + + return ans + + + def __str__(self): + + mul = '%s, ' + + ans = 'Non-Terminals:\n\t' + + nonterminals = mul * (len(self.nonTerminals)-1) + '%s\n' + + ans += nonterminals % tuple(self.nonTerminals) + + ans += 'Terminals:\n\t' + + terminals = mul * (len(self.terminals)-1) + '%s\n' + + ans += terminals % tuple(self.terminals) + + ans += 'Productions:\n\t' + + ans += str(self.Productions) + + return ans + + def __getitem__(self, name): + try: + return self.symbDict[name] + except KeyError: + return None + + @property + def to_json(self): + + productions = [] + + for p in self.Productions: + head = p.Left.Name + + body = [] + + for s in p.Right: + body.append(s.Name) + + productions.append({'Head':head, 'Body':body}) + + d={'NonTerminals':[symb.Name for symb in self.nonTerminals], 'Terminals': [symb.Name for symb in self.terminals],\ + 'Productions':productions} + + # [{'Head':p.Left.Name, "Body": [s.Name for s in p.Right]} for p in self.Productions] + return json.dumps(d) + + @staticmethod + def from_json(data): + data = json.loads(data) + + G = Grammar() + dic = {'epsilon':G.Epsilon} + + for term in data['Terminals']: + dic[term] = G.Terminal(term) + + for noTerm in data['NonTerminals']: + dic[noTerm] = G.NonTerminal(noTerm) + + for p in data['Productions']: + head = p['Head'] + dic[head] %= Sentence(*[dic[term] for term in p['Body']]) + + return G + + def copy(self): + G = Grammar() + G.Productions = self.Productions.copy() + G.nonTerminals = self.nonTerminals.copy() + G.terminals = self.terminals.copy() + G.pType = self.pType + G.startSymbol = self.startSymbol + G.Epsilon = self.Epsilon + G.EOF = self.EOF + G.symbDict = self.symbDict.copy() + + return G + + @property + def IsAugmentedGrammar(self): + augmented = 0 + for left, right in self.Productions: + if self.startSymbol == left: + augmented += 1 + if augmented <= 1: + return True + else: + return False + + def AugmentedGrammar(self, force=False): + if not self.IsAugmentedGrammar or force: + + G = self.copy() + # S, self.startSymbol, SS = self.startSymbol, None, self.NonTerminal('S\'', True) + S = G.startSymbol + G.startSymbol = None + SS = G.NonTerminal('S\'', True) + if G.pType is AttributeProduction: + SS %= S + G.Epsilon, lambda x : x + else: + SS %= S + G.Epsilon + + return G + else: + return self.copy() + #endchange + +class Item: + + def __init__(self, production, pos, lookaheads=[]): + self.production = production + self.pos = pos + self.lookaheads = frozenset(look for look in lookaheads) + + def __str__(self): + s = str(self.production.Left) + " -> " + if len(self.production.Right) > 0: + for i,c in enumerate(self.production.Right): + if i == self.pos: + s += "." + s += str(self.production.Right[i]) + if self.pos == len(self.production.Right): + s += "." + else: + s += "." + s += ", " + str(self.lookaheads)[10:-1] + return s + + def __repr__(self): + return str(self) + + + def __eq__(self, other): + return ( + (self.pos == other.pos) and + (self.production == other.production) and + (set(self.lookaheads) == set(other.lookaheads)) + ) + + def __hash__(self): + return hash((self.production,self.pos,self.lookaheads)) + + @property + def IsReduceItem(self): + return len(self.production.Right) == self.pos + + @property + def NextSymbol(self): + if self.pos < len(self.production.Right): + return self.production.Right[self.pos] + else: + return None + + def NextItem(self): + if self.pos < len(self.production.Right): + return Item(self.production,self.pos+1,self.lookaheads) + else: + return None + + def Preview(self, skip=1): + unseen = self.production.Right[self.pos+skip:] + return [ unseen + (lookahead,) for lookahead in self.lookaheads ] + + def Center(self): + return Item(self.production, self.pos) \ No newline at end of file diff --git a/src/cmp/semantic.py b/src/cmp/semantic.py new file mode 100644 index 000000000..0cd3cfbb7 --- /dev/null +++ b/src/cmp/semantic.py @@ -0,0 +1,302 @@ +import itertools as itt +from collections import OrderedDict + + +class SemanticError(Exception): + @property + def text(self): + return self.args[0] + + +class Attribute: + def __init__(self, name, typex): + self.name = name + self.type = typex + + def __str__(self): + return f"[attrib] {self.name} : {self.type.name};" + + def __repr__(self): + return str(self) + + +class Method: + def __init__(self, name, param_names, params_types, return_type): + self.name = name + self.param_names = param_names + self.param_types = params_types + self.return_type = return_type + self.tset = None + + def __str__(self): + params = ", ".join( + f"{n}:{t.name}" for n, t in zip(self.param_names, self.param_types) + ) + return f"[method] {self.name}({params}): {self.return_type.name};" + + def __eq__(self, other): + return ( + other.name == self.name + and other.return_type == self.return_type + and other.param_types == self.param_types + ) + + +class Type: + def __init__(self, name: str): + self.name = name + self.attributes = [] + self.methods = [] + self.parent = None + + def set_parent(self, parent): + if self.parent is not None: + raise SemanticError(f"Parent type is already set for {self.name}.") + if parent.name == "String" or parent.name == "Bool" or parent.name == "Int": + raise SemanticError(f"Is not possible to inherit from {parent.name}") + self.parent = parent + + def get_attribute(self, name: str, visited=None): + if visited is None: + visited = [] + try: + return next(attr for attr in self.attributes if attr.name == name) + except StopIteration: + visited.append(self.name) + if self.parent is None: + raise SemanticError( + f'Attribute "{name}" is not defined in {self.name}.' + ) + try: + if self.parent.name in visited: + raise SemanticError( + f'Attribute "{name}" is not defined in {self.name}.' + ) + return self.parent.get_attribute(name, visited=visited) + except SemanticError: + raise SemanticError( + f'Attribute "{name}" is not defined in {self.name}.' + ) + + def define_attribute(self, name: str, typex): + try: + self.get_attribute(name) + except SemanticError: + attribute = Attribute(name, typex) + self.attributes.append(attribute) + return attribute + else: + raise SemanticError( + f'Attribute "{name}" is already defined in {self.name}.' + ) + + def get_method(self, name: str, non_rec=False, visited=None): + if visited is None: + visited = [] + try: + return next(method for method in self.methods if method.name == name) + except StopIteration: + visited.append(self.name) + if non_rec or self.parent is None: + raise SemanticError(f'Method "{name}" is not defined in {self.name}.') + try: + if self.parent.name in visited: + raise SemanticError( + f'Method "{name}" is not defined in {self.name}.' + ) + return self.parent.get_method(name, visited=visited) + except SemanticError: + raise SemanticError(f'Method "{name}" is not defined in {self.name}.') + + def define_method( + self, name: str, param_names: list, param_types: list, return_type + ): + if name in (method.name for method in self.methods): + raise SemanticError(f'Method "{name}" already defined in {self.name}') + + method = Method(name, param_names, param_types, return_type) + self.methods.append(method) + return method + + def all_attributes(self, clean=True): + plain = ( + OrderedDict() if self.parent is None else self.parent.all_attributes(False) + ) + for attr in self.attributes: + plain[attr.name] = (attr, self) + return plain.values() if clean else plain + + def all_methods(self, clean=True): + plain = OrderedDict() if self.parent is None else self.parent.all_methods(False) + for method in self.methods: + plain[method.name] = (method, self) + return plain.values() if clean else plain + + def conforms_to(self, other): + + return ( + other.bypass() + or self == other + or self.name == "AUTO_TYPE" + or other.name == "AUTO_TYPE" + or self.parent != None + and self.parent.conforms_to(other) + ) + + def bypass(self): + return False + + def __str__(self): + output = f"type {self.name}" + parent = "" if self.parent is None else f" : {self.parent.name}" + output += parent + output += " {" + output += "\n\t" if self.attributes or self.methods else "" + output += "\n\t".join(str(x) for x in self.attributes) + output += "\n\t" if self.attributes else "" + output += "\n\t".join(str(x) for x in self.methods) + output += "\n" if self.methods else "" + output += "}\n" + return output + + def __repr__(self): + return str(self) + + +class ErrorType(Type): + def __init__(self): + Type.__init__(self, "") + + def conforms_to(self, other): + return True + + def bypass(self): + return True + + def __eq__(self, other): + return isinstance(other, Type) + + +class VoidType(Type): + def __init__(self): + Type.__init__(self, "Void") + + # def conforms_to(self, other): + # raise Exception("Invalid type at 'conforms_to' : void type.") + + # def bypass(self): + # return True + + def __eq__(self, other): + return isinstance(other, VoidType) + + +class IntType(Type): + def __init__(self): + Type.__init__(self, "Int") + + def __eq__(self, other): + return other.name == self.name or isinstance(other, IntType) + + +class StringType(Type): + def __init__(self): + Type.__init__(self, "String") + + +class BoolType(Type): + def __init__(self): + Type.__init__(self, "Bool") + + +class AutoType(Type): + def __init__(self): + Type.__init__(self, "AUTO_TYPE") + + +class ObjectType(Type): + def __init__(self): + Type.__init__(self, "Object") + + +class SelfType(Type): + def __init__(self): + Type.__init__(self, "SELF_TYPE") + + +# Despues de entregar!!!! +class IOType(Type): + def __init__(self): + Type.__init__(self, "IO") + + +# --------------------------- + + +class Context: + def __init__(self): + self.types = {} + + def create_type(self, name: str): + if name in self.types: + raise SemanticError(f"Type with the same name ({name}) already in context.") + typex = self.types[name] = Type(name) + return typex + + def get_type(self, name: str): + try: + return self.types[name] + except KeyError: + raise SemanticError(f'Type "{name}" is not defined.') + + def __str__(self): + return ( + "{\n\t" + + "\n\t".join(y for x in self.types.values() for y in str(x).split("\n")) + + "\n}" + ) + + def __repr__(self): + return str(self) + + +class VariableInfo: + def __init__(self, name, vtype): + self.name = name + self.type = vtype + + +class Scope: + def __init__(self, parent=None): + self.locals = [] + self.parent = parent + self.children = [] + self.index = 0 if parent is None else len(parent) + + def __len__(self): + return len(self.locals) + + def create_child(self): + child = Scope(self) + self.children.append(child) + return child + + def define_variable(self, vname, vtype): + info = VariableInfo(vname, vtype) + self.locals.append(info) + return info + + def find_variable(self, vname, index=None): + locals = self.locals if index is None else itt.islice(self.locals, index) + try: + return next(x for x in locals if x.name == vname) + except StopIteration: + if self.parent is not None: + return self.parent.find_variable(vname, self.index) + return None + + def is_defined(self, vname): + return self.find_variable(vname) is not None + + def is_local(self, vname): + return any(True for x in self.locals if x.name == vname) diff --git a/src/cmp/tools/.ipynb_checkpoints/__init__-checkpoint.py b/src/cmp/tools/.ipynb_checkpoints/__init__-checkpoint.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/cmp/tools/.ipynb_checkpoints/automata-checkpoint.py b/src/cmp/tools/.ipynb_checkpoints/automata-checkpoint.py new file mode 100644 index 000000000..59643cc5b --- /dev/null +++ b/src/cmp/tools/.ipynb_checkpoints/automata-checkpoint.py @@ -0,0 +1,3 @@ +import zlib, base64 +exec(zlib.decompress(base64.b64decode('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'))) +# Created by pyminifier (https://github.com/liftoff/pyminifier) diff --git a/src/cmp/tools/.ipynb_checkpoints/evaluation-checkpoint.py b/src/cmp/tools/.ipynb_checkpoints/evaluation-checkpoint.py new file mode 100644 index 000000000..d49df0ce5 --- /dev/null +++ b/src/cmp/tools/.ipynb_checkpoints/evaluation-checkpoint.py @@ -0,0 +1,3 @@ +import zlib, base64 +exec(zlib.decompress(base64.b64decode('eJxdUMFuwjAMvecrfGy3qoLrJN86YGViCO2GECrF1SLSpErcqf37OUWwsZPtZ/v5+TXetVC3Xd6NtWs7bciDbjvnGV4/FmqJmsmrE1oaWFnUQdvAla1JFbhxltQaDVm1QLJ9S75iUmdqgL4r00tx7CofKGmyMn1RoBuwjqEB56ekFAw8ce+tggaXSZMqKCWWEge8kSQnaWSRQ0EVAok2K1iZ5uwuZI88dpSJWmlfyWB4EJF03p37mrWzkSXT9ou8/HU+xgHCImrbZAZ/5xSMf6q8Yvb61DMFBYz74vCUrBOTPs/l5OV/vZ8d8N8J+U5e1tkOtIVFYrJ5PBn92OVv4ZN8q21lInR78LLXBx2giBBLjtO/hgYByASaZld4miy7b+0QV/k7NRyxLY6yGDO5swVhi54X0+bEj9vkknF6P3H3azXZFEekGWlmh7u1150HxkmQSP0BhJm25Q=='))) +# Created by pyminifier (https://github.com/liftoff/pyminifier) diff --git a/src/cmp/tools/.ipynb_checkpoints/parsing-checkpoint.py b/src/cmp/tools/.ipynb_checkpoints/parsing-checkpoint.py new file mode 100644 index 000000000..02d672f4b --- /dev/null +++ b/src/cmp/tools/.ipynb_checkpoints/parsing-checkpoint.py @@ -0,0 +1,10 @@ +import zlib, base64 +exec(zlib.decompress(base64.b64decode('eJytVVtr2zAUfvevEH2yqWfa14AeypKGlXlNL5SCMUZO5FTMlhRZbpZu++87ujiOm3QwGJRU56pzvu8cuVKiQUxTpYWoW8QaKZRGrK3ZkgaVMS4bmXSaDcbPgmvCOFUPVAcrWqGlaGSnaVGLJamLiqlWh/a3jUktX0g0CVCFnSZAEltlgKb4MFMYBUirHbiiBZbJl3YmW1YLHiD6Y0mldoZrUrc0QKxCC6OYJi3VBXWeJgMFszFUQqE5YhxJI6EUV9k8N6dp0skV0TRMIyNCIi40SpOlK6Xtk9kwVCpKvsOpT3t8oaK6UxxNR0C4VsO5a/zn7wDN8KPqoHBTV2nqmieAecM49GPrzcp8DEcZOW/tvLngj+MAnR/ht31hNUUzY5/1UNkkty7JQolVt9RMcJsDPePb5CuttDlLON+z9YsVrgCvZ4uXpwQ6B5W0qoGPXntUCEI3+ORUxNJaZ7/wNHkhalV4Nm569dWR2iNcjREWdS22AHHssB6P2GaEObXSX7DcnMJyk82TVhOlH3ZNKep3DvNkdnv9PxG/xxuPuIlmcbszCSjvGqoMEjJygMPAtjvYjm9DD86A7iBDu8udsKcN8pWYZjJm3nLI3oHxA7rcQxCCx/llDHfSKHKRQNVdv0pV6ZVQXFV+sErjkPuB2I0ltuxYvSokUS3j60KTsqZ7cmPP9pjkCo5OH8B+9xSTk7g/Y9LDvoBjj7oJoCagyhb5ZDTuafYc0zwhUlK+Ckn0fvCdHWfEwGr6hgynOx8uMTvlogd6Tt0z5ujwJg9ZaiFrqBYrUUhFVwxafRUFF4Wiyw4wfBWAXooNYx5Ef3aIWcHCyQY8xYAnNJTCRwAZt4lvkB0qTODRa+cdxdhR4FNLa5xT/BHrUCc42CbDrZ38J5zZnYvHWwmWpsEX8O8NZ0ZyC2kW396+xk+JFNK9SQRvs6bJ/bu/hi0ar5BRYkwm+2EGyV7aT3D/OUAHXwRkKjjHl8E7rVSM6/BsppRQCboq4csJPSZJcuaXxXNpgApGocNwLHCarWOSZxd+ee3bYGZJEb6mYU15uHDTHH26jO1f1Ff11A+V98hY7m9+21tOjNs/1u2lt/1sNsEfuhaMXQ=='))) +# Created by pyminifier (https://github.com/liftoff/pyminifier) + +deprecated_metodo_predictivo_no_recursivo = metodo_predictivo_no_recursivo +def metodo_predictivo_no_recursivo(G, M=None, firsts=None, follows=None): + parser = deprecated_metodo_predictivo_no_recursivo(G, M, firsts, follows) + def updated(tokens): + return parser([t.token_type for t in tokens]) + return updated \ No newline at end of file diff --git a/src/cmp/tools/__init__.py b/src/cmp/tools/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/cmp/tools/automata.py b/src/cmp/tools/automata.py new file mode 100644 index 000000000..59643cc5b --- /dev/null +++ b/src/cmp/tools/automata.py @@ -0,0 +1,3 @@ +import zlib, base64 +exec(zlib.decompress(base64.b64decode('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'))) +# Created by pyminifier (https://github.com/liftoff/pyminifier) diff --git a/src/cmp/tools/evaluation.py b/src/cmp/tools/evaluation.py new file mode 100644 index 000000000..d49df0ce5 --- /dev/null +++ b/src/cmp/tools/evaluation.py @@ -0,0 +1,3 @@ +import zlib, base64 +exec(zlib.decompress(base64.b64decode('eJxdUMFuwjAMvecrfGy3qoLrJN86YGViCO2GECrF1SLSpErcqf37OUWwsZPtZ/v5+TXetVC3Xd6NtWs7bciDbjvnGV4/FmqJmsmrE1oaWFnUQdvAla1JFbhxltQaDVm1QLJ9S75iUmdqgL4r00tx7CofKGmyMn1RoBuwjqEB56ekFAw8ce+tggaXSZMqKCWWEge8kSQnaWSRQ0EVAok2K1iZ5uwuZI88dpSJWmlfyWB4EJF03p37mrWzkSXT9ou8/HU+xgHCImrbZAZ/5xSMf6q8Yvb61DMFBYz74vCUrBOTPs/l5OV/vZ8d8N8J+U5e1tkOtIVFYrJ5PBn92OVv4ZN8q21lInR78LLXBx2giBBLjtO/hgYByASaZld4miy7b+0QV/k7NRyxLY6yGDO5swVhi54X0+bEj9vkknF6P3H3azXZFEekGWlmh7u1150HxkmQSP0BhJm25Q=='))) +# Created by pyminifier (https://github.com/liftoff/pyminifier) diff --git a/src/cmp/tools/parsing.py b/src/cmp/tools/parsing.py new file mode 100644 index 000000000..d0275cbcb --- /dev/null +++ b/src/cmp/tools/parsing.py @@ -0,0 +1,16 @@ +import zlib, base64 +exec(zlib.decompress(base64.b64decode('eJytVVtr2zAUfvevEH2yqWfa14AeypKGlXlNL5SCMUZO5FTMlhRZbpZu++87ujiOm3QwGJRU56pzvu8cuVKiQUxTpYWoW8QaKZRGrK3ZkgaVMS4bmXSaDcbPgmvCOFUPVAcrWqGlaGSnaVGLJamLiqlWh/a3jUktX0g0CVCFnSZAEltlgKb4MFMYBUirHbiiBZbJl3YmW1YLHiD6Y0mldoZrUrc0QKxCC6OYJi3VBXWeJgMFszFUQqE5YhxJI6EUV9k8N6dp0skV0TRMIyNCIi40SpOlK6Xtk9kwVCpKvsOpT3t8oaK6UxxNR0C4VsO5a/zn7wDN8KPqoHBTV2nqmieAecM49GPrzcp8DEcZOW/tvLngj+MAnR/ht31hNUUzY5/1UNkkty7JQolVt9RMcJsDPePb5CuttDlLON+z9YsVrgCvZ4uXpwQ6B5W0qoGPXntUCEI3+ORUxNJaZ7/wNHkhalV4Nm569dWR2iNcjREWdS22AHHssB6P2GaEObXSX7DcnMJyk82TVhOlH3ZNKep3DvNkdnv9PxG/xxuPuIlmcbszCSjvGqoMEjJygMPAtjvYjm9DD86A7iBDu8udsKcN8pWYZjJm3nLI3oHxA7rcQxCCx/llDHfSKHKRQNVdv0pV6ZVQXFV+sErjkPuB2I0ltuxYvSokUS3j60KTsqZ7cmPP9pjkCo5OH8B+9xSTk7g/Y9LDvoBjj7oJoCagyhb5ZDTuafYc0zwhUlK+Ckn0fvCdHWfEwGr6hgynOx8uMTvlogd6Tt0z5ujwJg9ZaiFrqBYrUUhFVwxafRUFF4Wiyw4wfBWAXooNYx5Ef3aIWcHCyQY8xYAnNJTCRwAZt4lvkB0qTODRa+cdxdhR4FNLa5xT/BHrUCc42CbDrZ38J5zZnYvHWwmWpsEX8O8NZ0ZyC2kW396+xk+JFNK9SQRvs6bJ/bu/hi0ar5BRYkwm+2EGyV7aT3D/OUAHXwRkKjjHl8E7rVSM6/BsppRQCboq4csJPSZJcuaXxXNpgApGocNwLHCarWOSZxd+ee3bYGZJEb6mYU15uHDTHH26jO1f1Ff11A+V98hY7m9+21tOjNs/1u2lt/1sNsEfuhaMXQ=='))) +# Created by pyminifier (https://github.com/liftoff/pyminifier) + +deprecated_metodo_predictivo_no_recursivo = metodo_predictivo_no_recursivo +def metodo_predictivo_no_recursivo(G, M=None, firsts=None, follows=None): + parser = deprecated_metodo_predictivo_no_recursivo(G, M, firsts, follows) + def updated(tokens): + return parser([t.token_type for t in tokens]) + return updated + +exec(zlib.decompress(base64.b64decode('eJx9U8GO2jAQvfMVZi9JtCFarqiuVLUsRUilWranCEUmGcBaY0e2s3TV7b/X9iQhpaiXxJ4Zv3nzZqYUzBiyOfK9fYKqKeE70wb0bEQ2X5ePzzQKv2hEnuZffnye0wj/zrBe0Wi9cocK9qQouOS2KGIDYp8u0lfQO2WAPjJhIHFoxDuyBV10xy6i/XdmVlquJP31uzMclFWDa7FruKiK2rHk8lBYthMQJy2JWz7/KhDQjBsg35RdnmoBJ5AWqrnWSvfPi5IJ0dVwTg9gC+OFKXRQZliMZeULzR+27lw22ihNH9xRNbZuLM29WdWgma/F4P185ALIs27AA3gECzTg5JOpDyBCqRd2BFbRc46gwcz3fwk2qzWXNg4v0+jDZDJ5f3efj1HavZptE3wXhyRpj5tIZQmXQ6EDF4KQ/4QnA+ddkCojn3ZKW6dulmV36NdgGy2dsNI3kSBuatmBDvLkV9hdZW27MTSMGjK6qJexugZZxZcITBsEuKd5D+lTBti2I/d06m8grtPgBP83D4ZgImxq53ZJ0BxS7lT1Rp0pWPZKE/N22inhRdbgGmagin1MgtmQdFarOkYQ4pYPtB3aHcmA0RV5PSUkLES/Gq2wvaa9LoGfj9jeVmG9mo1uUbrJKOxu5mzabi7s2lABEsfRRU6HI4HK+Tb7wbteJ8fJQIwx6aUPCdI1uCbt1s5/llB7dxwt5SsTvGqLGY/HUTL6AyImjec='))) +# Created by pyminifier (https://github.com/liftoff/pyminifier) + +exec(zlib.decompress(base64.b64decode('eJyFVltP4zoQfu+v8D41OcfHWl6RLJ0KekEgqLg+dKtiGrf1ktiR7RS6iP9+ZuykSYE9ywOKLzPzzTffjLuypiDLomSVV7kjqiiN9eTEaC+UlvZG+t6queKNyR0rhXVKr5urS1OUlZeLlbLOO9osc7MUedxsHZQ7PFa5tI31mZdFL5MrIl9LobMkozo97pEdz9ilfPU3u+LJ5D2iVmRHlCOXRktiLNHGkx07c7C+lbZQWuRgRaz0ldWzeY/c824KSdojKzAbEqVJxqZWbpV8STASeeZfQE40HYINuWdVmQkvk2dYCeckQMbY92wZ3buFLJ3Kje41wTGjpLQmo9/pfYpRcYGBdwy/qqVXRrt5yBpDW+lcMkAsOX97j0DD/QHCWwETJ1J7aTEJ4u0OdyG/fLaCPIG3pSw9OZe7obXGhkM84vfcxcTbJDKWG/MsNlJkLm0AvwXArx1sFBbGUTR/TkMGr/QZAeVMwV2XpO8RfG5cZYE3e5QMYt0mh7T/NYAwV/zWVrJHXjZQeHKFCK/4SOQO9oj4VKc2/0lIRjDQgQRpdBSSBh+TJi+xT6YldJIGjGvjTQ1wSqNEOYqI/qycXzxLq2UewSD8usKdMxRbNEP5YemDdf8xbj6SAu6SJ4lF3qpMZijVx0/OH/s9MuDQB7+kRl6jugPzaVtvtO3qnvNpm1k47SKT4PdDDSKotG04UXlTCC+adrvxwBctqhyaHThfQGw4BnEFsp4qlWeLi+ujRW1ndDLu8JJLWDPnha0BdgWdcn5E+2MrikLYPS2iWheo3gwI0PxwVoBv2JyN2fBqND/UQdiD0zP+23iz7yB/wwOHZ9BrrbR5NKcoE98hfWbmKUq0y5kHNQHFPBCTtHcnKUXVwtmWzzxE2vA3f2zfGxlvUZsXfAudUgbV3vHN7GJey3eK5RwzX48m9/eY6XZSuaDrQxwXAQcha75X7AQU2xVSjYegDlCI6+CG4CBSGhusnQ7kBdCsEc2X8+FD7HUdu7b6Hy7gb8tEWWI7rsP6joksW3grtFNYlmTKLkUh6QuyysC6lVjyhexaeds/PDM3G7Xy1xKqL6dwAopd5iBLAmqN6+TTDVQuynoRdV07XHjxlMvkIQz/MX9gYzZoRFqrN2nStfzrlqjLrOgpFlrqqpAWOQshQ4Ee2FbaJ+PkcWmV9omi/R++D//0D0/67KdROnHeJq9xvqKbU1S6lyle6gdyT5nKXrmqo4VYsYCShyP83E+P2jwWOAySMxfZwBaJ26SE16TtobgHd0t2IVeeHzZbbQKpLKxcK4clfGAiPhGJpLFHKexdnVOcimlUSBhMjfG+G7pvT3P4W9fT4PZ6eHp3MqRl7bfjdvrh5wEJnXPK1qDWKMC04SfkNwUuur8T/hz7ZnI2uqXrr1I6NMR2rc2wI/7FIqhlIf3GZLX89rdHFIgKEqkH6nloZGBnhO/MaHY+5/yS9oOS/4nFw4P41WxAw69ytfTfvn2DoRqtLnv/ATLgLos='))) +# Created by pyminifier (https://github.com/liftoff/pyminifier) diff --git a/src/cmp/tools/regex.py b/src/cmp/tools/regex.py new file mode 100644 index 000000000..85d74325a --- /dev/null +++ b/src/cmp/tools/regex.py @@ -0,0 +1,3 @@ +import zlib, base64 +exec(zlib.decompress(base64.b64decode('eJytVsFu2zgQvesreFhDVE0IdY8BCNTZtVRg2yyaOKgdwxAYiYrZSKRK0qnttp+1v7HftCQlWbLWTXPYgwzyzXDem9Fw5FyKEqRlFRKlASsrITWYalGy9EpkFF0yTuTeLW/blZe3Z6p9KsqKFVS2R2NJypLIzkULUaiQbE1IoknjBv+IpujKPC2epIVQW0l7gOAp0ZQTzQTv4JJxVrLDAN1yu+U5SbRIspwEQ376RIqtO9QKbRCaVEQqOvS3IOMPrXNJtchEUkmasVSzJ5FwkUiabo3Xk+gObzUrVHtoLh4p975gk6uXFkQpMKsUKwS3NYRdjYMLD2Q0PyqCiha5BYGkeis5+AKVNrjCE5Sb11EovHq9RloSrphNSeFvPwJP4l74hvBmX96L4sV8CttlWNDdGfI3R/LJgBy+Riq4mBgNKe4YGwm/1y/WaTh2kGV7a+Oy1JR2I7JakaiotIKsMNqvwLBNGg/vI+6FbwhvbS84uq53f8FXuHBI/pzXNdjAz7vGR642Wde0/zf5yVUYiogi3LF6NrCkD3RnLoLpPnagEmq60yhG6pFVydcNM++yIql5oXNZ823wau2BOMbfdheuZ+EOxavdOsiFBDvA+Mr/7iP/lXmgeQLz/PO3v/7hAetwMA7AUljlLAdDGkB4Bg4hU24LXYLAZKQZ31Kz1nLvoM84jlcHIwTQXUorDf6k+5mUQjbWWtnBKPOV6zF/HRiL68miDrEJSVVRnsHPxnLc1Af933wUh7O/osDYmgJvXLnut6zIkod6bjl9MY7bnQdmOA6vBJ9TWVoq6M985CrngTmK0BQt0BLdnTop6M9BBKZgAZbgzjeuFfqAbtAlIujWuPb8voNXAIIA1DkBU1jLOcLz8QIVpLzPCNggdaFWb9bIMNBTcGLqtRjhajzr49dwYweEPRM4u0m8Hg19L+tjchjhaLx8IdXS6OqjUdQyTSzT8lmmaISn47sXMt2N8Ic++tERBc7wDMd0hEkfTWEjzRhu+wbZM9yMZ+PLoa5jk8RejAct4r3Hz38QYBw0A+Ha3sVm3iaJ+XbpJHHzFrlb+t9LGZmuqKfAJzeM7SJ0vtj9un0zGQTHn8Ja2xGBzitoGVNzOVpGe0lPIzcp9gIaqlQ82LnhxkZwdnKdpXwulQ0ezqT6yJmhVB+yFxu/hxu7mOPTTzXMkcPf4Xl4/IRZYIG7PwDwnUUe8dn/DXARdMk/ev8C0IsPHg=='))) +# Created by pyminifier (https://github.com/liftoff/pyminifier) diff --git a/src/cmp/utils.py b/src/cmp/utils.py new file mode 100644 index 000000000..5bcf97b19 --- /dev/null +++ b/src/cmp/utils.py @@ -0,0 +1,343 @@ +from src.cmp.pycompiler import Production, Sentence, Symbol, EOF, Epsilon + + +class ContainerSet: + def __init__(self, *values, contains_epsilon=False): + self.set = set(values) + self.contains_epsilon = contains_epsilon + + def add(self, value): + n = len(self.set) + self.set.add(value) + return n != len(self.set) + + def extend(self, values): + change = False + for value in values: + change |= self.add(value) + return change + + def set_epsilon(self, value=True): + last = self.contains_epsilon + self.contains_epsilon = value + return last != self.contains_epsilon + + def update(self, other): + n = len(self.set) + self.set.update(other.set) + return n != len(self.set) + + def epsilon_update(self, other): + return self.set_epsilon(self.contains_epsilon | other.contains_epsilon) + + def hard_update(self, other): + return self.update(other) | self.epsilon_update(other) + + def find_match(self, match): + for item in self.set: + if item == match: + return item + return None + + def __len__(self): + return len(self.set) + int(self.contains_epsilon) + + def __str__(self): + return "%s-%s" % (str(self.set), self.contains_epsilon) + + def __repr__(self): + return str(self) + + def __iter__(self): + return iter(self.set) + + def __nonzero__(self): + return len(self) > 0 + + def __eq__(self, other): + if isinstance(other, set): + return self.set == other + return ( + isinstance(other, ContainerSet) + and self.set == other.set + and self.contains_epsilon == other.contains_epsilon + ) + + +def inspect(item, grammar_name="G", mapper=None): + try: + return mapper[item] + except (TypeError, KeyError): + if isinstance(item, dict): + items = ",\n ".join( + f"{inspect(key, grammar_name, mapper)}: {inspect(value, grammar_name, mapper)}" + for key, value in item.items() + ) + return f"{{\n {items} \n}}" + elif isinstance(item, ContainerSet): + args = ( + f'{ ", ".join(inspect(x, grammar_name, mapper) for x in item.set) } ,' + if item.set + else "" + ) + return f"ContainerSet({args} contains_epsilon={item.contains_epsilon})" + elif isinstance(item, EOF): + return f"{grammar_name}.EOF" + elif isinstance(item, Epsilon): + return f"{grammar_name}.Epsilon" + elif isinstance(item, Symbol): + return f"G['{item.Name}']" + elif isinstance(item, Sentence): + items = ", ".join(inspect(s, grammar_name, mapper) for s in item._symbols) + return f"Sentence({items})" + elif isinstance(item, Production): + left = inspect(item.Left, grammar_name, mapper) + right = inspect(item.Right, grammar_name, mapper) + return f"Production({left}, {right})" + elif isinstance(item, tuple) or isinstance(item, list): + ctor = ("(", ")") if isinstance(item, tuple) else ("[", "]") + return f'{ctor[0]} {("%s, " * len(item)) % tuple(inspect(x, grammar_name, mapper) for x in item)}{ctor[1]}' + else: + raise ValueError(f"Invalid: {item}") + + +def pprint(item, header=""): + if header: + print(header) + + if isinstance(item, dict): + for key, value in item.items(): + print(f"{key} ---> {value}") + elif isinstance(item, list): + print("[") + for x in item: + print(f" {repr(x)}") + print("]") + else: + print(item) + + +class Token: + """ + Basic token class. + + Parameters + ---------- + lex : str + Token's lexeme. + token_type : Enum + Token's type. + """ + + def __init__(self, lex, token_type): + self.lex = lex + self.token_type = token_type + + def __str__(self): + return f"{self.token_type}: {self.lex}" + + def __repr__(self): + return str(self) + + @property + def is_valid(self): + return True + + +class UnknownToken(Token): + def __init__(self, lex): + Token.__init__(self, lex, None) + + def transform_to(self, token_type): + return Token(self.lex, token_type) + + @property + def is_valid(self): + return False + + +def tokenizer(G, fixed_tokens): + def decorate(func): + def tokenize_text(text): + tokens = [] + collecting_str = False + str_token = "" + + # ---------Removing Comments(Comments starting with "--" are yet to implement)------------ + no_comments_text = "" + collecting_comment = False + for lex in text.split(): + if lex[0] == "*" and not collecting_comment: + collecting_comment = True + + elif lex[-1] == "*": + collecting_comment = False + continue + + if not collecting_comment: + no_comments_text += lex + " " + + text = no_comments_text + for lex in text.split(): + + # ------Building strings------------ + if lex[0] == '"' and not collecting_str: + collecting_str = True + if len(lex) > 1: + str_token += lex[1:] + " " + continue + + if lex[-1] == '"': + collecting_str = False + if len(lex) > 1: + str_token += lex[:-1] + token = Token( + str_token, G.terminals[39] + ) # 39 is the index of "string" terminal + tokens.append(token) + str_token = "" + continue + + if collecting_str: + str_token += lex + " " + continue + + try: + token = fixed_tokens[lex] + except KeyError: + token = UnknownToken(lex) + try: + token = func(token) + except TypeError: + pass + tokens.append(token) + tokens.append(Token("$", G.EOF)) + return tokens + + if hasattr(func, "__call__"): + return tokenize_text + elif isinstance(func, str): + return tokenize_text(func) + else: + raise TypeError('Argument must be "str" or a callable object.') + + return decorate + + +class DisjointSet: + def __init__(self, *items): + self.nodes = {x: DisjointNode(x) for x in items} + + def merge(self, items): + items = (self.nodes[x] for x in items) + try: + head, *others = items + for other in others: + head.merge(other) + except ValueError: + pass + + @property + def representatives(self): + return {n.representative for n in self.nodes.values()} + + @property + def groups(self): + return [ + [n for n in self.nodes.values() if n.representative == r] + for r in self.representatives + ] + + def __len__(self): + return len(self.representatives) + + def __getitem__(self, item): + return self.nodes[item] + + def __str__(self): + return str(self.groups) + + def __repr__(self): + return str(self) + + +class DisjointNode: + def __init__(self, value): + self.value = value + self.parent = self + + @property + def representative(self): + if self.parent != self: + self.parent = self.parent.representative + return self.parent + + def merge(self, other): + other.representative.parent = self.representative + + def __str__(self): + return str(self.value) + + def __repr__(self): + return str(self) + + +def find_least_type(type_a, type_b, context): + if type_a is None: + return type_b + + if type_b is None: + return type_a + + if type_a.conforms_to(type_b): + return type_b + + if type_b.conforms_to(type_a): + return type_a + + solve = type_a.parent + while solve is not None: + if type_b.conforms_to(solve): + return solve + solve = solve.parent + + return context.get_type("Object") + + +def least_type(type_set, context): + solve = None + for item in type_set: + typex = context.get_type(item) + solve = find_least_type(solve, typex, context) + + return solve.name + + +def union(set_a, set_b): + for item in set_b: + set_a.add(item) + return set_a + + +def intersection(set_a, set_b): + solve = set() + for item in set_a: + if item in set_b: + solve.add(item) + return solve + + +def reduce_set(set_a, set_b): + if "!static_type_declared" in set_a: + return set_a + + if "InferenceError" in set_a: + return union(set_a, set_b) + + _intersection = intersection(set_a, set_b) + if len(_intersection) == 0: + _union = union(set_a, set_b) + _union.add("InferenceError") + return _union + else: + return _intersection diff --git a/src/cmp/visitor.py b/src/cmp/visitor.py new file mode 100644 index 000000000..500298bcd --- /dev/null +++ b/src/cmp/visitor.py @@ -0,0 +1,80 @@ +# The MIT License (MIT) +# +# Copyright (c) 2013 Curtis Schlak +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +import inspect + +__all__ = ['on', 'when'] + +def on(param_name): + def f(fn): + dispatcher = Dispatcher(param_name, fn) + return dispatcher + return f + + +def when(param_type): + def f(fn): + frame = inspect.currentframe().f_back + func_name = fn.func_name if 'func_name' in dir(fn) else fn.__name__ + dispatcher = frame.f_locals[func_name] + if not isinstance(dispatcher, Dispatcher): + dispatcher = dispatcher.dispatcher + dispatcher.add_target(param_type, fn) + def ff(*args, **kw): + return dispatcher(*args, **kw) + ff.dispatcher = dispatcher + return ff + return f + + +class Dispatcher(object): + def __init__(self, param_name, fn): + frame = inspect.currentframe().f_back.f_back + top_level = frame.f_locals == frame.f_globals + self.param_index = self.__argspec(fn).args.index(param_name) + self.param_name = param_name + self.targets = {} + + def __call__(self, *args, **kw): + typ = args[self.param_index].__class__ + d = self.targets.get(typ) + if d is not None: + return d(*args, **kw) + else: + issub = issubclass + t = self.targets + ks = t.keys() + ans = [t[k](*args, **kw) for k in ks if issub(typ, k)] + if len(ans) == 1: + return ans.pop() + return ans + + def add_target(self, typ, target): + self.targets[typ] = target + + @staticmethod + def __argspec(fn): + # Support for Python 3 type hints requires inspect.getfullargspec + if hasattr(inspect, 'getfullargspec'): + return inspect.getfullargspec(fn) + else: + return inspect.getargspec(fn) diff --git a/src/main.py b/src/main.py new file mode 100644 index 000000000..7af8567f9 --- /dev/null +++ b/src/main.py @@ -0,0 +1,99 @@ +from src.lexical_analizer import tokenize_cool_text +from src.cool_grammar import define_cool_grammar +from src.cool_visitor import FormatVisitorST + +from src.type_collector import TypeCollector +from src.type_builder import TypeBuilder +from src.type_checker import TypeChecker +from src.tset_builder import TSetBuilder +from src.tsets_reducer import TSetReducer +from src.tset_merger import TSetMerger + +from src.shift_reduce_parsers import LR1Parser, DerivationTree +from src.errors import parsing_table_error, Error + +from src.cmp.evaluation import evaluate_reverse_parse + +from src.ui import print_array, print_grammar, print_tset + + +""" # Cool Intrepreter """ + +def run_pipeline(text): + main_error1 = ["A class Main with a method main most be provided"] + main_error2 = ['"main" method in class Main does not receive any parameters'] + # define grammar + grammar, idx, string, num = define_cool_grammar() + + # try: + tokens = tokenize_cool_text(grammar, idx, string, num, text) + parser = LR1Parser(grammar) + parse, operations = parser([t.token_type for t in tokens]) + + # print("\n".join(repr(x) for x in parse)) + # print(operations) + + ast = evaluate_reverse_parse(parse, operations, tokens) + formatter = FormatVisitorST() + tree = formatter.visit(ast) + + print("Initial AST") + print_array(tree) + + errors = [] + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + if errors != [] and errors != main_error1 and errors != main_error2: + print("---------ERRORS----------") + print_array(errors) + else: + if errors == main_error1 or errors == main_error2: + errors = [] + + tset_builder = TSetBuilder(context, errors) + tset = tset_builder.visit(ast, None) + + tset_reducer = TSetReducer(context, errors) + reduced_set = tset_reducer.visit(ast, tset) + + tset_merger = TSetMerger(context, errors) + tset_merger.visit(ast, reduced_set) + + collector = TypeCollector(errors) + collector.visit(ast) + + context = collector.context + + builder = TypeBuilder(context, errors) + builder.visit(ast) + + checker = TypeChecker(context, errors) + checker.visit(ast, None) + + if errors != [] and errors != main_error1 and errors != main_error2: + print("----------ERRORS-----------") + print_array(errors) + + print("Reduced Sets") + print(reduced_set) + + tree = formatter.visit(ast) + print("Final Tree:") + print_array(tree) + + # except Error as error: + # st.header("Sorry an error occur while tokenizing text:") + # st.write(str(error)) + + + diff --git a/src/type_builder.py b/src/type_builder.py new file mode 100644 index 000000000..ed0f0119c --- /dev/null +++ b/src/type_builder.py @@ -0,0 +1,201 @@ +from src.cmp.semantic import SemanticError +from src.cmp.semantic import Attribute, Method, Type +from src.cmp.semantic import VoidType, IntType, ErrorType, StringType, BoolType +from src.cmp.semantic import Context +from src.ast_nodes import ( + ProgramNode, + ClassDeclarationNode, + AttrDeclarationNode, + FuncDeclarationNode, +) +import src.cmp.visitor as visitor +from src.tset import Tset +from collections import deque + + +class TypeBuilder: + def __init__(self, context, errors=[]): + self.context = context + self.current_type = None + self.errors = errors + + @visitor.on("node") + def visit(self, node): + pass + + @visitor.when(ProgramNode) + def visit(self, node): + # Despues de entregar!!!!!! + io_type = self.context.get_type("IO") + self_type = self.context.get_type("SELF_TYPE") + int_type = self.context.get_type("Int") + string_type = self.context.get_type("String") + object_type = self.context.get_type("Object") + + # IO + parent_tset = Tset() + parent_tset.locals["out_string"] = {"SELF_TYPE"} + parent_tset.locals["out_int"] = {"SELF_TYPE"} + parent_tset.locals["in_string"] = {"String"} + parent_tset.locals["in_int"] = {"Int"} + + method = io_type.define_method("out_string", ["x"], [string_type], self_type) + method.tset = Tset(parent_tset) + method.tset.locals["x"] = {"String"} + + method = io_type.define_method("out_int", ["x"], [int_type], self_type) + method.tset = Tset(parent_tset) + method.tset.locals["x"] = {"Int"} + + method = io_type.define_method("in_string", [], [], string_type) + method.tset = Tset(parent_tset) + + method = io_type.define_method("in_int", [], [], int_type) + method.tset = Tset(parent_tset) + + # -------String + parent_tset = Tset() + parent_tset.locals["concat"] = {"String"} + parent_tset.locals["substr"] = {"String"} + parent_tset.locals["length"] = {"Int"} + + method = string_type.define_method("concat", ["s"], [string_type], string_type) + method.tset = Tset(parent_tset) + method.tset.locals["s"] = {"String"} + + method = string_type.define_method( + "substr", ["i", "l"], [int_type, int_type], string_type + ) + method.tset = Tset(parent_tset) + method.tset.locals["i"] = {"Int"} + method.tset.locals["l"] = {"Int"} + + method = string_type.define_method("length", [], [], int_type) + method.tset = Tset(parent_tset) + + # Object + parent_tset = Tset() + parent_tset.locals["abort"] = {"Object"} + parent_tset.locals["type_name"] = {"String"} + parent_tset.locals["copy"] = {"SELF_TYPE"} + + method = object_type.define_method("abort", [], [], object_type) + method.tset = Tset(parent_tset) + + method = object_type.define_method("type_name", [], [], string_type) + method.tset = Tset(parent_tset) + + method = object_type.define_method("copy", [], [], self_type) + method.tset = Tset(parent_tset) + + # -------------------- + + # ------checking for in order definitions and cyclic heritage + parent_child_dict = {} + queue = deque() + visited = {} + not_visited = [] # ++ + + for class_declaration in node.declarations: + not_visited.append(class_declaration) # ++ + parent_type = class_declaration.parent + try: + self.context.get_type(parent_type) + try: + parent_child_dict[parent_type].append(class_declaration) + except: # KeyError + parent_child_dict[parent_type] = [class_declaration] + except SemanticError: # parent is None or not definition provided + queue.append(class_declaration) + + main_round = 0 + while not_visited: # ++ + main_round += 1 + while queue: + class_declaration = queue.popleft() + try: + class_visited, roundn = visited[class_declaration] # .id + + if roundn == main_round: + self.errors.append( + f"{class_declaration.id} is involved in a cyclic heritage" + ) + + except: + not_visited.remove(class_declaration) + try: + children = parent_child_dict[class_declaration.id] + for declaration in children: + queue.append(declaration) + except: # no es padre de nadie + pass + + self.visit(class_declaration) + visited[class_declaration] = (True, main_round) # .id + + if not_visited: + queue.append(not_visited[0]) + + try: + main_meth = self.context.get_type("Main").get_method("main", non_rec=True) + if len(main_meth.param_names) > 0: + self.errors.append( + '"main" method in class Main does not receive any parameters' + ) + # modify in semantic get_method in order to get some ancestor where the method is already defined + except SemanticError: + self.errors.append("A class Main with a method main most be provided") + + # ---------------------------------------------------- + # for declaration in node.declarations: + # self.visit(declaration) + + @visitor.when(ClassDeclarationNode) + def visit(self, node): + # print(f"------------visiting class {node.id}------------") + self.current_type = self.context.get_type(node.id) + + if node.parent is not None: + try: + parent_type = self.get_type(node.parent) + self.current_type.set_parent(parent_type) + except SemanticError as error: + self.errors.append(error.text) + else: + object_type = self.context.get_type("Object") + try: + self.current_type.set_parent(object_type) + except SemanticError as error: + self.errors.append(error.text) + + for feature in node.features: + self.visit(feature) + + @visitor.when(FuncDeclarationNode) + def visit(self, node): + param_names = [fname for fname, ftype in node.params] + + try: + param_types = [self.get_type(ftype) for fname, ftype in node.params] + return_type = self.get_type(node.type) + self.current_type.define_method( + node.id, param_names, param_types, return_type + ) + except SemanticError as error: + # print("--------aqui se esta reportando el error del metodo doble---------") + self.errors.append(error.text) + + @visitor.when(AttrDeclarationNode) + def visit(self, node): + try: + attr_type = self.get_type(node.type) + self.current_type.define_attribute(node.id, attr_type) + except SemanticError as error: + self.errors.append(error.text) + + def get_type(self, tname): + try: + return self.context.get_type(tname) + except SemanticError as error: + self.errors.append(error.text) + return ErrorType() diff --git a/src/type_checker.py b/src/type_checker.py new file mode 100644 index 000000000..d8b9cf83e --- /dev/null +++ b/src/type_checker.py @@ -0,0 +1,455 @@ +import src.cmp.nbpackage +import src.cmp.visitor as visitor + +from src.ast_nodes import Node, ProgramNode, ExpressionNode +from src.ast_nodes import ClassDeclarationNode, FuncDeclarationNode, AttrDeclarationNode +from src.ast_nodes import VarDeclarationNode, AssignNode, CallNode +from src.ast_nodes import ( + AtomicNode, + BinaryNode, + ArithmeticOperation, + ComparisonOperation, + IfNode, + LetNode, + CaseNode, + CaseItemNode, + WhileNode, + BlockNode, + IsvoidNode, +) +from src.ast_nodes import ( + ConstantNumNode, + VariableNode, + InstantiateNode, + PlusNode, + MinusNode, + StarNode, + DivNode, + NegNode, + NotNode, + EqualNode, + BooleanNode, + StringNode, +) +from src.cool_visitor import FormatVisitor + +from src.cmp.semantic import SemanticError +from src.cmp.semantic import Attribute, Method, Type +from src.cmp.semantic import VoidType, ErrorType, IntType +from src.cmp.semantic import Context + +from src.cmp.semantic import Scope +from src.cmp.utils import find_least_type + +WRONG_SIGNATURE = 'Method "%s" already defined in "%s" with a different signature.' +SELF_IS_READONLY = 'Variable "self" is read-only.' +LOCAL_ALREADY_DEFINED = 'Variable "%s" is already defined in method "%s".' +INCOMPATIBLE_TYPES = 'Cannot convert "%s" into "%s".' +VARIABLE_NOT_DEFINED = 'Variable "%s" is not defined in "%s".' +INVALID_OPERATION = 'Operation is not defined between "%s" and "%s".' + + +class TypeChecker: + def __init__(self, context, errors=[]): + self.context = context + self.current_type = None + self.current_method = None + self.errors = errors + + @visitor.on("node") + def visit(self, node, scope): + pass + + @visitor.when(ProgramNode) + def visit(self, node, scope=None): + scope = Scope() + for declaration in node.declarations: + self.visit(declaration, scope.create_child()) + return scope + + @visitor.when(ClassDeclarationNode) + def visit(self, node, scope): + self.current_type = self.context.get_type(node.id) + scope.define_variable("self", self.current_type) + + for attr in self.current_type.attributes: + scope.define_variable(attr.name, attr.type) + + for feature in node.features: + self.visit(feature, scope) + + @visitor.when(AttrDeclarationNode) + def visit(self, node, scope): + try: + typex = self.context.get_type(node.type) + + except SemanticError as e: + self.errors.append(e) + return ErrorType() + + if typex.name == "SELF_TYPE": + typex = self.current_type + + if node.init_exp != None: + init_expr_type = self.visit(node.init_exp, scope) + if not init_expr_type.conforms_to(typex): + self.errors.append(INCOMPATIBLE_TYPES % (init_expr_type, typex)) + + return typex + + @visitor.when(FuncDeclarationNode) + def visit(self, node, scope): + self.current_method = self.current_type.get_method(node.id) + method_return_type = self.current_method.return_type + if method_return_type.name == "SELF_TYPE": + method_return_type = self.current_type + + child_scope = scope.create_child() + # ------------parameters most have differente names------------ + param_names = self.current_method.param_names + param_types = self.current_method.param_types + param_used = {} + + for i, param_name in enumerate(param_names): + try: + param_used[param_name] + self.errors.append( + f"More tan one param in method {node.id} has the name {param_name}" + ) + except: + param_used[param_name] = True + child_scope.define_variable(param_name, param_types[i]) + + # ------------------------------------------------------------- + + # for i in range(len(self.current_method.param_names)): + # child_scope.define_variable( + # self.current_method.param_names[i], self.current_method.param_types[i] + # ) + + body_type = self.visit(node.body, child_scope) + + if not body_type.conforms_to(method_return_type): + self.errors.append( + INCOMPATIBLE_TYPES % (body_type.name, method_return_type.name) + ) + + if self.current_type.parent is not None: + try: + parent_method = self.current_type.parent.get_method( + self.current_method.name + ) + if parent_method != self.current_method: + self.errors.append( + WRONG_SIGNATURE + % ( + parent_method.name, + f"an ancestor of {self.current_type.name}", + ) + ) + except SemanticError: + pass + + try: + return_type = self.context.get_type(node.type) + if return_type.name == "SELF_TYPE": + return self.current_type + + return return_type + + except SemanticError as e: + self.errors.append(e) + return ErrorType() + + @visitor.when(VarDeclarationNode) + def visit(self, node, scope): + if scope.is_local(node.id): + self.errors.append( + LOCAL_ALREADY_DEFINED % (node.id, self.current_method.name) + ) + elif node.id == "self": + self.errors.append(SELF_IS_READONLY) + try: + static_type = self.context.get_type(node.type) + except SemanticError as error: + self.errors.append(error.text) + static_type = ErrorType() + + expr_type = self.visit(node.expr, scope) + if not expr_type.conforms_to(static_type): + self.errors.append(INCOMPATIBLE_TYPES % (expr_type.name, static_type.name)) + + scope.define_variable(node.id, static_type) + return static_type + + @visitor.when(AssignNode) + def visit(self, node, scope): + if node.id == "self": + self.errors.append(SELF_IS_READONLY) + + var_type = None + if not scope.is_defined(node.id): + self.errors.append( + VARIABLE_NOT_DEFINED % (node.id, self.current_method.name) + ) + var_type = ErrorType() + else: + var_type = scope.find_variable(node.id).type + + expr_type = self.visit(node.expr, scope) + if not expr_type.conforms_to(var_type): + self.errors.append(INCOMPATIBLE_TYPES % (expr_type.name, var_type.name)) + + return var_type + + @visitor.when(CallNode) + def visit(self, node, scope): + auto_type = self.context.get_type("AUTO_TYPE") + typex = None + if node.obj is not None: + typex = self.visit(node.obj, scope) + if typex == auto_type: + return auto_type + + else: + typex = self.current_type + + method = None + try: + if node.at_type is not None: + node_at_type = self.context.get_type(node.at_type) + method = node_at_type.get_method(node.id) + if not typex.conforms_to(node_at_type): + self.errors.append( + f"The static type to the left of @ ({typex.name}) must conform to the type specified to the right of @ ({node_at_type.name}) " + ) + return ErrorType() + else: + method = typex.get_method(node.id) + except SemanticError as error: + self.errors.append(error.text) + return ErrorType() + + if len(method.param_names) != len(node.args): + self.errors.append( + f"There is no definition of {method.name} that takes {len(node.args)} arguments " + ) + + for arg, ptype in zip(node.args, method.param_types): + arg_type = self.visit(arg, scope) + if not arg_type.conforms_to(ptype): + self.errors.append(INCOMPATIBLE_TYPES % (arg_type.name, ptype.name)) + + if method.return_type == self.context.get_type("SELF_TYPE"): + return typex + + return method.return_type + + @visitor.when(IfNode) + def visit(self, node, scope): + predicate_type = self.visit(node.if_expr, scope) + + if predicate_type.name != "Bool" and predicate_type.name != "AUTO_TYPE": + self.errors.append( + f"Expression after 'if' must be bool, current is {predicate_type.name}" + ) + return ErrorType() + + then_type = self.visit(node.then_expr, scope) + else_type = self.visit(node.else_expr, scope) + + least_type = find_least_type(then_type, else_type, self.context) + return least_type + + @visitor.when(WhileNode) + def visit(self, node, scope): + condition_type = self.visit(node.condition, scope) + bool_type = self.context.get_type("Bool") + + if condition_type != bool_type and condition_type.name != "AUTO_TYPE": + self.errors.append( + f"Expression after 'while' must be bool, current is {condition_type.name}" + ) + return ErrorType() + + return self.context.get_type("Object") + + @visitor.when(BlockNode) + def visit(self, node, scope): + typex = None + for expr in node.expression_list: + typex = self.visit(expr, scope) + + return typex + + @visitor.when(LetNode) + def visit(self, node, scope): + + child_scope = scope.create_child() + + for var_dec in node.identifiers: + self.visit(var_dec, child_scope) + + return self.visit(node.body, child_scope) + + @visitor.when(VarDeclarationNode) + def visit(self, node, scope): + + static_type = None + try: + static_type = self.context.get_type(node.type) + if static_type.name == "SELF_TYPE": + static_type = self.current_type + scope.define_variable(node.id, static_type) + + except SemanticError as e: + self.errors.append(e) + return ErrorType() + + if node.expr != None: + typex = self.visit(node.expr, scope) + if not typex.conforms_to(static_type): + self.errors.append(INCOMPATIBLE_TYPES % (typex, static_type)) + + return static_type + + @visitor.when(CaseNode) + def visit(self, node, scope): + self.visit(node.expr, scope) + + current_case_type = None + for item in node.case_items: + child_scope = scope.create_child() + case_item_type = self.visit(item, child_scope) + current_case_type = find_least_type( + current_case_type, case_item_type, self.context + ) + + return current_case_type + + @visitor.when(CaseItemNode) + def visit(self, node, scope): + try: + static_type = self.context.get_type(node.type) + scope.define_variable(node.id, static_type) + except SemanticError as e: + self.errors.append(e) + return ErrorType() + + typex = self.visit(node.expr, scope) + + return typex + + @visitor.when(InstantiateNode) # NewNode + def visit(self, node, scope): + try: + typex = self.context.get_type(node.lex) + if typex.name == "SELF_TYPE": + return self.current_type + + return typex + except SemanticError as error: + self.errors.append(error.text) + return ErrorType() + + @visitor.when(IsvoidNode) + def visit(self, node, scope): + self.visit(node.expr, scope) + return self.context.get_type("Bool") + + @visitor.when(ArithmeticOperation) + def visit(self, node, scope): + int_type = self.context.get_type("Int") + left_type = self.visit(node.left, scope) + right_type = self.visit(node.right, scope) + + if (left_type != int_type and left_type.name != "AUTO_TYPE") or ( + right_type != int_type and right_type.name != "AUTO_TYPE" + ): + self.errors.append(INVALID_OPERATION % (left_type.name, right_type.name)) + + return int_type + + @visitor.when(ComparisonOperation) + def visit(self, node, scope): + int_type = self.context.get_type("Int") + left_type = self.visit(node.left, scope) + right_type = self.visit(node.right, scope) + + if (left_type != int_type and left_type.name != "AUTO_TYPE") or ( + right_type != int_type and right_type.name != "AUTO_TYPE" + ): + self.errors.append(INVALID_OPERATION % (left_type.name, right_type.name)) + + return self.context.get_type("Bool") + + @visitor.when(EqualNode) + def visit(self, node, scope): + int_type = self.context.get_type("Int") + string_type = self.context.get_type("String") + bool_type = self.context.get_type("Bool") + built_in_types = [int_type, string_type, bool_type] + + left_type = self.visit(node.left, scope) + right_type = self.visit(node.right, scope) + + if left_type in built_in_types or right_type in built_in_types: + if ( + left_type != right_type + and left_type.name != "AUTO_TYPE" + and right_type.name != "AUTO_TYPE" + ): + self.errors.append( + f"One of the expressions of '=' operator is of type Int, String or Bool, the other must have the same static type. Left type: {left_type.name}.Right type: {right_type.name}" + ) + + return self.context.get_type("Bool") + + @visitor.when(NotNode) + def visit(self, node, scope): + bool_type = self.context.get_type("Bool") + typex = self.visit(node.expr, scope) + + if typex != bool_type and not typex.name == "AUTO_TYPE": + self.errors.append( + f"Expression after 'not' must be Bool, current is {typex.name}" + ) + return ErrorType() + + return bool_type + + @visitor.when(NegNode) + def visit(self, node, scope): + int_type = self.context.get_type("Int") + typex = self.visit(node.expr, scope) + + if typex != int_type and not typex.name == "AUTO_TYPE": + self.errors.append( + f"Expression after '~' must be Int, current is {typex.name}" + ) + return ErrorType() + + return int_type + + @visitor.when(ConstantNumNode) + def visit(self, node, scope): + return self.context.get_type("Int") + + @visitor.when(VariableNode) + def visit(self, node, scope): + var = scope.find_variable(node.lex) + if var is None: + self.errors.append( + VARIABLE_NOT_DEFINED % (node.lex, self.current_method.name) + ) + return ErrorType() + return var.type + + @visitor.when(StringNode) + def visit(self, node, scope): + return self.context.get_type("String") + + @visitor.when(BooleanNode) + def visit(self, node, scope): + return self.context.get_type("Bool") + diff --git a/src/type_collector.py b/src/type_collector.py new file mode 100644 index 000000000..cdfdbe273 --- /dev/null +++ b/src/type_collector.py @@ -0,0 +1,54 @@ +from src.cmp.semantic import SemanticError +from src.cmp.semantic import Attribute, Method, Type +from src.cmp.semantic import ( + VoidType, + IntType, + ErrorType, + StringType, + BoolType, + AutoType, + ObjectType, + SelfType, + IOType, +) +from src.cmp.semantic import Context +from src.ast_nodes import ProgramNode, ClassDeclarationNode +import src.cmp.visitor as visitor + + +class TypeCollector(object): + def __init__(self, errors=[]): + self.context = Context() + self.errors = errors + + @visitor.on("node") + def visit(self, node): + pass + + @visitor.when(ProgramNode) + def visit(self, node): + self.context.types["Object"] = ObjectType() + self.context.types["Int"] = IntType() + self.context.types["String"] = StringType() + self.context.types["Bool"] = BoolType() + self.context.types["AUTO_TYPE"] = AutoType() + self.context.types["SELF_TYPE"] = SelfType() + # Despues de entregar!!!!! + self.context.types["IO"] = IOType() + # ------------------- + + object_type = self.context.get_type("Object") + for typex in self.context.types.values(): + if typex == object_type: + continue + typex.set_parent(object_type) + + for declaration in node.declarations: + self.visit(declaration) + + @visitor.when(ClassDeclarationNode) + def visit(self, node): + try: + self.context.create_type(node.id) + except SemanticError as error: + self.errors.append(error.text) From 096a20e96dadd39471b1050e109196e34dbdcaa3 Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Sat, 12 Feb 2022 16:28:43 -0500 Subject: [PATCH 030/162] feat: add context to ast. Type collector returns new ast Implement CopyVisitor to create a copy of an ast. --- src/ast_nodes.py | 6 +- src/cmp/semantic.py | 10 ++- src/cool_visitor.py | 194 ++++++++++++++++++++++++++++++++++++++++++ src/type_collector.py | 16 +++- 4 files changed, 218 insertions(+), 8 deletions(-) diff --git a/src/ast_nodes.py b/src/ast_nodes.py index d8dfa6aaf..3dc72753e 100644 --- a/src/ast_nodes.py +++ b/src/ast_nodes.py @@ -1,10 +1,14 @@ +from src.cmp.semantic import Context + + class Node: pass class ProgramNode(Node): - def __init__(self, declarations): + def __init__(self, declarations, context=None): self.declarations = declarations + self.context = context class ExpressionNode(Node): diff --git a/src/cmp/semantic.py b/src/cmp/semantic.py index 0cd3cfbb7..b4f6424c0 100644 --- a/src/cmp/semantic.py +++ b/src/cmp/semantic.py @@ -224,15 +224,11 @@ def __init__(self): Type.__init__(self, "SELF_TYPE") -# Despues de entregar!!!! class IOType(Type): def __init__(self): Type.__init__(self, "IO") -# --------------------------- - - class Context: def __init__(self): self.types = {} @@ -259,6 +255,12 @@ def __str__(self): def __repr__(self): return str(self) + def __copy__(self): + newContext = Context() + for key, value in self.types.items(): + newContext.types[key] = value + return newContext + class VariableInfo: def __init__(self, name, vtype): diff --git a/src/cool_visitor.py b/src/cool_visitor.py index 8dab5b918..d49220b35 100644 --- a/src/cool_visitor.py +++ b/src/cool_visitor.py @@ -17,6 +17,23 @@ BinaryNode, AtomicNode, UnaryNode, + ArithmeticOperation, + ComparisonOperation, + ConstantNumNode, + VariableNode, + StringNode, + BooleanNode, + InstantiateNode, + NotNode, + IsvoidNode, + NegNode, + PlusNode, + MinusNode, + StarNode, + DivNode, + LessNode, + LessEqualNode, + EqualNode, ) @@ -337,3 +354,180 @@ def visit(self, node, tabs=0): self.visit(node.expr, tabs + 1) return + +class CopyVisitor(object): + @visitor.on("node") + def visit(self, node): + pass + + @visitor.when(ProgramNode) + def visit(self, node): + declarations = [] + for child in node.declarations: + declarations.append(self.visit(child)) + context = node.context.copy() + return ProgramNode(declarations, context) + + @visitor.when(ClassDeclarationNode) + def visit(self, node): + features = [] + for feat in node.features: + features.append(self.visit(feat)) + return ClassDeclarationNode(node.id, features, node.parent) + + @visitor.when(AttrDeclarationNode) + def visit(self, node): + init_exp = None + if not node.init_exp is None: + init_exp = self.visit(node.init_exp) + + return AttrDeclarationNode(node.id, node.type, init_exp) + + @visitor.when(VarDeclarationNode) + def visit(self, node): + expr = None + if not node.expr is None: + expr = self.visit(node.expr) + + return VarDeclarationNode(node.id, node.type, expr) + + @visitor.when(AssignNode) + def visit(self, node): + expr = self.visit(node.expr) + return AssignNode(node.id, expr) + + @visitor.when(FuncDeclarationNode) + def visit(self, node): + params = [p for p in node.params] + body = self.visit(node.body) + return FuncDeclarationNode(node.id, params, node.type, body) + + @visitor.when(CallNode) + def visit(self, node): + obj = None + if not node.obj is None: + obj = self.visit(node.obj) + + args = [] + for arg in node.args: + args.append(self.visit(arg)) + + return CallNode(node.idx, args, obj, node.at_type) + + @visitor.when(BlockNode) + def visit(self, node): + expression_list = [] + for child in node.expression_list: + expression_list.append(self.visit(child)) + return BlockNode(expression_list) + + @visitor.when(IfNode) + def visit(self, node): + if_expr = self.visit(node.if_expr) + then_expr = self.visit(node.then_expr) + else_expr = self.visit(node.else_expr) + return IfNode(if_expr, then_expr, else_expr) + + @visitor.when(WhileNode) + def visit(self, node): + condition = self.visit(node.condition) + body = self.visit(node.body) + return WhileNode(condition, body) + + @visitor.when(LetNode) + def visit(self, node): + identifiers = [] + for child in node.identifiers: + identifiers.append(self.visit(child)) + body = self.visit(node.body) + return LetNode(identifiers, body) + + @visitor.when(CaseNode) + def visit(self, node): + expr = self.visit(node.expr) + case_items = [] + for child in node.case_items: + case_items.append(self.visit(child)) + return CaseNode(expr, case_items) + + @visitor.when(CaseItemNode) + def visit(self, node): + expr = self.visit(node.expr) + return CaseItemNode(node.idx, node.type, expr) + + @visitor.when(PlusNode) + def visit(self, node): + left = self.visit(node.left) + right = self.visit(node.right) + return PlusNode(left, right) + + @visitor.when(MinusNode) + def visit(self, node): + left = self.visit(node.left) + right = self.visit(node.right) + return MinusNode(left, right) + + @visitor.when(StarNode) + def visit(self, node): + left = self.visit(node.left) + right = self.visit(node.right) + return StarNode(left, right) + + @visitor.when(DivNode) + def visit(self, node): + left = self.visit(node.left) + right = self.visit(node.right) + return DivNode(left, right) + + @visitor.when(LessNode) + def visit(self, node): + left = self.visit(node.left) + right = self.visit(node.right) + return LessNode(left, right) + + @visitor.when(LessEqualNode) + def visit(self, node): + left = self.visit(node.left) + right = self.visit(node.right) + return LessEqualNode(left, right) + + @visitor.when(EqualNode) + def visit(self, node): + left = self.visit(node.left) + right = self.visit(node.right) + return EqualNode(left, right) + + @visitor.when(ConstantNumNode) + def visit(self, node): + return ConstantNumNode(node.lex) + + @visitor.when(VariableNode) + def visit(self, node): + return VariableNode(node.lex) + + @visitor.when(StringNode) + def visit(self, node): + return StringNode(node.lex) + + @visitor.when(BooleanNode) + def visit(self, node): + return BooleanNode(node.lex) + + @visitor.when(InstantiateNode) + def visit(self, node): + return InstantiateNode(node.lex) + + @visitor.when(NotNode) + def visit(self, node): + expr = self.visit(node.expr) + return NotNode(expr) + + @visitor.when(IsvoidNode) + def visit(self, node): + expr = self.visit(node.expr) + return IsvoidNode(expr) + + @visitor.when(NegNode) + def visit(self, node): + expr = self.visit(node.expr) + return NegNode(expr) diff --git a/src/type_collector.py b/src/type_collector.py index cdfdbe273..d78131076 100644 --- a/src/type_collector.py +++ b/src/type_collector.py @@ -14,11 +14,12 @@ from src.cmp.semantic import Context from src.ast_nodes import ProgramNode, ClassDeclarationNode import src.cmp.visitor as visitor +from cool_visitor import CopyVisitor class TypeCollector(object): def __init__(self, errors=[]): - self.context = Context() + self.context = None self.errors = errors @visitor.on("node") @@ -27,15 +28,15 @@ def visit(self, node): @visitor.when(ProgramNode) def visit(self, node): + self.context = Context() + # Es necesario crear estos tipos especificos? self.context.types["Object"] = ObjectType() self.context.types["Int"] = IntType() self.context.types["String"] = StringType() self.context.types["Bool"] = BoolType() self.context.types["AUTO_TYPE"] = AutoType() self.context.types["SELF_TYPE"] = SelfType() - # Despues de entregar!!!!! self.context.types["IO"] = IOType() - # ------------------- object_type = self.context.get_type("Object") for typex in self.context.types.values(): @@ -46,6 +47,15 @@ def visit(self, node): for declaration in node.declarations: self.visit(declaration) + copy_visitor = CopyVisitor() + newAst = copy_visitor.visit(node) + + newAst.context = self.context.copy() + self.context = None + # self.errors tambien deberia volver a su estado inicial + # devolver (newAst,errors) ??? + return newAst + @visitor.when(ClassDeclarationNode) def visit(self, node): try: From 206b6d35e4f031708a1d577eafa83adb1272799c Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Sun, 13 Feb 2022 17:19:48 -0500 Subject: [PATCH 031/162] feat: type_builder returns new ast with context --- src/type_builder.py | 21 +++++++++++++++------ src/type_checker.py | 11 ++++++++--- src/type_collector.py | 4 ++-- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/type_builder.py b/src/type_builder.py index ed0f0119c..38403d7bb 100644 --- a/src/type_builder.py +++ b/src/type_builder.py @@ -11,11 +11,12 @@ import src.cmp.visitor as visitor from src.tset import Tset from collections import deque +from cool_visitor import CopyVisitor class TypeBuilder: - def __init__(self, context, errors=[]): - self.context = context + def __init__(self, errors=[]): + self.context = None self.current_type = None self.errors = errors @@ -25,7 +26,8 @@ def visit(self, node): @visitor.when(ProgramNode) def visit(self, node): - # Despues de entregar!!!!!! + self.context = node.context.copy() + io_type = self.context.get_type("IO") self_type = self.context.get_type("SELF_TYPE") int_type = self.context.get_type("Int") @@ -53,7 +55,7 @@ def visit(self, node): method = io_type.define_method("in_int", [], [], int_type) method.tset = Tset(parent_tset) - # -------String + # String parent_tset = Tset() parent_tset.locals["concat"] = {"String"} parent_tset.locals["substr"] = {"String"} @@ -88,8 +90,6 @@ def visit(self, node): method = object_type.define_method("copy", [], [], self_type) method.tset = Tset(parent_tset) - # -------------------- - # ------checking for in order definitions and cyclic heritage parent_child_dict = {} queue = deque() @@ -150,6 +150,15 @@ def visit(self, node): # for declaration in node.declarations: # self.visit(declaration) + copy_visitor = CopyVisitor() + newAst = copy_visitor.visit(node) + newAst.context = self.context.copy() + + self.context = None + self.current_type = None + + return newAst + @visitor.when(ClassDeclarationNode) def visit(self, node): # print(f"------------visiting class {node.id}------------") diff --git a/src/type_checker.py b/src/type_checker.py index d8b9cf83e..5eec395a7 100644 --- a/src/type_checker.py +++ b/src/type_checker.py @@ -50,8 +50,8 @@ class TypeChecker: - def __init__(self, context, errors=[]): - self.context = context + def __init__(self, errors=[]): + self.context = None self.current_type = None self.current_method = None self.errors = errors @@ -63,8 +63,14 @@ def visit(self, node, scope): @visitor.when(ProgramNode) def visit(self, node, scope=None): scope = Scope() + self.context = node.context.copy() for declaration in node.declarations: self.visit(declaration, scope.create_child()) + + self.context = None + self.current_type = None + self.current_method = None + return scope @visitor.when(ClassDeclarationNode) @@ -452,4 +458,3 @@ def visit(self, node, scope): @visitor.when(BooleanNode) def visit(self, node, scope): return self.context.get_type("Bool") - diff --git a/src/type_collector.py b/src/type_collector.py index d78131076..c693260a8 100644 --- a/src/type_collector.py +++ b/src/type_collector.py @@ -29,7 +29,7 @@ def visit(self, node): @visitor.when(ProgramNode) def visit(self, node): self.context = Context() - # Es necesario crear estos tipos especificos? + # TODO: Es necesario crear estos tipos especificos? self.context.types["Object"] = ObjectType() self.context.types["Int"] = IntType() self.context.types["String"] = StringType() @@ -52,7 +52,7 @@ def visit(self, node): newAst.context = self.context.copy() self.context = None - # self.errors tambien deberia volver a su estado inicial + # TODO: self.errors tambien deberia volver a su estado inicial # devolver (newAst,errors) ??? return newAst From ed72f8fa4e43deafafac7baf2f821d86f9b13865 Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Tue, 15 Feb 2022 20:12:42 -0500 Subject: [PATCH 032/162] feat: add pipeline and error classes. Remove src module --- src/__init__.py | 0 src/ast_nodes.py | 2 +- src/cmp/ast.py | 7 +- src/cmp/cil.py | 3 +- src/cmp/evaluation.py | 4 +- src/cmp/utils.py | 2 +- src/cool_grammar.py | 4 +- src/cool_tokenizer.py | 3 +- src/cool_visitor.py | 4 +- src/coolc.sh | 5 +- src/errors.py | 156 +++++++++++++++++++++++++++++++++++- src/lexical_analizer.py | 5 +- src/main.py | 121 ++++++++++------------------ src/methods.py | 148 ++++++++++++++++++++++++++++++++++ src/parser_automatons.py | 8 +- src/shift_reduce_parsers.py | 8 +- src/tokens_rules.py | 4 +- src/tset.py | 72 +++++++++++++++++ src/type_builder.py | 14 ++-- src/type_checker.py | 32 ++++---- src/type_collector.py | 12 +-- 21 files changed, 476 insertions(+), 138 deletions(-) create mode 100644 src/__init__.py create mode 100644 src/methods.py create mode 100644 src/tset.py diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/ast_nodes.py b/src/ast_nodes.py index 3dc72753e..869599488 100644 --- a/src/ast_nodes.py +++ b/src/ast_nodes.py @@ -1,4 +1,4 @@ -from src.cmp.semantic import Context +from cmp.semantic import Context class Node: diff --git a/src/cmp/ast.py b/src/cmp/ast.py index c0f73e1b2..9f2d775f5 100644 --- a/src/cmp/ast.py +++ b/src/cmp/ast.py @@ -1,4 +1,4 @@ -import src.cmp.visitor as visitor +import cmp.visitor as visitor class Node: @@ -40,7 +40,9 @@ def operate(lvalue, rvalue): def get_printer( - AtomicNode=AtomicNode, UnaryNode=UnaryNode, BinaryNode=BinaryNode, + AtomicNode=AtomicNode, + UnaryNode=UnaryNode, + BinaryNode=BinaryNode, ): class PrintVisitor(object): @visitor.on("node") @@ -66,4 +68,3 @@ def visit(self, node, tabs=0): printer = PrintVisitor() return lambda ast: printer.visit(ast) - diff --git a/src/cmp/cil.py b/src/cmp/cil.py index 5864ccdd0..21cbaedaa 100644 --- a/src/cmp/cil.py +++ b/src/cmp/cil.py @@ -1,4 +1,4 @@ -import src.cmp.visitor as visitor +import cmp.visitor as visitor class Node: @@ -264,4 +264,3 @@ def visit(self, node): printer = PrintVisitor() return lambda ast: printer.visit(ast) - diff --git a/src/cmp/evaluation.py b/src/cmp/evaluation.py index 830703efe..f54d09279 100644 --- a/src/cmp/evaluation.py +++ b/src/cmp/evaluation.py @@ -1,5 +1,5 @@ -from src.cmp.pycompiler import EOF -from src.shift_reduce_parsers import ShiftReduceParser +from cmp.pycompiler import EOF +from shift_reduce_parsers import ShiftReduceParser def evaluate_reverse_parse(right_parse, operations, tokens): diff --git a/src/cmp/utils.py b/src/cmp/utils.py index 5bcf97b19..cad362fdb 100644 --- a/src/cmp/utils.py +++ b/src/cmp/utils.py @@ -1,4 +1,4 @@ -from src.cmp.pycompiler import Production, Sentence, Symbol, EOF, Epsilon +from cmp.pycompiler import Production, Sentence, Symbol, EOF, Epsilon class ContainerSet: diff --git a/src/cool_grammar.py b/src/cool_grammar.py index fc3035214..a7c4c6e46 100644 --- a/src/cool_grammar.py +++ b/src/cool_grammar.py @@ -1,5 +1,5 @@ -from src.cmp.pycompiler import Grammar -from src.ast_nodes import ( +from cmp.pycompiler import Grammar +from ast_nodes import ( ProgramNode, ClassDeclarationNode, FuncDeclarationNode, diff --git a/src/cool_tokenizer.py b/src/cool_tokenizer.py index 90178fc09..7300d4eda 100644 --- a/src/cool_tokenizer.py +++ b/src/cool_tokenizer.py @@ -1,4 +1,4 @@ -from src.cmp.utils import Token, tokenizer +from cmp.utils import Token, tokenizer def tokenize_cool_text(G, text, idx, num, print_tokens=False): @@ -40,4 +40,3 @@ def pprint_tokens(tokens): # if __name__ == "__main__": # pprint_tokens(tokens) - diff --git a/src/cool_visitor.py b/src/cool_visitor.py index d49220b35..60fb2f78a 100644 --- a/src/cool_visitor.py +++ b/src/cool_visitor.py @@ -1,5 +1,5 @@ -import src.cmp.visitor as visitor -from src.ast_nodes import ( +import cmp.visitor as visitor +from ast_nodes import ( ProgramNode, ClassDeclarationNode, FuncDeclarationNode, diff --git a/src/coolc.sh b/src/coolc.sh index 57da22e35..d3cf16bd2 100755 --- a/src/coolc.sh +++ b/src/coolc.sh @@ -4,8 +4,9 @@ INPUT_FILE=$1 OUTPUT_FILE=${INPUT_FILE:0: -2}mips # Si su compilador no lo hace ya, aquí puede imprimir la información de contacto -echo "LINEA_CON_NOMBRE_Y_VERSION_DEL_COMPILADOR" # TODO: Recuerde cambiar estas -echo "Copyright (c) 2022: Amalia_Ibarra, Sandra_Martos, Gabriela_Martinez" # TODO: líneas a los valores correctos +echo "EL_COMPI 1.0" +echo "Copyright (c) 2022: Amalia_Ibarra, Sandra_Martos, Gabriela_Martinez" # Llamar al compilador echo "Compiling $INPUT_FILE into $OUTPUT_FILE" +python -m main $@ \ No newline at end of file diff --git a/src/errors.py b/src/errors.py index 14c9922a5..6411c8a1b 100644 --- a/src/errors.py +++ b/src/errors.py @@ -1,3 +1,156 @@ +class CoolCompilerError(object): + """ + Errors reported by the compiler + """ + + def __init__(self, line, column, type, msg) -> None: + self.line = line + self.column = column + self.type = type + self.msg = msg + + def __str__(self) -> str: + return f"({self.line}, {self.column}) - {self.type}: {self.msg}" + + +# Compiler errors + + +class CompilerError(CoolCompilerError): + """ + Error reported when an anomaly in the compiler's input is detected. + For example, if the input file doesn't exist. + """ + + def __init__(self, msg) -> None: + CoolCompilerError.__init__(self, 0, 0, "CompilerError", msg) + + +class InvalidInputFileError(CompilerError): + """ + Reported when input file is invalid. + """ + + def __init__(self, path: str) -> None: + CompilerError.__init__(self, f"File `{path}` is not a valid file.") + + +# Lexicographic errors + + +class LexicographicError(CoolCompilerError): + """ + Error reported by lexer + """ + + def __init__(self, line: int, column: int, msg: str) -> None: + CoolCompilerError.__init__(self, line, column, "LexicographicError", msg) + + +class UnexpectedCharError(LexicographicError): + """ + Reported the lexer encounters an unexpected character. + """ + + def __init__(self, line: int, column: int, char: str) -> None: + LexicographicError.__init__(self, line, column, f"Unexpected `{char}`.") + + +# Syntactic errors + + +class SyntacticError(CoolCompilerError): + """ + Error reported by parser + """ + + def __init__(self, line: int, column: int, msg: str) -> None: + CoolCompilerError.__init__(self, line, column, "SyntacticError", msg) + + +class UnexpectedTokenError(SyntacticError): + """ + Reported the parser encounters an unexpected Token. + """ + + def __init__(self, line: int, column: int, token: str) -> None: + SyntacticError.__init__( + self, + line, + column, + f"Unexpected token `{token}`.", + ) + + +class UnexpectedEOFError(SyntacticError): + """ + Reported the parser encounters end of file unexpectedly. + """ + + def __init__(self) -> None: + SyntacticError.__init__(self, 0, 0, "Unexpected EOF.") + + +# Semantic errors + + +class NameError(CoolCompilerError): + """ + Error reported when an identifier is referenced in a scope where it is not visible. + """ + + def __init__(self, line: int, column: int, msg: str) -> None: + CoolCompilerError.__init__(self, line, column, "NameError", msg) + + +class TypeError(CoolCompilerError): + """ + Error reported when a problem with types is detected. Includes: + - type incompatibility between `rvalue` and `lvalue`, + - undefined operation between objects of certain types + - referenced type is undefined + """ + + def __init__(self, line: int, column: int, msg: str) -> None: + CoolCompilerError.__init__(self, line, column, "TypeError", msg) + + +class AttributeError(CoolCompilerError): + """ + Error reported when an attribute or method is referenced but undefined. + """ + + def __init__(self, line: int, column: int, msg: str) -> None: + CoolCompilerError.__init__(self, line, column, "AttributeError", msg) + + +class SemanticError(CoolCompilerError): + """ + Any kind of semantic error + """ + + def __init__(self, line, column, msg) -> None: + CoolCompilerError.__init__(self, line, column, "SemanticError", msg) + + +class IncompatibleTypesError(SemanticError): + def __init__(self, line, column, type_a, type_b) -> None: + SemanticError.__init__( + self, line, column, f"Cannot convert {type_a} into {type_b}." + ) + + +class WrongSignatureError(SemanticError): + def __init__(self, line, column, method) -> None: + SemanticError.__init__( + self, + line, + column, + f"Method {method} already defined with a different signature.", + ) + + +# ---------------------------------------------- class Error(Exception): "Base class for exceptions" pass @@ -8,7 +161,8 @@ class tokenizer_error(Error): def __init__(self, text, line): Error.__init__( - self, f"Got {text} while analizing line {line}", + self, + f"Got {text} while analizing line {line}", ) diff --git a/src/lexical_analizer.py b/src/lexical_analizer.py index a0e3a9a1c..e76f75d6d 100644 --- a/src/lexical_analizer.py +++ b/src/lexical_analizer.py @@ -1,6 +1,6 @@ import ply.lex as lex -import src.tokens_rules as tokens_rules -from src.cmp.utils import Token +import tokens_rules as tokens_rules +from cmp.utils import Token def pprint_tokens(tokens): @@ -54,4 +54,3 @@ def tokenize_cool_text(grammar, idx, string, num, data, printing=False): if printing: pprint_tokens(tokens) return tokens - diff --git a/src/main.py b/src/main.py index 7af8567f9..e6f005f7d 100644 --- a/src/main.py +++ b/src/main.py @@ -1,99 +1,64 @@ -from src.lexical_analizer import tokenize_cool_text -from src.cool_grammar import define_cool_grammar -from src.cool_visitor import FormatVisitorST +from lexical_analizer import tokenize_cool_text +from cool_grammar import define_cool_grammar +from cool_visitor import FormatVisitorST -from src.type_collector import TypeCollector -from src.type_builder import TypeBuilder -from src.type_checker import TypeChecker -from src.tset_builder import TSetBuilder -from src.tsets_reducer import TSetReducer -from src.tset_merger import TSetMerger +from type_collector import TypeCollector +from type_builder import TypeBuilder +from type_checker import TypeChecker -from src.shift_reduce_parsers import LR1Parser, DerivationTree -from src.errors import parsing_table_error, Error +from shift_reduce_parsers import LR1Parser, DerivationTree +from errors import parsing_table_error, Error -from src.cmp.evaluation import evaluate_reverse_parse +from cmp.evaluation import evaluate_reverse_parse +from pathlib import Path +from errors import InvalidInputFileError +import typer -from src.ui import print_array, print_grammar, print_tset +def report_and_exit(errors): + if len(errors) == 0: + raise typer.Exit(code=0) -""" # Cool Intrepreter """ + for error in errors: + typer.echo(error) + raise typer.Exit(code=1) -def run_pipeline(text): - main_error1 = ["A class Main with a method main most be provided"] - main_error2 = ['"main" method in class Main does not receive any parameters'] - # define grammar - grammar, idx, string, num = define_cool_grammar() - - # try: - tokens = tokenize_cool_text(grammar, idx, string, num, text) - parser = LR1Parser(grammar) - parse, operations = parser([t.token_type for t in tokens]) - - # print("\n".join(repr(x) for x in parse)) - # print(operations) - - ast = evaluate_reverse_parse(parse, operations, tokens) - formatter = FormatVisitorST() - tree = formatter.visit(ast) - - print("Initial AST") - print_array(tree) +def pipeline(input_file: Path, output_file: Path = None): errors = [] - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) + if not input_file.is_file: + errors.append(InvalidInputFileError(str(input_file))) - checker = TypeChecker(context, errors) - checker.visit(ast, None) + if len(errors) > 0: + report_and_exit(errors) - if errors != [] and errors != main_error1 and errors != main_error2: - print("---------ERRORS----------") - print_array(errors) - else: - if errors == main_error1 or errors == main_error2: - errors = [] + text = input_file.read_text() - tset_builder = TSetBuilder(context, errors) - tset = tset_builder.visit(ast, None) + # main_error1 = ["A class Main with a method main most be provided"] + # main_error2 = ['"main" method in class Main does not receive any parameters'] - tset_reducer = TSetReducer(context, errors) - reduced_set = tset_reducer.visit(ast, tset) - - tset_merger = TSetMerger(context, errors) - tset_merger.visit(ast, reduced_set) - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) + # define grammar + grammar, idx, string, num = define_cool_grammar() - if errors != [] and errors != main_error1 and errors != main_error2: - print("----------ERRORS-----------") - print_array(errors) + tokens = tokenize_cool_text(grammar, idx, string, num, text) + parser = LR1Parser(grammar) + parse, operations = parser([t.token_type for t in tokens]) - print("Reduced Sets") - print(reduced_set) + ast = evaluate_reverse_parse(parse, operations, tokens) + # formatter = FormatVisitorST() + # tree = formatter.visit(ast) - tree = formatter.visit(ast) - print("Final Tree:") - print_array(tree) + visitors = [TypeCollector(errors), TypeBuilder(errors), TypeChecker(errors)] + for visitor in visitors: + ast = visitor.visit(ast) - # except Error as error: - # st.header("Sorry an error occur while tokenizing text:") - # st.write(str(error)) + if len(errors) > 0: + report_and_exit(errors) + if output is None: + output = input.with_suffix(".mips") +if __name__ == "__main__": + typer.run(pipeline) diff --git a/src/methods.py b/src/methods.py new file mode 100644 index 000000000..8723d7c20 --- /dev/null +++ b/src/methods.py @@ -0,0 +1,148 @@ +from cmp.pycompiler import ( + Symbol, + NonTerminal, + Terminal, + EOF, + Sentence, + SentenceList, + Epsilon, + Production, + Grammar, +) +from cmp.utils import ContainerSet +from errors import parsing_table_error, invalid_sentence_error +from cmp.automata import State + + +# Computes First(alpha), given First(Vt) and First(Vn) +# alpha in (Vt U Vn)* +def compute_local_first(firsts, alpha): + first_alpha = ContainerSet() + + try: + alpha_is_epsilon = alpha.IsEpsilon + except: + alpha_is_epsilon = False + + ################################################### + # alpha == epsilon ? First(alpha) = { epsilon } + ################################################### + if alpha_is_epsilon or len(alpha) == 0: + first_alpha.set_epsilon() + return first_alpha + ################################################### + + ################################################### + # alpha = X1 ... XN + # First(Xi) subconjunto First(alpha) + # epsilon pertenece a First(X1)...First(Xi) ? First(Xi+1) subconjunto de First(X) y First(alpha) + # epsilon pertenece a First(X1)...First(XN) ? epsilon pertence a First(X) y al First(alpha) + ################################################### + if alpha[0].IsTerminal: + first_alpha.add(alpha[0]) + return first_alpha + + # if alpha[0].IsNonTerminal: + # first_alpha.update(firsts[alpha[0]]) + + for item in alpha: + if firsts[item].contains_epsilon: + first_alpha.update(firsts[item]) + else: + first_alpha.update(firsts[item]) + break + + else: + first_alpha.set_epsilon() + + ################################################### + + # First(alpha) + return first_alpha + + +# Computes First(Vt) U First(Vn) U First(alpha) +# P: X -> alpha +def compute_firsts(G): + firsts = {} + change = True + + # init First(Vt) + for terminal in G.terminals: + firsts[terminal] = ContainerSet(terminal) + + # init First(Vn) + for nonterminal in G.nonTerminals: + firsts[nonterminal] = ContainerSet() + + while change: + change = False + + # P: X -> alpha + for production in G.Productions: + X = production.Left + alpha = production.Right + + # get current First(X) + first_X = firsts[X] + + # init First(alpha) + try: + first_alpha = firsts[alpha] + except: + first_alpha = firsts[alpha] = ContainerSet() + + # CurrentFirst(alpha)??? + local_first = compute_local_first(firsts, alpha) + + # update First(X) and First(alpha) from CurrentFirst(alpha) + change |= first_alpha.hard_update(local_first) + change |= first_X.hard_update(local_first) + + # First(Vt) + First(Vt) + First(RightSides) + return firsts + + +def compute_follows(G, firsts): + follows = {} + change = True + + # local_firsts = {} + + # init Follow(Vn) + for nonterminal in G.nonTerminals: + follows[nonterminal] = ContainerSet() + follows[G.startSymbol] = ContainerSet(G.EOF) + + while change: + change = False + + # P: X -> alpha + for production in G.Productions: + X = production.Left + alpha = production.Right + + follow_X = follows[X] + + ################################################### + # X -> zeta Y beta + # First(beta) - { epsilon } subset of Follow(Y) + # beta ->* epsilon or X -> zeta Y ? Follow(X) subset of Follow(Y) + ################################################### + + for i in range(0, len(alpha) - 1): + if alpha[i].IsNonTerminal: + beta = Sentence(*alpha[i + 1 :]) + firsts_beta = compute_local_first(firsts, beta) + change |= follows[alpha[i]].update(firsts_beta) + + if firsts_beta.contains_epsilon: + change |= follows[alpha[i]].update(follow_X) + + if not alpha.IsEpsilon and alpha[-1].IsNonTerminal: + change |= follows[alpha[-1]].update(follow_X) + + ################################################### + + # Follow(Vn) + return follows diff --git a/src/parser_automatons.py b/src/parser_automatons.py index 6fce5323d..437f4d16b 100644 --- a/src/parser_automatons.py +++ b/src/parser_automatons.py @@ -1,7 +1,7 @@ -from src.cmp.pycompiler import Item -from src.cmp.automata import State, lr0_formatter, multiline_formatter -from src.cmp.utils import ContainerSet -from src.methods import compute_firsts, compute_local_first, compute_follows +from cmp.pycompiler import Item +from cmp.automata import State, lr0_formatter, multiline_formatter +from cmp.utils import ContainerSet +from methods import compute_firsts, compute_local_first, compute_follows # LR0 automaton -> for SLR and LALR parsers def build_LR0_automaton(G): diff --git a/src/shift_reduce_parsers.py b/src/shift_reduce_parsers.py index 3501302b1..a873a4566 100644 --- a/src/shift_reduce_parsers.py +++ b/src/shift_reduce_parsers.py @@ -1,11 +1,11 @@ -from src.parser_automatons import ( +from parser_automatons import ( build_LR0_automaton, build_LR1_automaton, build_LALR_automaton, ) -from src.methods import compute_firsts, compute_local_first, compute_follows -from src.cmp.automata import State -from src.errors import shift_reduce_error, invalid_sentence_error +from methods import compute_firsts, compute_local_first, compute_follows +from cmp.automata import State +from errors import shift_reduce_error, invalid_sentence_error class ShiftReduceParser: diff --git a/src/tokens_rules.py b/src/tokens_rules.py index b00583675..e3af67637 100644 --- a/src/tokens_rules.py +++ b/src/tokens_rules.py @@ -1,7 +1,7 @@ # https://www.dabeaz.com/ply/ply.html # file for PLY rules -from src.errors import tokenizer_error +from errors import tokenizer_error # def find_column(input, lexpos): @@ -133,7 +133,7 @@ def t_comment1(t): def t_string(t): - r"\"" + r"\" " string_list = [] text = t.lexer.lexdata initial = t.lexer.lexpos diff --git a/src/tset.py b/src/tset.py new file mode 100644 index 000000000..4258080d4 --- /dev/null +++ b/src/tset.py @@ -0,0 +1,72 @@ +class Tset: + def __init__(self, parent=None): + self.locals = {} + self.parent = parent + self.children = {} + + def create_child(self, node): + child = Tset(self) + self.children[node] = child + return child + + def find_set(self, idx): + if idx in self.locals.keys(): + return self.locals + elif self.parent != None: + return self.parent.find_set(idx) + + return None + + def __str__(self): + output = "" + + for key, value in self.locals.items(): + output += "\t" + str(key) + ":" + str(value) + "\n" + for key, child in self.children.items(): + output += "\n" + try: + output += key.id + "--->" + except AttributeError: + output += "let or case --->" + output += "\n" + output += str(child) + return output + + def clone(self): + solve = Tset() + solve.parent = self.parent + for idx, typex in self.locals.items(): + solve.locals[idx] = typex.copy() + + for key, value in self.children.items(): + solve.children[key] = value.clone() + + return solve + + def compare(self, other): + if len(self.locals) != len(other.locals) or len(self.children) != len( + other.children + ): + return False + + for (idx, tset), (idx_other, tset_other) in zip( + self.locals.items(), other.locals.items() + ): + if idx != idx_other or tset != tset_other: + return False + for (key, value), (key_other, value_other) in zip( + self.children.items(), other.children.items() + ): + if key != key_other or not value.compare(value_other): + return False + return True + + def clean(self): + for typex in self.locals.values(): + if "InferenceError" in typex: + typex.remove("InferenceError") + if "!static_type_declared" in typex: + typex.remove("!static_type_declared") + for child in self.children.values(): + child.clean() + diff --git a/src/type_builder.py b/src/type_builder.py index 38403d7bb..4a6baca48 100644 --- a/src/type_builder.py +++ b/src/type_builder.py @@ -1,15 +1,15 @@ -from src.cmp.semantic import SemanticError -from src.cmp.semantic import Attribute, Method, Type -from src.cmp.semantic import VoidType, IntType, ErrorType, StringType, BoolType -from src.cmp.semantic import Context -from src.ast_nodes import ( +from cmp.semantic import SemanticError +from cmp.semantic import Attribute, Method, Type +from cmp.semantic import VoidType, IntType, ErrorType, StringType, BoolType +from cmp.semantic import Context +from ast_nodes import ( ProgramNode, ClassDeclarationNode, AttrDeclarationNode, FuncDeclarationNode, ) -import src.cmp.visitor as visitor -from src.tset import Tset +import cmp.visitor as visitor +from tset import Tset from collections import deque from cool_visitor import CopyVisitor diff --git a/src/type_checker.py b/src/type_checker.py index 5eec395a7..16c0159e4 100644 --- a/src/type_checker.py +++ b/src/type_checker.py @@ -1,10 +1,10 @@ -import src.cmp.nbpackage -import src.cmp.visitor as visitor +import cmp.nbpackage +import cmp.visitor as visitor -from src.ast_nodes import Node, ProgramNode, ExpressionNode -from src.ast_nodes import ClassDeclarationNode, FuncDeclarationNode, AttrDeclarationNode -from src.ast_nodes import VarDeclarationNode, AssignNode, CallNode -from src.ast_nodes import ( +from ast_nodes import Node, ProgramNode, ExpressionNode +from ast_nodes import ClassDeclarationNode, FuncDeclarationNode, AttrDeclarationNode +from ast_nodes import VarDeclarationNode, AssignNode, CallNode +from ast_nodes import ( AtomicNode, BinaryNode, ArithmeticOperation, @@ -17,7 +17,7 @@ BlockNode, IsvoidNode, ) -from src.ast_nodes import ( +from ast_nodes import ( ConstantNumNode, VariableNode, InstantiateNode, @@ -31,15 +31,15 @@ BooleanNode, StringNode, ) -from src.cool_visitor import FormatVisitor +from cool_visitor import FormatVisitor -from src.cmp.semantic import SemanticError -from src.cmp.semantic import Attribute, Method, Type -from src.cmp.semantic import VoidType, ErrorType, IntType -from src.cmp.semantic import Context +from cmp.semantic import SemanticError +from cmp.semantic import Attribute, Method, Type +from cmp.semantic import VoidType, ErrorType, IntType +from cmp.semantic import Context -from src.cmp.semantic import Scope -from src.cmp.utils import find_least_type +from cmp.semantic import Scope +from cmp.utils import find_least_type WRONG_SIGNATURE = 'Method "%s" already defined in "%s" with a different signature.' SELF_IS_READONLY = 'Variable "self" is read-only.' @@ -57,11 +57,11 @@ def __init__(self, errors=[]): self.errors = errors @visitor.on("node") - def visit(self, node, scope): + def visit(self, node, scope=None): pass @visitor.when(ProgramNode) - def visit(self, node, scope=None): + def visit(self, node): scope = Scope() self.context = node.context.copy() for declaration in node.declarations: diff --git a/src/type_collector.py b/src/type_collector.py index c693260a8..9649b6b9b 100644 --- a/src/type_collector.py +++ b/src/type_collector.py @@ -1,6 +1,6 @@ -from src.cmp.semantic import SemanticError -from src.cmp.semantic import Attribute, Method, Type -from src.cmp.semantic import ( +from cmp.semantic import SemanticError +from cmp.semantic import Attribute, Method, Type +from cmp.semantic import ( VoidType, IntType, ErrorType, @@ -11,9 +11,9 @@ SelfType, IOType, ) -from src.cmp.semantic import Context -from src.ast_nodes import ProgramNode, ClassDeclarationNode -import src.cmp.visitor as visitor +from cmp.semantic import Context +from ast_nodes import ProgramNode, ClassDeclarationNode +import cmp.visitor as visitor from cool_visitor import CopyVisitor From 0656b2c9f533b79abdf8d14fb2385506d192bb2c Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Fri, 18 Feb 2022 16:19:08 -0500 Subject: [PATCH 033/162] feat: lexer and parser collect errors, don't throw exception Reset state after visitors. Remove type_checker from pipeline. Remove context copy from CopyVisitor. --- src/cool_tokenizer.py | 4 --- src/cool_visitor.py | 7 ++--- src/lexical_analizer.py | 3 +- src/main.py | 16 ++++++---- src/shift_reduce_parsers.py | 49 +++++++++++++++--------------- src/tokens_rules.py | 59 ++++++++++++++++++++++++++++--------- src/type_builder.py | 7 +++-- src/type_collector.py | 7 +++-- 8 files changed, 94 insertions(+), 58 deletions(-) diff --git a/src/cool_tokenizer.py b/src/cool_tokenizer.py index 7300d4eda..6b474cab3 100644 --- a/src/cool_tokenizer.py +++ b/src/cool_tokenizer.py @@ -36,7 +36,3 @@ def pprint_tokens(tokens): if token.lex == "{": indent += 1 print(" ".join([str(t.token_type) for t in pending])) - - -# if __name__ == "__main__": -# pprint_tokens(tokens) diff --git a/src/cool_visitor.py b/src/cool_visitor.py index 60fb2f78a..ba83adc5d 100644 --- a/src/cool_visitor.py +++ b/src/cool_visitor.py @@ -365,8 +365,7 @@ def visit(self, node): declarations = [] for child in node.declarations: declarations.append(self.visit(child)) - context = node.context.copy() - return ProgramNode(declarations, context) + return ProgramNode(declarations) @visitor.when(ClassDeclarationNode) def visit(self, node): @@ -412,7 +411,7 @@ def visit(self, node): for arg in node.args: args.append(self.visit(arg)) - return CallNode(node.idx, args, obj, node.at_type) + return CallNode(node.id, args, obj, node.at_type) @visitor.when(BlockNode) def visit(self, node): @@ -453,7 +452,7 @@ def visit(self, node): @visitor.when(CaseItemNode) def visit(self, node): expr = self.visit(node.expr) - return CaseItemNode(node.idx, node.type, expr) + return CaseItemNode(node.id, node.type, expr) @visitor.when(PlusNode) def visit(self, node): diff --git a/src/lexical_analizer.py b/src/lexical_analizer.py index e76f75d6d..cf9769988 100644 --- a/src/lexical_analizer.py +++ b/src/lexical_analizer.py @@ -18,8 +18,9 @@ def pprint_tokens(tokens): print(" ".join([str(t.token_type) for t in pending])) -def tokenize_cool_text(grammar, idx, string, num, data, printing=False): +def tokenize_cool_text(grammar, idx, string, num, data, errors, printing=False): lexer = lex.lex(module=tokens_rules) + lexer.errors = errors # Give the lexer some input lexer.input(data) diff --git a/src/main.py b/src/main.py index e6f005f7d..ed0655348 100644 --- a/src/main.py +++ b/src/main.py @@ -41,23 +41,29 @@ def pipeline(input_file: Path, output_file: Path = None): # define grammar grammar, idx, string, num = define_cool_grammar() - tokens = tokenize_cool_text(grammar, idx, string, num, text) - parser = LR1Parser(grammar) + tokens = tokenize_cool_text(grammar, idx, string, num, text, errors) + if len(errors) > 0: + report_and_exit(errors) + parser = LR1Parser(grammar, errors) + + if len(errors) > 0: + report_and_exit(errors) + parse, operations = parser([t.token_type for t in tokens]) ast = evaluate_reverse_parse(parse, operations, tokens) # formatter = FormatVisitorST() # tree = formatter.visit(ast) - visitors = [TypeCollector(errors), TypeBuilder(errors), TypeChecker(errors)] + visitors = [TypeCollector(errors), TypeBuilder(errors)] for visitor in visitors: ast = visitor.visit(ast) if len(errors) > 0: report_and_exit(errors) - if output is None: - output = input.with_suffix(".mips") + if output_file is None: + output_file = input.with_suffix(".mips") if __name__ == "__main__": diff --git a/src/shift_reduce_parsers.py b/src/shift_reduce_parsers.py index a873a4566..33f0e72fd 100644 --- a/src/shift_reduce_parsers.py +++ b/src/shift_reduce_parsers.py @@ -5,7 +5,7 @@ ) from methods import compute_firsts, compute_local_first, compute_follows from cmp.automata import State -from errors import shift_reduce_error, invalid_sentence_error +from errors import shift_reduce_error, invalid_sentence_error, SyntacticError class ShiftReduceParser: @@ -13,12 +13,13 @@ class ShiftReduceParser: REDUCE = "REDUCE" OK = "OK" - def __init__(self, G, verbose=False): + def __init__(self, G, errors, verbose=False): self.G = G self.verbose = verbose self.action = {} self.goto = {} self.automaton = self._build_parsing_table() + self.errors = errors def _build_parsing_table(self): raise NotImplementedError() @@ -40,15 +41,14 @@ def __call__(self, w): action, tag = self.action[state, lookahead] except KeyError: - raise invalid_sentence_error( - w, - cursor, - lookahead, - None, - "No transition available. Sentence given does not belong to the grammar", - output, - operations, + self.errors.append( + SyntacticError( + cursor, + 0, + "No transition available. Sentence given does not belong to the grammar", + ) ) + return output, operations # Exception( # "No transition available" # ) # string does not belong to this grammar @@ -72,25 +72,24 @@ def __call__(self, w): return output, operations # Invalid case else: - raise invalid_sentence_error( - w, - cursor, - lookahead, - None, - "Invalid case. Sentence given does not belong to the grammar", + self.errors.append( + SyntacticError( + cursor, + 0, + "Invalid case. Sentence given does not belong to the grammar", + ) ) - # raise Exception("Invalid case") - # break + return output, operations if cursor >= len(w): # or not stack - raise invalid_sentence_error( - w, - cursor - 1, - lookahead, - None, - "Exceed word length while looking for a viable derivation. Sentence given does not belong to the grammar", + self.errors.append( + SyntacticError( + cursor - 1, + 0, + "Exceed word length while looking for a viable derivation. Sentence given does not belong to the grammar", + ) ) - # raise Exception("Invalid sentence") + return output, operations class SLR1Parser(ShiftReduceParser): diff --git a/src/tokens_rules.py b/src/tokens_rules.py index e3af67637..775443409 100644 --- a/src/tokens_rules.py +++ b/src/tokens_rules.py @@ -1,7 +1,13 @@ # https://www.dabeaz.com/ply/ply.html # file for PLY rules -from errors import tokenizer_error +from errors import ( + tokenizer_error, + LexicographicError, + UnexpectedCharError, + UnexpectedEOFError, + UnexpectedTokenError, +) # def find_column(input, lexpos): @@ -97,14 +103,21 @@ def t_comments_clsymb(t): # For bad characters. In this case we just skip over everything but (* or *) def t_comments_error(t): + # t.lexer.errors.append( + # LexicographicError( + # t.lexer.lineno, + # 0, + # "Illegal character inside comment", + # ) + # ) t.lexer.skip(1) # EOF handling rule def t_comments_eof(t): if t.lexer.level > 0: # guardar este error y actuar acorde - print(f"code_start{t.lexer.code_start}") - raise tokenizer_error("Comments can not cross file boundaries", t.lexer.lineno) + # print(f"code_start{t.lexer.code_start}") + t.lexer.errors.append(LexicographicError(t.lexer.lineno, 0, "EOF in comment")) return None @@ -139,7 +152,6 @@ def t_string(t): initial = t.lexer.lexpos index = t.lexer.lexpos final = len(text) - while index < final and text[index] != '"': if text[index] == "\\": if text[index + 1] in ["t", "b", "f", "n"]: @@ -150,10 +162,14 @@ def t_string(t): string_list.append("\n") elif text[index + 1] == "0": # null character \0 is not allowed # print("Illegal character \\0 inside string") # do something about it - raise tokenizer_error( - "Illegal character \\0 inside string", - t.lexer.lineno + text[initial : index + 1].count("\n"), + t.lexer.errors.append( + LexicographicError( + t.lexer.lineno + text[initial : index + 1].count("\n"), + 0, + "Illegal character \\0 inside string", + ) ) + return t else: string_list.append( text[index : index + 2] @@ -163,11 +179,16 @@ def t_string(t): elif text[index] == "\n": # \n whithout and extra \ is not allowed # print("Illegal character \\n inside string") # do something about it - raise tokenizer_error( - "Illegal character \\n inside string", - t.lexer.lineno + text[initial : index + 1].count("\n"), + t.lexer.errors.append( + LexicographicError( + t.lexer.lineno + text[initial : index + 1].count("\n"), + 0, + "Illegal character \\n inside string", + ) ) index += 1 + return t + else: string_list.append(text[index]) # string_to_append += text[index + 1] @@ -175,10 +196,14 @@ def t_string(t): if index == final: # print("String may not cross file boundaries") # do something about it - raise tokenizer_error( - "String may not cross file boundaries", - t.lexer.lineno + text[initial : index + 1].count("\n"), + t.lexer.errors.append( + LexicographicError( + t.lexer.lineno + text[initial : index + 1].count("\n"), + 0, + "String may not cross file boundaries", + ) ) + return t else: index += 1 @@ -208,5 +233,11 @@ def t_newline(t): # Error handling rule def t_error(t): - raise tokenizer_error(f"Illegal character {t.value[0]}", t.lexer.lineno) + t.lexer.errors.append( + LexicographicError( + t.lexer.lineno, + 0, + f"ERROR {t.value[0]}", + ) + ) t.lexer.skip(1) diff --git a/src/type_builder.py b/src/type_builder.py index 4a6baca48..29a52848d 100644 --- a/src/type_builder.py +++ b/src/type_builder.py @@ -1,3 +1,4 @@ +import copy from cmp.semantic import SemanticError from cmp.semantic import Attribute, Method, Type from cmp.semantic import VoidType, IntType, ErrorType, StringType, BoolType @@ -26,7 +27,7 @@ def visit(self, node): @visitor.when(ProgramNode) def visit(self, node): - self.context = node.context.copy() + self.context = copy.copy(node.context) io_type = self.context.get_type("IO") self_type = self.context.get_type("SELF_TYPE") @@ -152,10 +153,12 @@ def visit(self, node): copy_visitor = CopyVisitor() newAst = copy_visitor.visit(node) - newAst.context = self.context.copy() + newAst.context = self.context + # Reset state self.context = None self.current_type = None + self.errors = None return newAst diff --git a/src/type_collector.py b/src/type_collector.py index 9649b6b9b..2f5dfc503 100644 --- a/src/type_collector.py +++ b/src/type_collector.py @@ -49,11 +49,12 @@ def visit(self, node): copy_visitor = CopyVisitor() newAst = copy_visitor.visit(node) + newAst.context = self.context - newAst.context = self.context.copy() + # Reset state self.context = None - # TODO: self.errors tambien deberia volver a su estado inicial - # devolver (newAst,errors) ??? + self.errors = None + return newAst @visitor.when(ClassDeclarationNode) From 844deeaefa7bf4b14490a60b1cec1f8b8b387b5b Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Sat, 19 Feb 2022 10:54:18 -0500 Subject: [PATCH 034/162] feat!: update with amaliaibarra repo --- .directory | 5 +- ...I_barra_Gabriela_Martinez_c312_informe.pdf | Bin 246202 -> 0 bytes conftest.py | 0 main.py | 129 -------- src/ast_nodes.py | 6 +- src/cmp/ast.py | 7 +- src/cmp/cil.py | 3 +- src/cmp/evaluation.py | 4 +- src/cmp/semantic.py | 10 +- src/cmp/utils.py | 2 +- src/cool_grammar.py | 4 +- src/cool_tokenizer.py | 7 +- src/cool_visitor.py | 197 ++++++++++- src/coolc.sh | 5 +- src/errors.py | 156 ++++++++- src/lexical_analizer.py | 8 +- src/main.py | 70 ++++ src/methods.py | 9 +- src/parser_automatons.py | 8 +- src/shift_reduce_parsers.py | 55 ++-- src/tokens_rules.py | 61 +++- src/tset_builder.py | 178 ---------- src/tset_merger.py | 163 --------- src/tsets_reducer.py | 311 ------------------ src/type_builder.py | 38 ++- src/type_checker.py | 43 +-- src/type_collector.py | 26 +- src/ui.py | 127 ------- 28 files changed, 598 insertions(+), 1034 deletions(-) delete mode 100644 AmaliaI_barra_Gabriela_Martinez_c312_informe.pdf delete mode 100644 conftest.py delete mode 100644 main.py create mode 100644 src/main.py delete mode 100644 src/tset_builder.py delete mode 100644 src/tset_merger.py delete mode 100644 src/tsets_reducer.py delete mode 100644 src/ui.py diff --git a/.directory b/.directory index d0e97ae24..411e7e8e9 100644 --- a/.directory +++ b/.directory @@ -1,7 +1,4 @@ [Dolphin] -Timestamp=2021,4,13,11,6,10 +Timestamp=2022,2,19,10,32,56 Version=4 ViewMode=1 - -[Settings] -HiddenFilesShown=true diff --git a/AmaliaI_barra_Gabriela_Martinez_c312_informe.pdf b/AmaliaI_barra_Gabriela_Martinez_c312_informe.pdf deleted file mode 100644 index 20b458ab95b3d395d14fb21bf85b73300cb4c6ec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 246202 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�L>Lw_~e0h#_Wz$NQ4UB-Pmc33a@MsCnwx)eQYg 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 diff --git a/conftest.py b/conftest.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/main.py b/main.py deleted file mode 100644 index 8781dd651..000000000 --- a/main.py +++ /dev/null @@ -1,129 +0,0 @@ -from src.lexical_analizer import tokenize_cool_text -from src.cool_grammar import define_cool_grammar -from src.cool_visitor import FormatVisitorST - -from src.type_collector import TypeCollector -from src.type_builder import TypeBuilder -from src.type_checker import TypeChecker -from src.tset_builder import TSetBuilder -from src.tsets_reducer import TSetReducer -from src.tset_merger import TSetMerger - -from src.shift_reduce_parsers import LR1Parser, DerivationTree -from src.errors import parsing_table_error, Error - -from src.cmp.evaluation import evaluate_reverse_parse - -import streamlit as st -from src.ui import print_array, print_grammar, print_tset - -st.sidebar.header("About") -st.sidebar.subheader("Segundo Proyecto de Compilacion: Cool Intrepreter") -st.sidebar.text("Amalia Ibarra Rodríguez") -st.sidebar.text("Gabriela B. Martínez Giraldo") -st.sidebar.text("Grupo: C-312") -st.sidebar.text("Curso: 2019-2020") - -""" # Cool Intrepreter """ - -data = st.text_area("Type some code", "") -run_analysis = st.button("compile", "") - - -initial_ast = "Initial_AST" -final_ast = "Final_AST" -reduced_sets = "ReducedSets" - - -selected_options = st.multiselect( - "Select what to see", (initial_ast, final_ast, reduced_sets), -) - - -def run_pipeline(text): - main_error1 = ["A class Main with a method main most be provided"] - main_error2 = ['"main" method in class Main does not receive any parameters'] - # define grammar - grammar, idx, string, num = define_cool_grammar() - - try: - tokens = tokenize_cool_text(grammar, idx, string, num, text) - - parser = LR1Parser(grammar) - parse, operations = parser([t.token_type for t in tokens]) - - # print("\n".join(repr(x) for x in parse)) - # print(operations) - - ast = evaluate_reverse_parse(parse, operations, tokens) - formatter = FormatVisitorST() - tree = formatter.visit(ast) - - if initial_ast in selected_options: - st.header("Initial Tree:") - print_array(tree) - - errors = [] - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - if errors != [] and errors != main_error1 and errors != main_error2: - st.header("Sorry we found some errors in your code:") - print_array(errors) - else: - if errors == main_error1 or errors == main_error2: - st.header("Warning") - st.write("We will continue the analisis but note that:") - st.write(errors[0]) - errors = [] - - tset_builder = TSetBuilder(context, errors) - tset = tset_builder.visit(ast, None) - - tset_reducer = TSetReducer(context, errors) - reduced_set = tset_reducer.visit(ast, tset) - - tset_merger = TSetMerger(context, errors) - tset_merger.visit(ast, reduced_set) - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - if errors != [] and errors != main_error1 and errors != main_error2: - st.header("Sorry we found some errors in your code:") - print_array(errors) - - if reduced_sets in selected_options: - st.header("Reduced Sets") - print_tset(reduced_set) - - if final_ast in selected_options: - tree = formatter.visit(ast) - st.header("Final Tree:") - print_array(tree) - - except Error as error: - st.header("Sorry an error occur while tokenizing text:") - st.write(str(error)) - - -if run_analysis: - run_pipeline(data) - diff --git a/src/ast_nodes.py b/src/ast_nodes.py index d8dfa6aaf..869599488 100644 --- a/src/ast_nodes.py +++ b/src/ast_nodes.py @@ -1,10 +1,14 @@ +from cmp.semantic import Context + + class Node: pass class ProgramNode(Node): - def __init__(self, declarations): + def __init__(self, declarations, context=None): self.declarations = declarations + self.context = context class ExpressionNode(Node): diff --git a/src/cmp/ast.py b/src/cmp/ast.py index c0f73e1b2..9f2d775f5 100644 --- a/src/cmp/ast.py +++ b/src/cmp/ast.py @@ -1,4 +1,4 @@ -import src.cmp.visitor as visitor +import cmp.visitor as visitor class Node: @@ -40,7 +40,9 @@ def operate(lvalue, rvalue): def get_printer( - AtomicNode=AtomicNode, UnaryNode=UnaryNode, BinaryNode=BinaryNode, + AtomicNode=AtomicNode, + UnaryNode=UnaryNode, + BinaryNode=BinaryNode, ): class PrintVisitor(object): @visitor.on("node") @@ -66,4 +68,3 @@ def visit(self, node, tabs=0): printer = PrintVisitor() return lambda ast: printer.visit(ast) - diff --git a/src/cmp/cil.py b/src/cmp/cil.py index 5864ccdd0..21cbaedaa 100644 --- a/src/cmp/cil.py +++ b/src/cmp/cil.py @@ -1,4 +1,4 @@ -import src.cmp.visitor as visitor +import cmp.visitor as visitor class Node: @@ -264,4 +264,3 @@ def visit(self, node): printer = PrintVisitor() return lambda ast: printer.visit(ast) - diff --git a/src/cmp/evaluation.py b/src/cmp/evaluation.py index 830703efe..f54d09279 100644 --- a/src/cmp/evaluation.py +++ b/src/cmp/evaluation.py @@ -1,5 +1,5 @@ -from src.cmp.pycompiler import EOF -from src.shift_reduce_parsers import ShiftReduceParser +from cmp.pycompiler import EOF +from shift_reduce_parsers import ShiftReduceParser def evaluate_reverse_parse(right_parse, operations, tokens): diff --git a/src/cmp/semantic.py b/src/cmp/semantic.py index 0cd3cfbb7..b4f6424c0 100644 --- a/src/cmp/semantic.py +++ b/src/cmp/semantic.py @@ -224,15 +224,11 @@ def __init__(self): Type.__init__(self, "SELF_TYPE") -# Despues de entregar!!!! class IOType(Type): def __init__(self): Type.__init__(self, "IO") -# --------------------------- - - class Context: def __init__(self): self.types = {} @@ -259,6 +255,12 @@ def __str__(self): def __repr__(self): return str(self) + def __copy__(self): + newContext = Context() + for key, value in self.types.items(): + newContext.types[key] = value + return newContext + class VariableInfo: def __init__(self, name, vtype): diff --git a/src/cmp/utils.py b/src/cmp/utils.py index 5bcf97b19..cad362fdb 100644 --- a/src/cmp/utils.py +++ b/src/cmp/utils.py @@ -1,4 +1,4 @@ -from src.cmp.pycompiler import Production, Sentence, Symbol, EOF, Epsilon +from cmp.pycompiler import Production, Sentence, Symbol, EOF, Epsilon class ContainerSet: diff --git a/src/cool_grammar.py b/src/cool_grammar.py index fc3035214..a7c4c6e46 100644 --- a/src/cool_grammar.py +++ b/src/cool_grammar.py @@ -1,5 +1,5 @@ -from src.cmp.pycompiler import Grammar -from src.ast_nodes import ( +from cmp.pycompiler import Grammar +from ast_nodes import ( ProgramNode, ClassDeclarationNode, FuncDeclarationNode, diff --git a/src/cool_tokenizer.py b/src/cool_tokenizer.py index 90178fc09..6b474cab3 100644 --- a/src/cool_tokenizer.py +++ b/src/cool_tokenizer.py @@ -1,4 +1,4 @@ -from src.cmp.utils import Token, tokenizer +from cmp.utils import Token, tokenizer def tokenize_cool_text(G, text, idx, num, print_tokens=False): @@ -36,8 +36,3 @@ def pprint_tokens(tokens): if token.lex == "{": indent += 1 print(" ".join([str(t.token_type) for t in pending])) - - -# if __name__ == "__main__": -# pprint_tokens(tokens) - diff --git a/src/cool_visitor.py b/src/cool_visitor.py index 8dab5b918..ba83adc5d 100644 --- a/src/cool_visitor.py +++ b/src/cool_visitor.py @@ -1,5 +1,5 @@ -import src.cmp.visitor as visitor -from src.ast_nodes import ( +import cmp.visitor as visitor +from ast_nodes import ( ProgramNode, ClassDeclarationNode, FuncDeclarationNode, @@ -17,6 +17,23 @@ BinaryNode, AtomicNode, UnaryNode, + ArithmeticOperation, + ComparisonOperation, + ConstantNumNode, + VariableNode, + StringNode, + BooleanNode, + InstantiateNode, + NotNode, + IsvoidNode, + NegNode, + PlusNode, + MinusNode, + StarNode, + DivNode, + LessNode, + LessEqualNode, + EqualNode, ) @@ -337,3 +354,179 @@ def visit(self, node, tabs=0): self.visit(node.expr, tabs + 1) return + +class CopyVisitor(object): + @visitor.on("node") + def visit(self, node): + pass + + @visitor.when(ProgramNode) + def visit(self, node): + declarations = [] + for child in node.declarations: + declarations.append(self.visit(child)) + return ProgramNode(declarations) + + @visitor.when(ClassDeclarationNode) + def visit(self, node): + features = [] + for feat in node.features: + features.append(self.visit(feat)) + return ClassDeclarationNode(node.id, features, node.parent) + + @visitor.when(AttrDeclarationNode) + def visit(self, node): + init_exp = None + if not node.init_exp is None: + init_exp = self.visit(node.init_exp) + + return AttrDeclarationNode(node.id, node.type, init_exp) + + @visitor.when(VarDeclarationNode) + def visit(self, node): + expr = None + if not node.expr is None: + expr = self.visit(node.expr) + + return VarDeclarationNode(node.id, node.type, expr) + + @visitor.when(AssignNode) + def visit(self, node): + expr = self.visit(node.expr) + return AssignNode(node.id, expr) + + @visitor.when(FuncDeclarationNode) + def visit(self, node): + params = [p for p in node.params] + body = self.visit(node.body) + return FuncDeclarationNode(node.id, params, node.type, body) + + @visitor.when(CallNode) + def visit(self, node): + obj = None + if not node.obj is None: + obj = self.visit(node.obj) + + args = [] + for arg in node.args: + args.append(self.visit(arg)) + + return CallNode(node.id, args, obj, node.at_type) + + @visitor.when(BlockNode) + def visit(self, node): + expression_list = [] + for child in node.expression_list: + expression_list.append(self.visit(child)) + return BlockNode(expression_list) + + @visitor.when(IfNode) + def visit(self, node): + if_expr = self.visit(node.if_expr) + then_expr = self.visit(node.then_expr) + else_expr = self.visit(node.else_expr) + return IfNode(if_expr, then_expr, else_expr) + + @visitor.when(WhileNode) + def visit(self, node): + condition = self.visit(node.condition) + body = self.visit(node.body) + return WhileNode(condition, body) + + @visitor.when(LetNode) + def visit(self, node): + identifiers = [] + for child in node.identifiers: + identifiers.append(self.visit(child)) + body = self.visit(node.body) + return LetNode(identifiers, body) + + @visitor.when(CaseNode) + def visit(self, node): + expr = self.visit(node.expr) + case_items = [] + for child in node.case_items: + case_items.append(self.visit(child)) + return CaseNode(expr, case_items) + + @visitor.when(CaseItemNode) + def visit(self, node): + expr = self.visit(node.expr) + return CaseItemNode(node.id, node.type, expr) + + @visitor.when(PlusNode) + def visit(self, node): + left = self.visit(node.left) + right = self.visit(node.right) + return PlusNode(left, right) + + @visitor.when(MinusNode) + def visit(self, node): + left = self.visit(node.left) + right = self.visit(node.right) + return MinusNode(left, right) + + @visitor.when(StarNode) + def visit(self, node): + left = self.visit(node.left) + right = self.visit(node.right) + return StarNode(left, right) + + @visitor.when(DivNode) + def visit(self, node): + left = self.visit(node.left) + right = self.visit(node.right) + return DivNode(left, right) + + @visitor.when(LessNode) + def visit(self, node): + left = self.visit(node.left) + right = self.visit(node.right) + return LessNode(left, right) + + @visitor.when(LessEqualNode) + def visit(self, node): + left = self.visit(node.left) + right = self.visit(node.right) + return LessEqualNode(left, right) + + @visitor.when(EqualNode) + def visit(self, node): + left = self.visit(node.left) + right = self.visit(node.right) + return EqualNode(left, right) + + @visitor.when(ConstantNumNode) + def visit(self, node): + return ConstantNumNode(node.lex) + + @visitor.when(VariableNode) + def visit(self, node): + return VariableNode(node.lex) + + @visitor.when(StringNode) + def visit(self, node): + return StringNode(node.lex) + + @visitor.when(BooleanNode) + def visit(self, node): + return BooleanNode(node.lex) + + @visitor.when(InstantiateNode) + def visit(self, node): + return InstantiateNode(node.lex) + + @visitor.when(NotNode) + def visit(self, node): + expr = self.visit(node.expr) + return NotNode(expr) + + @visitor.when(IsvoidNode) + def visit(self, node): + expr = self.visit(node.expr) + return IsvoidNode(expr) + + @visitor.when(NegNode) + def visit(self, node): + expr = self.visit(node.expr) + return NegNode(expr) diff --git a/src/coolc.sh b/src/coolc.sh index 3088de4f9..d3cf16bd2 100755 --- a/src/coolc.sh +++ b/src/coolc.sh @@ -4,8 +4,9 @@ INPUT_FILE=$1 OUTPUT_FILE=${INPUT_FILE:0: -2}mips # Si su compilador no lo hace ya, aquí puede imprimir la información de contacto -echo "LINEA_CON_NOMBRE_Y_VERSION_DEL_COMPILADOR" # TODO: Recuerde cambiar estas -echo "Copyright (c) 2019: Nombre1, Nombre2, Nombre3" # TODO: líneas a los valores correctos +echo "EL_COMPI 1.0" +echo "Copyright (c) 2022: Amalia_Ibarra, Sandra_Martos, Gabriela_Martinez" # Llamar al compilador echo "Compiling $INPUT_FILE into $OUTPUT_FILE" +python -m main $@ \ No newline at end of file diff --git a/src/errors.py b/src/errors.py index 14c9922a5..6411c8a1b 100644 --- a/src/errors.py +++ b/src/errors.py @@ -1,3 +1,156 @@ +class CoolCompilerError(object): + """ + Errors reported by the compiler + """ + + def __init__(self, line, column, type, msg) -> None: + self.line = line + self.column = column + self.type = type + self.msg = msg + + def __str__(self) -> str: + return f"({self.line}, {self.column}) - {self.type}: {self.msg}" + + +# Compiler errors + + +class CompilerError(CoolCompilerError): + """ + Error reported when an anomaly in the compiler's input is detected. + For example, if the input file doesn't exist. + """ + + def __init__(self, msg) -> None: + CoolCompilerError.__init__(self, 0, 0, "CompilerError", msg) + + +class InvalidInputFileError(CompilerError): + """ + Reported when input file is invalid. + """ + + def __init__(self, path: str) -> None: + CompilerError.__init__(self, f"File `{path}` is not a valid file.") + + +# Lexicographic errors + + +class LexicographicError(CoolCompilerError): + """ + Error reported by lexer + """ + + def __init__(self, line: int, column: int, msg: str) -> None: + CoolCompilerError.__init__(self, line, column, "LexicographicError", msg) + + +class UnexpectedCharError(LexicographicError): + """ + Reported the lexer encounters an unexpected character. + """ + + def __init__(self, line: int, column: int, char: str) -> None: + LexicographicError.__init__(self, line, column, f"Unexpected `{char}`.") + + +# Syntactic errors + + +class SyntacticError(CoolCompilerError): + """ + Error reported by parser + """ + + def __init__(self, line: int, column: int, msg: str) -> None: + CoolCompilerError.__init__(self, line, column, "SyntacticError", msg) + + +class UnexpectedTokenError(SyntacticError): + """ + Reported the parser encounters an unexpected Token. + """ + + def __init__(self, line: int, column: int, token: str) -> None: + SyntacticError.__init__( + self, + line, + column, + f"Unexpected token `{token}`.", + ) + + +class UnexpectedEOFError(SyntacticError): + """ + Reported the parser encounters end of file unexpectedly. + """ + + def __init__(self) -> None: + SyntacticError.__init__(self, 0, 0, "Unexpected EOF.") + + +# Semantic errors + + +class NameError(CoolCompilerError): + """ + Error reported when an identifier is referenced in a scope where it is not visible. + """ + + def __init__(self, line: int, column: int, msg: str) -> None: + CoolCompilerError.__init__(self, line, column, "NameError", msg) + + +class TypeError(CoolCompilerError): + """ + Error reported when a problem with types is detected. Includes: + - type incompatibility between `rvalue` and `lvalue`, + - undefined operation between objects of certain types + - referenced type is undefined + """ + + def __init__(self, line: int, column: int, msg: str) -> None: + CoolCompilerError.__init__(self, line, column, "TypeError", msg) + + +class AttributeError(CoolCompilerError): + """ + Error reported when an attribute or method is referenced but undefined. + """ + + def __init__(self, line: int, column: int, msg: str) -> None: + CoolCompilerError.__init__(self, line, column, "AttributeError", msg) + + +class SemanticError(CoolCompilerError): + """ + Any kind of semantic error + """ + + def __init__(self, line, column, msg) -> None: + CoolCompilerError.__init__(self, line, column, "SemanticError", msg) + + +class IncompatibleTypesError(SemanticError): + def __init__(self, line, column, type_a, type_b) -> None: + SemanticError.__init__( + self, line, column, f"Cannot convert {type_a} into {type_b}." + ) + + +class WrongSignatureError(SemanticError): + def __init__(self, line, column, method) -> None: + SemanticError.__init__( + self, + line, + column, + f"Method {method} already defined with a different signature.", + ) + + +# ---------------------------------------------- class Error(Exception): "Base class for exceptions" pass @@ -8,7 +161,8 @@ class tokenizer_error(Error): def __init__(self, text, line): Error.__init__( - self, f"Got {text} while analizing line {line}", + self, + f"Got {text} while analizing line {line}", ) diff --git a/src/lexical_analizer.py b/src/lexical_analizer.py index a0e3a9a1c..cf9769988 100644 --- a/src/lexical_analizer.py +++ b/src/lexical_analizer.py @@ -1,6 +1,6 @@ import ply.lex as lex -import src.tokens_rules as tokens_rules -from src.cmp.utils import Token +import tokens_rules as tokens_rules +from cmp.utils import Token def pprint_tokens(tokens): @@ -18,8 +18,9 @@ def pprint_tokens(tokens): print(" ".join([str(t.token_type) for t in pending])) -def tokenize_cool_text(grammar, idx, string, num, data, printing=False): +def tokenize_cool_text(grammar, idx, string, num, data, errors, printing=False): lexer = lex.lex(module=tokens_rules) + lexer.errors = errors # Give the lexer some input lexer.input(data) @@ -54,4 +55,3 @@ def tokenize_cool_text(grammar, idx, string, num, data, printing=False): if printing: pprint_tokens(tokens) return tokens - diff --git a/src/main.py b/src/main.py new file mode 100644 index 000000000..ed0655348 --- /dev/null +++ b/src/main.py @@ -0,0 +1,70 @@ +from lexical_analizer import tokenize_cool_text +from cool_grammar import define_cool_grammar +from cool_visitor import FormatVisitorST + +from type_collector import TypeCollector +from type_builder import TypeBuilder +from type_checker import TypeChecker + +from shift_reduce_parsers import LR1Parser, DerivationTree +from errors import parsing_table_error, Error + +from cmp.evaluation import evaluate_reverse_parse +from pathlib import Path +from errors import InvalidInputFileError +import typer + + +def report_and_exit(errors): + if len(errors) == 0: + raise typer.Exit(code=0) + + for error in errors: + typer.echo(error) + raise typer.Exit(code=1) + + +def pipeline(input_file: Path, output_file: Path = None): + errors = [] + + if not input_file.is_file: + errors.append(InvalidInputFileError(str(input_file))) + + if len(errors) > 0: + report_and_exit(errors) + + text = input_file.read_text() + + # main_error1 = ["A class Main with a method main most be provided"] + # main_error2 = ['"main" method in class Main does not receive any parameters'] + + # define grammar + grammar, idx, string, num = define_cool_grammar() + + tokens = tokenize_cool_text(grammar, idx, string, num, text, errors) + if len(errors) > 0: + report_and_exit(errors) + parser = LR1Parser(grammar, errors) + + if len(errors) > 0: + report_and_exit(errors) + + parse, operations = parser([t.token_type for t in tokens]) + + ast = evaluate_reverse_parse(parse, operations, tokens) + # formatter = FormatVisitorST() + # tree = formatter.visit(ast) + + visitors = [TypeCollector(errors), TypeBuilder(errors)] + for visitor in visitors: + ast = visitor.visit(ast) + + if len(errors) > 0: + report_and_exit(errors) + + if output_file is None: + output_file = input.with_suffix(".mips") + + +if __name__ == "__main__": + typer.run(pipeline) diff --git a/src/methods.py b/src/methods.py index 3302215e5..8723d7c20 100644 --- a/src/methods.py +++ b/src/methods.py @@ -1,4 +1,4 @@ -from src.cmp.pycompiler import ( +from cmp.pycompiler import ( Symbol, NonTerminal, Terminal, @@ -9,9 +9,9 @@ Production, Grammar, ) -from src.cmp.utils import ContainerSet -from src.errors import parsing_table_error, invalid_sentence_error -from src.cmp.automata import State +from cmp.utils import ContainerSet +from errors import parsing_table_error, invalid_sentence_error +from cmp.automata import State # Computes First(alpha), given First(Vt) and First(Vn) @@ -146,4 +146,3 @@ def compute_follows(G, firsts): # Follow(Vn) return follows - diff --git a/src/parser_automatons.py b/src/parser_automatons.py index 6fce5323d..437f4d16b 100644 --- a/src/parser_automatons.py +++ b/src/parser_automatons.py @@ -1,7 +1,7 @@ -from src.cmp.pycompiler import Item -from src.cmp.automata import State, lr0_formatter, multiline_formatter -from src.cmp.utils import ContainerSet -from src.methods import compute_firsts, compute_local_first, compute_follows +from cmp.pycompiler import Item +from cmp.automata import State, lr0_formatter, multiline_formatter +from cmp.utils import ContainerSet +from methods import compute_firsts, compute_local_first, compute_follows # LR0 automaton -> for SLR and LALR parsers def build_LR0_automaton(G): diff --git a/src/shift_reduce_parsers.py b/src/shift_reduce_parsers.py index 3501302b1..33f0e72fd 100644 --- a/src/shift_reduce_parsers.py +++ b/src/shift_reduce_parsers.py @@ -1,11 +1,11 @@ -from src.parser_automatons import ( +from parser_automatons import ( build_LR0_automaton, build_LR1_automaton, build_LALR_automaton, ) -from src.methods import compute_firsts, compute_local_first, compute_follows -from src.cmp.automata import State -from src.errors import shift_reduce_error, invalid_sentence_error +from methods import compute_firsts, compute_local_first, compute_follows +from cmp.automata import State +from errors import shift_reduce_error, invalid_sentence_error, SyntacticError class ShiftReduceParser: @@ -13,12 +13,13 @@ class ShiftReduceParser: REDUCE = "REDUCE" OK = "OK" - def __init__(self, G, verbose=False): + def __init__(self, G, errors, verbose=False): self.G = G self.verbose = verbose self.action = {} self.goto = {} self.automaton = self._build_parsing_table() + self.errors = errors def _build_parsing_table(self): raise NotImplementedError() @@ -40,15 +41,14 @@ def __call__(self, w): action, tag = self.action[state, lookahead] except KeyError: - raise invalid_sentence_error( - w, - cursor, - lookahead, - None, - "No transition available. Sentence given does not belong to the grammar", - output, - operations, + self.errors.append( + SyntacticError( + cursor, + 0, + "No transition available. Sentence given does not belong to the grammar", + ) ) + return output, operations # Exception( # "No transition available" # ) # string does not belong to this grammar @@ -72,25 +72,24 @@ def __call__(self, w): return output, operations # Invalid case else: - raise invalid_sentence_error( - w, - cursor, - lookahead, - None, - "Invalid case. Sentence given does not belong to the grammar", + self.errors.append( + SyntacticError( + cursor, + 0, + "Invalid case. Sentence given does not belong to the grammar", + ) ) - # raise Exception("Invalid case") - # break + return output, operations if cursor >= len(w): # or not stack - raise invalid_sentence_error( - w, - cursor - 1, - lookahead, - None, - "Exceed word length while looking for a viable derivation. Sentence given does not belong to the grammar", + self.errors.append( + SyntacticError( + cursor - 1, + 0, + "Exceed word length while looking for a viable derivation. Sentence given does not belong to the grammar", + ) ) - # raise Exception("Invalid sentence") + return output, operations class SLR1Parser(ShiftReduceParser): diff --git a/src/tokens_rules.py b/src/tokens_rules.py index b00583675..775443409 100644 --- a/src/tokens_rules.py +++ b/src/tokens_rules.py @@ -1,7 +1,13 @@ # https://www.dabeaz.com/ply/ply.html # file for PLY rules -from src.errors import tokenizer_error +from errors import ( + tokenizer_error, + LexicographicError, + UnexpectedCharError, + UnexpectedEOFError, + UnexpectedTokenError, +) # def find_column(input, lexpos): @@ -97,14 +103,21 @@ def t_comments_clsymb(t): # For bad characters. In this case we just skip over everything but (* or *) def t_comments_error(t): + # t.lexer.errors.append( + # LexicographicError( + # t.lexer.lineno, + # 0, + # "Illegal character inside comment", + # ) + # ) t.lexer.skip(1) # EOF handling rule def t_comments_eof(t): if t.lexer.level > 0: # guardar este error y actuar acorde - print(f"code_start{t.lexer.code_start}") - raise tokenizer_error("Comments can not cross file boundaries", t.lexer.lineno) + # print(f"code_start{t.lexer.code_start}") + t.lexer.errors.append(LexicographicError(t.lexer.lineno, 0, "EOF in comment")) return None @@ -133,13 +146,12 @@ def t_comment1(t): def t_string(t): - r"\"" + r"\" " string_list = [] text = t.lexer.lexdata initial = t.lexer.lexpos index = t.lexer.lexpos final = len(text) - while index < final and text[index] != '"': if text[index] == "\\": if text[index + 1] in ["t", "b", "f", "n"]: @@ -150,10 +162,14 @@ def t_string(t): string_list.append("\n") elif text[index + 1] == "0": # null character \0 is not allowed # print("Illegal character \\0 inside string") # do something about it - raise tokenizer_error( - "Illegal character \\0 inside string", - t.lexer.lineno + text[initial : index + 1].count("\n"), + t.lexer.errors.append( + LexicographicError( + t.lexer.lineno + text[initial : index + 1].count("\n"), + 0, + "Illegal character \\0 inside string", + ) ) + return t else: string_list.append( text[index : index + 2] @@ -163,11 +179,16 @@ def t_string(t): elif text[index] == "\n": # \n whithout and extra \ is not allowed # print("Illegal character \\n inside string") # do something about it - raise tokenizer_error( - "Illegal character \\n inside string", - t.lexer.lineno + text[initial : index + 1].count("\n"), + t.lexer.errors.append( + LexicographicError( + t.lexer.lineno + text[initial : index + 1].count("\n"), + 0, + "Illegal character \\n inside string", + ) ) index += 1 + return t + else: string_list.append(text[index]) # string_to_append += text[index + 1] @@ -175,10 +196,14 @@ def t_string(t): if index == final: # print("String may not cross file boundaries") # do something about it - raise tokenizer_error( - "String may not cross file boundaries", - t.lexer.lineno + text[initial : index + 1].count("\n"), + t.lexer.errors.append( + LexicographicError( + t.lexer.lineno + text[initial : index + 1].count("\n"), + 0, + "String may not cross file boundaries", + ) ) + return t else: index += 1 @@ -208,5 +233,11 @@ def t_newline(t): # Error handling rule def t_error(t): - raise tokenizer_error(f"Illegal character {t.value[0]}", t.lexer.lineno) + t.lexer.errors.append( + LexicographicError( + t.lexer.lineno, + 0, + f"ERROR {t.value[0]}", + ) + ) t.lexer.skip(1) diff --git a/src/tset_builder.py b/src/tset_builder.py deleted file mode 100644 index 3ff33d27d..000000000 --- a/src/tset_builder.py +++ /dev/null @@ -1,178 +0,0 @@ -import src.cmp.visitor as visitor -import src.cmp.nbpackage -import src.cmp.visitor as visitor - -from src.tset import Tset -from src.cmp.semantic import ( - ObjectType, - IntType, - StringType, - VoidType, - BoolType, - ErrorType, - AutoType, - SelfType, - SemanticError, -) -from src.ast_nodes import Node, ProgramNode, ExpressionNode -from src.ast_nodes import ClassDeclarationNode, FuncDeclarationNode, AttrDeclarationNode -from src.ast_nodes import VarDeclarationNode, AssignNode, CallNode -from src.ast_nodes import ( - AtomicNode, - UnaryNode, - BinaryNode, - ArithmeticOperation, - ComparisonOperation, - IfNode, - LetNode, - CaseNode, - CaseItemNode, - WhileNode, - BlockNode, - IsvoidNode, -) -from src.ast_nodes import ( - ConstantNumNode, - VariableNode, - InstantiateNode, - PlusNode, - MinusNode, - StarNode, - DivNode, - NegNode, - NotNode, - EqualNode, - BooleanNode, - StringNode, -) - - -class TSetBuilder: - def __init__(self, context, errors=[]): - self.context = context - self.current_type = None - self.errors = errors - - def get_autotype_set(self): - solve = set(self.context.types.keys()) - solve.remove("AUTO_TYPE") - return solve - - @visitor.on("node") - def visit(self, node, tset): - pass - - @visitor.when(ProgramNode) - def visit(self, node, tset=None): - tset = Tset() - for declaration in node.declarations: - self.visit(declaration, tset.create_child(declaration)) - return tset - - @visitor.when(ClassDeclarationNode) - def visit(self, node, tset): - self.current_type = self.context.get_type(node.id) - for feature in node.features: - self.visit(feature, tset) - - @visitor.when(AttrDeclarationNode) - def visit(self, node, tset): - static_type = self.context.get_type(node.type) - if static_type.name == "AUTO_TYPE": - tset.locals[node.id] = self.get_autotype_set() - else: - tset.locals[node.id] = {static_type.name, "!static_type_declared"} - if node.init_exp is not None: - self.visit(node.init_exp, tset) - - @visitor.when(FuncDeclarationNode) - def visit(self, node, tset): - if node.type == "AUTO_TYPE": - tset.locals[node.id] = self.get_autotype_set() - else: - tset.locals[node.id] = {node.type, "!static_type_declared"} - - child_set = tset.create_child(node) - method = self.current_type.get_method(node.id) - method.tset = child_set - - for param in node.params: - typex = self.context.get_type(param[1]) - if typex.name == "AUTO_TYPE": - child_set.locals[param[0]] = self.get_autotype_set() - else: - child_set.locals[param[0]] = {typex.name, "!static_type_declared"} - - self.visit(node.body, child_set) - - @visitor.when(AssignNode) - def visit(self, node, tset): - self.visit(node.expr, tset) - - @visitor.when(LetNode) - def visit(self, node, tset): - child_set = tset.create_child(node) - for var_dec in node.identifiers: - self.visit(var_dec, child_set) - - self.visit(node.body, child_set) - - @visitor.when(VarDeclarationNode) - def visit(self, node, tset): - typex = self.context.get_type(node.type) - if typex.name == "AUTO_TYPE": - tset.locals[node.id] = self.get_autotype_set() - else: - tset.locals[node.id] = {typex.name, "!static_type_declared"} - - self.visit(node.expr, tset) - - @visitor.when(IfNode) - def visit(self, node, tset): - self.visit(node.if_expr, tset) - self.visit(node.then_expr, tset) - self.visit(node.else_expr, tset) - - @visitor.when(WhileNode) - def visit(self, node, tset): - self.visit(node.condition, tset) - self.visit(node.body, tset) - - @visitor.when(CaseNode) - def visit(self, node, tset): - self.visit(node.expr, tset) - - for item in node.case_items: - self.visit(item, tset.create_child(item)) - - @visitor.when(CaseItemNode) - def visit(self, node, tset): - typex = self.context.get_type(node.type) - if typex.name == "AUTO_TYPE": - tset.locals[node.id] = self.get_autotype_set() - else: - tset.locals[node.id] = {typex.name, "!static_type_declared"} - - self.visit(node.expr, tset) - - @visitor.when(CallNode) - def visit(self, node, tset): - pass - - @visitor.when(BlockNode) - def visit(self, node, tset): - for expr in node.expression_list: - self.visit(expr, tset) - - @visitor.when(AtomicNode) - def visit(self, node, tset): - pass - - @visitor.when(UnaryNode) - def visit(self, node, tset): - self.visit(node.expr, tset) - - @visitor.when(BinaryNode) - def visit(self, node, tset): - self.visit(node.left, tset) - self.visit(node.right, tset) diff --git a/src/tset_merger.py b/src/tset_merger.py deleted file mode 100644 index 178132095..000000000 --- a/src/tset_merger.py +++ /dev/null @@ -1,163 +0,0 @@ -import src.cmp.visitor as visitor -import src.cmp.nbpackage -import src.cmp.visitor as visitor - -from src.tset import Tset -from src.cmp.semantic import ( - ObjectType, - IntType, - StringType, - VoidType, - BoolType, - ErrorType, - AutoType, - SelfType, - SemanticError, -) -from src.ast_nodes import Node, ProgramNode, ExpressionNode -from src.ast_nodes import ClassDeclarationNode, FuncDeclarationNode, AttrDeclarationNode -from src.ast_nodes import VarDeclarationNode, AssignNode, CallNode -from src.ast_nodes import ( - AtomicNode, - UnaryNode, - BinaryNode, - ArithmeticOperation, - ComparisonOperation, - IfNode, - LetNode, - CaseNode, - CaseItemNode, - WhileNode, - BlockNode, - IsvoidNode, -) -from src.ast_nodes import ( - ConstantNumNode, - VariableNode, - InstantiateNode, - PlusNode, - MinusNode, - StarNode, - DivNode, - NegNode, - NotNode, - EqualNode, - BooleanNode, - StringNode, -) -from src.cmp.utils import least_type - - -class TSetMerger: - def __init__(self, context, errors=[]): - self.context = context - self.errors = errors - - def get_autotype_set(self): - solve = set(self.context.types.keys()) - solve.remove("AUTO_TYPE") - return solve - - @visitor.on("node") - def visit(self, node, tset): - pass - - @visitor.when(ProgramNode) - def visit(self, node, tset): - for declaration in node.declarations: - self.visit(declaration, tset.children[declaration]) - - @visitor.when(ClassDeclarationNode) - def visit(self, node, tset): - for feature in node.features: - self.visit(feature, tset) - - @visitor.when(AttrDeclarationNode) - def visit(self, node, tset): - typex = least_type(tset.locals[node.id], self.context) - node.type = typex - - if node.init_exp is not None: - self.visit(node.init_exp, tset) - - @visitor.when(FuncDeclarationNode) - def visit(self, node, tset): - return_type = least_type(tset.locals[node.id], self.context) - node.type = return_type - - child_tset = tset.children[node] - args_types = [] - for param in node.params: - typex = least_type(child_tset.locals[param[0]], self.context) - args_types.append((param[0], typex)) - - for i in range(len(args_types)): - node.params[i] = args_types[i] - self.visit(node.body, child_tset) - - @visitor.when(AssignNode) - def visit(self, node, tset): - self.visit(node.expr, tset) - - @visitor.when(LetNode) - def visit(self, node, tset): - child_set = tset.children[node] - for var_dec in node.identifiers: - self.visit(var_dec, child_set) - - self.visit(node.body, child_set) - - @visitor.when(VarDeclarationNode) - def visit(self, node, tset): - typex = least_type(tset.locals[node.id], self.context) - node.type = typex - - if node.expr is not None: - self.visit(node.expr, tset) - - @visitor.when(IfNode) - def visit(self, node, tset): - self.visit(node.if_expr, tset) - self.visit(node.then_expr, tset) - self.visit(node.else_expr, tset) - - @visitor.when(WhileNode) - def visit(self, node, tset): - self.visit(node.condition, tset) - self.visit(node.body, tset) - - @visitor.when(CaseNode) - def visit(self, node, tset): - self.visit(node.expr, tset) - - for item in node.case_items: - self.visit(item, tset.children[item]) - - @visitor.when(CaseItemNode) - def visit(self, node, tset): - typex = least_type(tset.locals[node.id], self.context) - node.type = typex - self.visit(node.expr, tset) - - @visitor.when(CallNode) - def visit(self, node, tset): - for arg in node.args: - self.visit(arg, tset) - - @visitor.when(BlockNode) - def visit(self, node, tset): - for expr in node.expression_list: - self.visit(expr, tset) - - @visitor.when(AtomicNode) - def visit(self, node, tset): - pass - - @visitor.when(UnaryNode) - def visit(self, node, tset): - self.visit(node.expr, tset) - - @visitor.when(BinaryNode) - def visit(self, node, tset): - self.visit(node.left, tset) - self.visit(node.right, tset) diff --git a/src/tsets_reducer.py b/src/tsets_reducer.py deleted file mode 100644 index 55f2acb0a..000000000 --- a/src/tsets_reducer.py +++ /dev/null @@ -1,311 +0,0 @@ -import src.cmp.visitor as visitor -import src.cmp.nbpackage -import src.cmp.visitor as visitor - -from src.tset import Tset -from src.cmp.semantic import ( - ObjectType, - IntType, - StringType, - VoidType, - BoolType, - ErrorType, - AutoType, - SelfType, - SemanticError, -) -from src.ast_nodes import Node, ProgramNode, ExpressionNode -from src.ast_nodes import ClassDeclarationNode, FuncDeclarationNode, AttrDeclarationNode -from src.ast_nodes import VarDeclarationNode, AssignNode, CallNode -from src.ast_nodes import ( - AtomicNode, - UnaryNode, - BinaryNode, - ArithmeticOperation, - ComparisonOperation, - IfNode, - LetNode, - CaseNode, - CaseItemNode, - WhileNode, - BlockNode, - IsvoidNode, -) -from src.ast_nodes import ( - ConstantNumNode, - VariableNode, - InstantiateNode, - PlusNode, - MinusNode, - StarNode, - DivNode, - NegNode, - NotNode, - EqualNode, - BooleanNode, - StringNode, -) -from src.cmp.utils import find_least_type, union, intersection, reduce_set - - -class TSetReducer: - def __init__(self, context, errors=[]): - self.context = context - self.current_type = None - self.current_method = None - self.errors = errors - - def get_autotype_set(self): - return {self.context.types.keys()} - - @visitor.on("node") - def visit(self, node, tset): - pass - - @visitor.when(ProgramNode) - def visit(self, node, tset): - backup_tset = Tset() - while not backup_tset.compare(tset): - backup_tset = tset.clone() - - for declaration in node.declarations: - self.visit(declaration, tset.children[declaration]) - - tset.clean() - return tset - - @visitor.when(ClassDeclarationNode) - def visit(self, node, tset): - tset.locals["self"] = {node.id} - self.current_type = self.context.get_type(node.id) - for feature in node.features: - self.visit(feature, tset) - - @visitor.when(AttrDeclarationNode) - def visit(self, node, tset): - if node.init_exp is not None: - init_expr_set = self.visit(node.init_exp, tset) - tset.locals[node.id] = reduce_set(tset.locals[node.id], init_expr_set) - return tset.locals[node.id] - - return tset.locals[node.id] - - @visitor.when(FuncDeclarationNode) - def visit(self, node, tset): - method = self.current_type.get_method(node.id) - self.current_method = method - - current_tset = tset.children[node] - body_set = self.visit(node.body, current_tset) - tset.locals[node.id] = reduce_set(tset.locals[node.id], body_set) - method.tset = current_tset - - @visitor.when(AssignNode) - def visit(self, node, tset): - expr_set = self.visit(node.expr, tset) - var_set = tset.find_set(node.id) - var_set[node.id] = reduce_set(var_set[node.id], expr_set) - return var_set[node.id] - - @visitor.when(LetNode) - def visit(self, node, tset): - current_tset = tset.children[node] - for var_dec in node.identifiers: - self.visit(var_dec, current_tset) - - return self.visit(node.body, current_tset) - - @visitor.when(VarDeclarationNode) - def visit(self, node, tset): - if node.expr is not None: - expr_set = self.visit(node.expr, tset) - tset.locals[node.id] = reduce_set(tset.locals[node.id], expr_set) - - return tset.locals[node.id] - - @visitor.when(IfNode) - def visit(self, node, tset): - self.visit(node.if_expr, tset) - if isinstance(node.if_expr, VariableNode): - tset_locals = tset.find_set(node.if_expr.lex) - tset_locals[node.if_expr.lex] = reduce_set( - tset_locals[node.if_expr.lex], {"Bool"} - ) - then_expr_set = self.visit(node.then_expr, tset) - else_expr_set = self.visit(node.else_expr, tset) - - solve = intersection(then_expr_set, else_expr_set) - if len(solve) == 0: - solve = union(then_expr_set, else_expr_set) - - return solve - - @visitor.when(WhileNode) - def visit(self, node, tset): - self.visit(node.condition, tset) - - if isinstance(node.condition, VariableNode): - node_id = node.condition.lex - tset_locals = tset.find_set(node_id) - tset_locals[node_id] = reduce_set(tset_locals[node_id], {"Bool"}) - - self.visit(node.body, tset) - - return {"Object"} - - @visitor.when(CaseNode) - def visit(self, node, tset): - self.visit(node.expr, tset) - - union_set = set() - for item in node.case_items: - item_set = self.visit(item, tset.children[item]) - union_set = union(union_set, item_set) - - # current_type = None - # for item in union_set: - # if item == "!static_type_declared": - # continue - # item_type = self.context.get_type(item) - # current_type = find_least_type(current_type, item_type, self.context) - - # return {current_type.name} - - return union_set - - @visitor.when(CaseItemNode) - def visit(self, node, tset): - expr_tset = self.visit(node.expr, tset) - # tset.locals[node.id] = reduce_set(tset.locals[node.id], expr_tset) - # return tset.locals[node.id] - return expr_tset - - @visitor.when(CallNode) - def visit(self, node, tset): - args_set = {} - for expr in node.args: - args_set[expr] = self.visit(expr, tset) - - if node.obj is not None: - expr_set = self.visit(node.obj, tset) - else: - expr_set = {self.current_type.name} - - types_with_method = set() - method = None - if node.at_type is not None: - types_with_method.add(node.at_type) - method = self.context.get_type(node.at_type).get_method(node.id) - - else: - for typex in self.context.types.values(): - try: - method = typex.get_method(node.id) - if len(method.param_names) == len(node.args): - types_with_method.add(typex.name) - except SemanticError: - continue - - if len(types_with_method) == 1: - for arg, param in zip(node.args, method.param_names): - method.tset.locals[param] = reduce_set( - method.tset.locals[param], args_set[arg] - ) - if isinstance(arg, VariableNode): - arg_locals = tset.find_set(arg.lex) - arg_locals[arg.lex] = reduce_set( - arg_locals[arg.lex], method.tset.locals[param] - ) - - if isinstance(node.obj, VariableNode): - node_id = node.obj.lex - tset_locals = tset.find_set(node_id) - - tset_locals[node_id] = reduce_set(tset_locals[node_id], types_with_method) - - types_reduced = intersection(expr_set, types_with_method) - - if len(types_reduced) == 0: - return {"InferenceError"} - - return_types = set() - for item in types_reduced: - item_type = self.context.get_type(item) - method = item_type.get_method(node.id) - for typex in method.tset.parent.locals[node.id]: - return_types.add(typex) - - # ------- Despues de la entrega!!!!!!! - if "SELF_TYPE" in return_types: - return_types.remove("SELF_TYPE") - return_types = union(return_types, expr_set) - # ------------------------------- - return return_types - - @visitor.when(BlockNode) - def visit(self, node, tset): - current_set = None - for expr in node.expression_list: - current_set = self.visit(expr, tset) - - return current_set - - @visitor.when(InstantiateNode) # NewNode - def visit(self, node, tset): - return {node.lex} - - @visitor.when(IsvoidNode) - def visit(self, node, tset): - self.visit(node.expr, tset) - return {"Bool"} - - @visitor.when(BinaryNode) - def visit(self, node, tset): - self.visit(node.left, tset) - self.visit(node.right, tset) - - int_set = {"Int"} - if isinstance(node.left, VariableNode): - node_id = node.left.lex - tset_locals = tset.find_set(node_id) - tset_locals[node_id] = reduce_set(tset_locals[node_id], int_set) - - if isinstance(node.right, VariableNode): - node_id = node.right.lex - tset_locals = tset.find_set(node_id) - tset_locals[node_id] = reduce_set(tset_locals[node_id], int_set) - - return int_set - - @visitor.when(EqualNode) - def visit(self, node, tset): - self.visit(node.left, tset) - self.visit(node.right, tset) - - @visitor.when(NotNode) - def visit(self, node, tset): - self.visit(node.expr, tset) - return {"Bool"} - - @visitor.when(NegNode) - def visit(self, node, tset): - self.visit(node.expr, tset) - return {"Int"} - - @visitor.when(ConstantNumNode) - def visit(self, node, tset): - return {"Int"} - - @visitor.when(VariableNode) - def visit(self, node, tset): - tset_locals = tset.find_set(node.lex) - return tset_locals[node.lex] - - @visitor.when(StringNode) - def visit(self, node, tset): - return {"String"} - - @visitor.when(BooleanNode) - def visit(self, node, tset): - return {"Bool"} - diff --git a/src/type_builder.py b/src/type_builder.py index ed0f0119c..29a52848d 100644 --- a/src/type_builder.py +++ b/src/type_builder.py @@ -1,21 +1,23 @@ -from src.cmp.semantic import SemanticError -from src.cmp.semantic import Attribute, Method, Type -from src.cmp.semantic import VoidType, IntType, ErrorType, StringType, BoolType -from src.cmp.semantic import Context -from src.ast_nodes import ( +import copy +from cmp.semantic import SemanticError +from cmp.semantic import Attribute, Method, Type +from cmp.semantic import VoidType, IntType, ErrorType, StringType, BoolType +from cmp.semantic import Context +from ast_nodes import ( ProgramNode, ClassDeclarationNode, AttrDeclarationNode, FuncDeclarationNode, ) -import src.cmp.visitor as visitor -from src.tset import Tset +import cmp.visitor as visitor +from tset import Tset from collections import deque +from cool_visitor import CopyVisitor class TypeBuilder: - def __init__(self, context, errors=[]): - self.context = context + def __init__(self, errors=[]): + self.context = None self.current_type = None self.errors = errors @@ -25,7 +27,8 @@ def visit(self, node): @visitor.when(ProgramNode) def visit(self, node): - # Despues de entregar!!!!!! + self.context = copy.copy(node.context) + io_type = self.context.get_type("IO") self_type = self.context.get_type("SELF_TYPE") int_type = self.context.get_type("Int") @@ -53,7 +56,7 @@ def visit(self, node): method = io_type.define_method("in_int", [], [], int_type) method.tset = Tset(parent_tset) - # -------String + # String parent_tset = Tset() parent_tset.locals["concat"] = {"String"} parent_tset.locals["substr"] = {"String"} @@ -88,8 +91,6 @@ def visit(self, node): method = object_type.define_method("copy", [], [], self_type) method.tset = Tset(parent_tset) - # -------------------- - # ------checking for in order definitions and cyclic heritage parent_child_dict = {} queue = deque() @@ -150,6 +151,17 @@ def visit(self, node): # for declaration in node.declarations: # self.visit(declaration) + copy_visitor = CopyVisitor() + newAst = copy_visitor.visit(node) + newAst.context = self.context + + # Reset state + self.context = None + self.current_type = None + self.errors = None + + return newAst + @visitor.when(ClassDeclarationNode) def visit(self, node): # print(f"------------visiting class {node.id}------------") diff --git a/src/type_checker.py b/src/type_checker.py index d8b9cf83e..16c0159e4 100644 --- a/src/type_checker.py +++ b/src/type_checker.py @@ -1,10 +1,10 @@ -import src.cmp.nbpackage -import src.cmp.visitor as visitor +import cmp.nbpackage +import cmp.visitor as visitor -from src.ast_nodes import Node, ProgramNode, ExpressionNode -from src.ast_nodes import ClassDeclarationNode, FuncDeclarationNode, AttrDeclarationNode -from src.ast_nodes import VarDeclarationNode, AssignNode, CallNode -from src.ast_nodes import ( +from ast_nodes import Node, ProgramNode, ExpressionNode +from ast_nodes import ClassDeclarationNode, FuncDeclarationNode, AttrDeclarationNode +from ast_nodes import VarDeclarationNode, AssignNode, CallNode +from ast_nodes import ( AtomicNode, BinaryNode, ArithmeticOperation, @@ -17,7 +17,7 @@ BlockNode, IsvoidNode, ) -from src.ast_nodes import ( +from ast_nodes import ( ConstantNumNode, VariableNode, InstantiateNode, @@ -31,15 +31,15 @@ BooleanNode, StringNode, ) -from src.cool_visitor import FormatVisitor +from cool_visitor import FormatVisitor -from src.cmp.semantic import SemanticError -from src.cmp.semantic import Attribute, Method, Type -from src.cmp.semantic import VoidType, ErrorType, IntType -from src.cmp.semantic import Context +from cmp.semantic import SemanticError +from cmp.semantic import Attribute, Method, Type +from cmp.semantic import VoidType, ErrorType, IntType +from cmp.semantic import Context -from src.cmp.semantic import Scope -from src.cmp.utils import find_least_type +from cmp.semantic import Scope +from cmp.utils import find_least_type WRONG_SIGNATURE = 'Method "%s" already defined in "%s" with a different signature.' SELF_IS_READONLY = 'Variable "self" is read-only.' @@ -50,21 +50,27 @@ class TypeChecker: - def __init__(self, context, errors=[]): - self.context = context + def __init__(self, errors=[]): + self.context = None self.current_type = None self.current_method = None self.errors = errors @visitor.on("node") - def visit(self, node, scope): + def visit(self, node, scope=None): pass @visitor.when(ProgramNode) - def visit(self, node, scope=None): + def visit(self, node): scope = Scope() + self.context = node.context.copy() for declaration in node.declarations: self.visit(declaration, scope.create_child()) + + self.context = None + self.current_type = None + self.current_method = None + return scope @visitor.when(ClassDeclarationNode) @@ -452,4 +458,3 @@ def visit(self, node, scope): @visitor.when(BooleanNode) def visit(self, node, scope): return self.context.get_type("Bool") - diff --git a/src/type_collector.py b/src/type_collector.py index f57d94527..2f5dfc503 100644 --- a/src/type_collector.py +++ b/src/type_collector.py @@ -1,6 +1,6 @@ -from src.cmp.semantic import SemanticError -from src.cmp.semantic import Attribute, Method, Type -from src.cmp.semantic import ( +from cmp.semantic import SemanticError +from cmp.semantic import Attribute, Method, Type +from cmp.semantic import ( VoidType, IntType, ErrorType, @@ -11,9 +11,10 @@ SelfType, IOType, ) -from src.cmp.semantic import Context -from src.ast_nodes import ProgramNode, ClassDeclarationNode -import src.cmp.visitor as visitor +from cmp.semantic import Context +from ast_nodes import ProgramNode, ClassDeclarationNode +import cmp.visitor as visitor +from cool_visitor import CopyVisitor class TypeCollector(object): @@ -28,15 +29,14 @@ def visit(self, node): @visitor.when(ProgramNode) def visit(self, node): self.context = Context() + # TODO: Es necesario crear estos tipos especificos? self.context.types["Object"] = ObjectType() self.context.types["Int"] = IntType() self.context.types["String"] = StringType() self.context.types["Bool"] = BoolType() self.context.types["AUTO_TYPE"] = AutoType() self.context.types["SELF_TYPE"] = SelfType() - # Despues de entregar!!!!! self.context.types["IO"] = IOType() - # ------------------- object_type = self.context.get_type("Object") for typex in self.context.types.values(): @@ -47,6 +47,16 @@ def visit(self, node): for declaration in node.declarations: self.visit(declaration) + copy_visitor = CopyVisitor() + newAst = copy_visitor.visit(node) + newAst.context = self.context + + # Reset state + self.context = None + self.errors = None + + return newAst + @visitor.when(ClassDeclarationNode) def visit(self, node): try: diff --git a/src/ui.py b/src/ui.py deleted file mode 100644 index d0ceb8102..000000000 --- a/src/ui.py +++ /dev/null @@ -1,127 +0,0 @@ -from src.cmp.pycompiler import ( - Symbol, - NonTerminal, - Terminal, - EOF, - Sentence, - SentenceList, - Epsilon, - Production, - Grammar, -) -import graphviz -import streamlit as st -from pandas import DataFrame -from src.shift_reduce_parsers import ShiftReduceParser - - -def print_array(array): - for item in array: - st.write(str(item)) - - -def print_tset(tset): - output = [] - - for key, value in tset.locals.items(): - # output.append("\_" + str(key) + ":" + str(value) + "\n") - # output.append(f"\\__ {key} : {value} aaa") - - st.write("\\__" + str(key) + ":" + str(value)) - for key, child in tset.children.items(): - # output += "\n" - try: - # output.append(key.id + "--->") - # output.append(f"{key.id}---> eee") - st.write(key.id + "--->") - except AttributeError: - # output.append("let or case --->iii") - st.write("let or case --->") - # output += "\n" - # output.append(str(chil)) - # output.append(f"{print_tset(child)} ooo") - print_tset(child) - - # st.write(str(chil)) - # for item in output: - # st.write(item) - - -def print_grammar(G): - st.subheader("Simbolo distinguido") - st.write(G.startSymbol.Name) - - st.subheader("Terminales") - for t in G.terminals: - st.write(t.Name) - - st.subheader("No Terminales") - for nt in G.nonTerminals: - st.write(nt.Name) - - st.subheader("Producciones") - for p in G.Productions: - st.write(p.__repr__()) - - -def table_to_dataframe_ll(table): - d = {} - for (state, symbol), value in table.items(): - # value = encode_value(value) - try: - d[state][symbol] = value.__repr__() - except KeyError: - d[state] = {symbol: value.__repr__()} - - return DataFrame.from_dict(d, orient="index", dtype=str) - - -def encode_value(value): - try: - action, tag = value - if action == ShiftReduceParser.SHIFT: - return "S" + str(tag) - elif action == ShiftReduceParser.REDUCE: - return repr(tag) - elif action == ShiftReduceParser.OK: - return action - else: - return value - except TypeError: - return value - - -def table_to_dataframe(table): - d = {} - for (state, symbol), value in table.items(): - value = encode_value(value) - try: - d[state][symbol] = value - except KeyError: - d[state] = {symbol: value} - - return DataFrame.from_dict(d, orient="index", dtype=str) - - -# def print_automaton(nfa): -# graph = graphviz.Digraph() - -# if nfa.start not in nfa.finals: -# graph.attr("node", shape="diamond") -# graph.node(str(nfa.start)) - -# graph.attr("node", shape="doublecircle") -# for f in nfa.finals: -# graph.node(str(f)) - -# graph.attr("node", shape="circle") -# for (start, tran), destination in nfa.map.items(): -# tran = "e" if tran == "" else tran -# for state in destination: -# if tran == "%" or tran == "none": -# continue -# graph.edge( -# str(start), str(state), label=tran, -# ) - -# st.graphviz_chart(graph) From fa0b9ddb03e0aa1dfc69f63c4d809d8cd1359030 Mon Sep 17 00:00:00 2001 From: gabriela Date: Tue, 22 Feb 2022 00:32:52 -0500 Subject: [PATCH 035/162] Fix line Lines are detected where no strings are involve. Column no. still need to be reviewed. --- customized_tests/lexer/no_strings.cl | 9 ++ customized_tests/lexer/test_comment.cl | 15 +++ customized_tests/lexer/tryNoSymbol.cl | 9 ++ requirements.txt | 4 + src/coolc.sh | 2 +- src/lexical_analizer.py | 14 ++- src/tokens_rules.py | 128 ++++++++++++++++++------- 7 files changed, 143 insertions(+), 38 deletions(-) create mode 100644 customized_tests/lexer/no_strings.cl create mode 100644 customized_tests/lexer/test_comment.cl create mode 100644 customized_tests/lexer/tryNoSymbol.cl diff --git a/customized_tests/lexer/no_strings.cl b/customized_tests/lexer/no_strings.cl new file mode 100644 index 000000000..bedf7bd00 --- /dev/null +++ b/customized_tests/lexer/no_strings.cl @@ -0,0 +1,9 @@ +" +class Cons { + xcar : Int ; + xcdr : String ; + + isNill ( ) : Bool { + false + } ; +} \ No newline at end of file diff --git a/customized_tests/lexer/test_comment.cl b/customized_tests/lexer/test_comment.cl new file mode 100644 index 000000000..6283574f5 --- /dev/null +++ b/customized_tests/lexer/test_comment.cl @@ -0,0 +1,15 @@ +--Any characters between two dashes “--” and the next newline +--(or EOF, if there is no next newline) are treated as comments + +(*(*(* +Comments may also be written by enclosing +text in (∗ . . . ∗). The latter form 8 of comment may be nested. +Comments cannot cross file boundaries. +*)*)*) + +class Error() { + + (* case There was once a comment, + that was quite long. + But, the. Now, reader; is the comment + ever gonna end? \ No newline at end of file diff --git a/customized_tests/lexer/tryNoSymbol.cl b/customized_tests/lexer/tryNoSymbol.cl new file mode 100644 index 000000000..d9a423eb5 --- /dev/null +++ b/customized_tests/lexer/tryNoSymbol.cl @@ -0,0 +1,9 @@ +# +class Cons { + xcar : Int ; + xcdr : String ; + + isNill ( ) : Bool { + false + } ; +} \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 9eb0cad1a..9c1764f20 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,6 @@ pytest pytest-ordering +typer +ply +ipython +nbformat \ No newline at end of file diff --git a/src/coolc.sh b/src/coolc.sh index d3cf16bd2..a20fe82b5 100755 --- a/src/coolc.sh +++ b/src/coolc.sh @@ -9,4 +9,4 @@ echo "Copyright (c) 2022: Amalia_Ibarra, Sandra_Martos, Gabriela_Martinez" # Llamar al compilador echo "Compiling $INPUT_FILE into $OUTPUT_FILE" -python -m main $@ \ No newline at end of file +python3 -m main $@ \ No newline at end of file diff --git a/src/lexical_analizer.py b/src/lexical_analizer.py index cf9769988..c5de0dec9 100644 --- a/src/lexical_analizer.py +++ b/src/lexical_analizer.py @@ -18,9 +18,13 @@ def pprint_tokens(tokens): print(" ".join([str(t.token_type) for t in pending])) -def tokenize_cool_text(grammar, idx, string, num, data, errors, printing=False): - lexer = lex.lex(module=tokens_rules) - lexer.errors = errors +def tokenize_cool_text(grammar, idx, string, num, data, errors, printing=True): + # lexer starts with: lexpos = 0, lineno = 1, last_new_line = 0 + # lexpos Within token rule functions, this points to the first character after the matched text. + lexer = lex.lex(module = tokens_rules) + # lexer.lineno = 0# check if this cause any problems + lexer.last_new_line_pos = 0#no matter the index that it uses + lexer.errors = errors # Give the lexer some input lexer.input(data) @@ -30,6 +34,9 @@ def tokenize_cool_text(grammar, idx, string, num, data, errors, printing=False): for t in grammar.terminals if t not in {idx, string, num} } + print("First element") + print(lexer.token().value) + print("finito first elem") tokens = [] # Tokenize @@ -54,4 +61,5 @@ def tokenize_cool_text(grammar, idx, string, num, data, errors, printing=False): if printing: pprint_tokens(tokens) + # print(tokens[0].lex) return tokens diff --git a/src/tokens_rules.py b/src/tokens_rules.py index 775443409..3b248c9c9 100644 --- a/src/tokens_rules.py +++ b/src/tokens_rules.py @@ -23,6 +23,14 @@ # All lexers must provide a list tokens that defines all of the possible token names # that can be produced by the lexer. +# first_tokens = [ +# "larrow", +# "rarrow", +# "lessequal", +# "id", +# "int", +# "string", +# ] first_tokens = [ "larrow", "rarrow", @@ -30,8 +38,9 @@ "id", "int", "string", + "ccom" ] - + reserved = { "class": "class", "inherits": "inherits", @@ -76,7 +85,7 @@ tokens = first_tokens + list(reserved.values()) # Match the first (*. Enter comments state. -def t_comments(t): +def t_begin_comments(t): r"\(\*" t.lexer.code_start = t.lexer.lexpos # Record the starting position t.lexer.level = 1 # Initial level @@ -89,17 +98,37 @@ def t_comments_opsymb(t): r"\(\*" t.lexer.level += 1 +# Define a rule so we can track line numbers +def t_comments_newline(t): + r"\n" + # t.lexer.lineno += len(t.value) + t.lexer.last_new_line_pos = t.lexer.lexpos + t.lexer.lineno += 1 +# t_foo_end(t) # Comments closing symbol -def t_comments_clsymb(t): +# def t_comments_clsymb(t): +def t_comments_ccom(t): r"\*\)" t.lexer.level -= 1 if t.lexer.level == 0: - t.value = t.lexer.lexdata[t.lexer.code_start : t.lexer.lexpos + 1] - t.lexer.lineno += t.value.count("\n") + # t.value = t.lexer.lexdata[t.lexer.code_start : t.lexer.lexpos + 1] + t.value = t.lexer.lexdata[t.lexer.code_start : t.lexer.lexpos -2] # comments should not be returned, just skipped + t.type = "ccom" + # t.lexer.lineno += t.value.count("\n") + # t.lexer.lineno +=1#after the last closing symbol add new line t.lexer.begin("INITIAL") - + return t + +def t_comments_any(t): +# def t_ccode_nonspace(t): + r'[^\s\{\}\'\"]+' + # r'^[^ \n]+$' + # r"\.*" + print("ANY") + print(t.lexer.lexdata[t.lexer.lexpos -1]) + # t.lexer.skip(1) # For bad characters. In this case we just skip over everything but (* or *) def t_comments_error(t): @@ -110,6 +139,8 @@ def t_comments_error(t): # "Illegal character inside comment", # ) # ) + # print("character skipped") + print(t.lexer.lexdata[t.lexer.lexpos -1]) t.lexer.skip(1) @@ -117,19 +148,18 @@ def t_comments_error(t): def t_comments_eof(t): if t.lexer.level > 0: # guardar este error y actuar acorde # print(f"code_start{t.lexer.code_start}") - t.lexer.errors.append(LexicographicError(t.lexer.lineno, 0, "EOF in comment")) + t.lexer.errors.append(LexicographicError(t.lexer.lineno, t.lexer.lexpos - t.lexer.last_new_line_pos, "EOF in comment")) return None # Rules for initial state (default state) def t_id(t): - r"[a-zA-Z_][a-zA-Z_0-9]*" + r"[a-zA-Z][a-zA-Z_0-9]*" t.type = reserved.get( t.value, "id" ) # Check for reserved words. If it isn't a reserved word is categorized as identifier return t - # matching int numbers def t_int(t): r"\d+" @@ -156,37 +186,57 @@ def t_string(t): if text[index] == "\\": if text[index + 1] in ["t", "b", "f", "n"]: # string_to_append+=f'\\{text[index + 1]}' - string_list.append(text[index : index + 2]) # \t,\b,\f - elif text[index + 1] == "\n": # non scape \n whith \ before + string_list.append(text[index : index + 2]) # \t,\b,\f, \n + elif text[index + 1] == "\n": # \n whith \ before # string_to_append+='\n' + t.lexer.lineno +=1 + t.lexer.last_new_line_pos = index + 1# saving last \n string_list.append("\n") elif text[index + 1] == "0": # null character \0 is not allowed # print("Illegal character \\0 inside string") # do something about it + # t.lexer.errors.append( + # LexicographicError( + # t.lexer.lineno + text[initial : index + 1].count("\n"), + # index - t.lexer.last_new_line_pos + 2, + # "Illegal character \\0 inside string", + # ) + # ) t.lexer.errors.append( LexicographicError( - t.lexer.lineno + text[initial : index + 1].count("\n"), - 0, + t.lexer.lineno, + index - t.lexer.last_new_line_pos + 1, "Illegal character \\0 inside string", ) ) + t.lexer.lexpos = index+1 return t else: - string_list.append( + string_list.append(#CHEQUEAR PQ ESTO SE AHCE DOS VECES< COMO TRATAR DIFERENTE EL \n text[index : index + 2] ) # ]character c: take the character in \c # string_to_append += text[index + 1] index += 2 - elif text[index] == "\n": # \n whithout and extra \ is not allowed + elif text[index] == "\n": # non scape \n (whithout and extra \) is not allowed # print("Illegal character \\n inside string") # do something about it + # t.lexer.errors.append( + # LexicographicError( + # t.lexer.lineno + text[initial : index + 1].count("\n"), + # index - t.lexer.last_new_line_pos + 1, + # "Illegal character \\n inside string", + # ) + # ) t.lexer.errors.append( LexicographicError( - t.lexer.lineno + text[initial : index + 1].count("\n"), - 0, + t.lexer.lineno, + index - t.lexer.last_new_line_pos, "Illegal character \\n inside string", ) ) - index += 1 + t.lexer.lineno +=1 + t.lexer.last_new_line_pos = index# sabing last \n + # index += 1 + t.lexer.lexpos = index#new return t else: @@ -196,37 +246,47 @@ def t_string(t): if index == final: # print("String may not cross file boundaries") # do something about it + # t.lexer.errors.append( + # LexicographicError( + # t.lexer.lineno + text[initial : index + 1].count("\n"), + # t.lexer.lexpos - t.lexer.last_new_line_pos + 1, + # "String may not cross file boundaries", + # ) + # ) t.lexer.errors.append( LexicographicError( - t.lexer.lineno + text[initial : index + 1].count("\n"), - 0, + t.lexer.lineno, + index - t.lexer.last_new_line_pos, "String may not cross file boundaries", ) ) + #AQUI NO HACE FALTA ACTUALIZAR index antes? + t.lexer.lexpos = index return t else: - index += 1 - - t.value = "".join(string_list) - t.type = "string" - t.lexer.lexpos += index - initial - t.lexer.lineno += text[initial : index + 1].count("\n") - # print(t.value) - # print(string_to_append) - return t + # index += 1 + + t.value = "".join(string_list) + t.type = "string" + # t.lexer.lexpos += index - initial #RECIEND BORRADO + t.lexer.lexpos = index# en index se supone este el " de cerrar los comentarios + # t.lexer.lineno += text[initial : index + 1].count("\n") + # print(t.value) + # print(string_to_append) + return t # Define a rule so we can track line numbers def t_newline(t): - r"\n+" - t.lexer.lineno += len(t.value) - + r"\n" + # t.lexer.lineno += len(t.value) + t.lexer.last_new_line_pos = t.lexer.lexpos + t.lexer.lineno += 1 t_larrow = r"<-" t_rarrow = r"=>" t_lessequal = r"<=" - # A string containing ignored characters (spaces and tabs) t_ignore = " \t" @@ -236,7 +296,7 @@ def t_error(t): t.lexer.errors.append( LexicographicError( t.lexer.lineno, - 0, + t.lexer.lexpos - t.lexer.last_new_line_pos, f"ERROR {t.value[0]}", ) ) From 8637267b2542ee78e70bedcc626a23a032a10cbc Mon Sep 17 00:00:00 2001 From: gabriela Date: Tue, 22 Feb 2022 00:54:24 -0500 Subject: [PATCH 036/162] Fix part of column number. Fix column number. in code with no strings. --- src/tokens_rules.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/tokens_rules.py b/src/tokens_rules.py index 3b248c9c9..09872412c 100644 --- a/src/tokens_rules.py +++ b/src/tokens_rules.py @@ -126,8 +126,8 @@ def t_comments_any(t): r'[^\s\{\}\'\"]+' # r'^[^ \n]+$' # r"\.*" - print("ANY") - print(t.lexer.lexdata[t.lexer.lexpos -1]) + # print("ANY") + # print(t.lexer.lexdata[t.lexer.lexpos -1]) # t.lexer.skip(1) # For bad characters. In this case we just skip over everything but (* or *) @@ -140,7 +140,7 @@ def t_comments_error(t): # ) # ) # print("character skipped") - print(t.lexer.lexdata[t.lexer.lexpos -1]) + # print(t.lexer.lexdata[t.lexer.lexpos -1]) t.lexer.skip(1) @@ -292,11 +292,21 @@ def t_newline(t): # Error handling rule -def t_error(t): +def t_error(t):#for some reason here lexpos is the current character, maybe because it could not be matched + print("ERROR") + print(t.lexer.lexpos) + print(t.lexer.last_new_line_pos) + print("In lex pos") + print(t.lexer.lexdata[t.lexer.lexpos]) + print("In last new line pos") + print(t.lexer.lexdata[t.lexer.last_new_line_pos]) + print(t.lexer.lexdata[t.lexer.last_new_line_pos-1]) + + t.lexer.errors.append( LexicographicError( t.lexer.lineno, - t.lexer.lexpos - t.lexer.last_new_line_pos, + t.lexer.lexpos - t.lexer.last_new_line_pos + 1, f"ERROR {t.value[0]}", ) ) From cee4adc0a0162a92581190c12b0701e7a4cd3cba Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Tue, 22 Feb 2022 01:15:29 -0500 Subject: [PATCH 037/162] feat: add cil hierarchy and cil visitor COOL nodes visited: Program, ClassDeclaration, AttrDeclaration, FuncDeclaration, VarDeclaration, Assign, IfNode. --- src/code_gen/cil_builder.py | 402 ++++++++++++++++++++++++++++++++++++ src/code_gen/cil_nodes.py | 73 +++++++ src/coolc.sh | 2 +- 3 files changed, 476 insertions(+), 1 deletion(-) create mode 100644 src/code_gen/cil_builder.py create mode 100644 src/code_gen/cil_nodes.py diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py new file mode 100644 index 000000000..2c94a81e4 --- /dev/null +++ b/src/code_gen/cil_builder.py @@ -0,0 +1,402 @@ +import cmp.nbpackage +import cmp.visitor as visitor + +from ast_nodes import Node, ProgramNode, ExpressionNode +from ast_nodes import ClassDeclarationNode, FuncDeclarationNode, AttrDeclarationNode +from ast_nodes import VarDeclarationNode, AssignNode, CallNode +from ast_nodes import ( + AtomicNode, + BinaryNode, + ArithmeticOperation, + ComparisonOperation, + IfNode, + LetNode, + CaseNode, + CaseItemNode, + WhileNode, + BlockNode, + IsvoidNode, +) +from ast_nodes import ( + ConstantNumNode, + VariableNode, + InstantiateNode, + PlusNode, + MinusNode, + StarNode, + DivNode, + NegNode, + NotNode, + EqualNode, + BooleanNode, + StringNode, +) + +from cil_nodes import ( + StringCil, + TypeCil, + AttributeCil, + MethodCil, + ProgramCil, + FunctionCil, + ArgCil, + LocalCil, + AssignmentCil, + IfCil, + LabelCil, + GotoCil, +) +from cool_visitor import FormatVisitor + +from cmp.semantic import SemanticError +from cmp.semantic import Attribute, Method, Type +from cmp.semantic import VoidType, ErrorType, IntType +from cmp.semantic import Context + +from cmp.semantic import Scope +from cmp.utils import find_least_type + +WRONG_SIGNATURE = 'Method "%s" already defined in "%s" with a different signature.' +SELF_IS_READONLY = 'Variable "self" is read-only.' +LOCAL_ALREADY_DEFINED = 'Variable "%s" is already defined in method "%s".' +INCOMPATIBLE_TYPES = 'Cannot convert "%s" into "%s".' +VARIABLE_NOT_DEFINED = 'Variable "%s" is not defined in "%s".' +INVALID_OPERATION = 'Operation is not defined between "%s" and "%s".' + + +class CILBuilder: + def __init__(self, errors=[]): + self.types = [] + self.code = [] + self.data = [] + self.current_type = None + self.current_function = None + self.errors = errors + self.method_count = 0 + self.string_count = 0 + self.temp_vars_count = 0 + self._count = 0 + self.context = None + + def generate_next_method_id(self): + self.method_count += 1 + return "method_" + str(self.method_count) + + def generate_next_string_id(self): + self.string_count += 1 + return "string_" + str(self.string_count) + + def generate_next_tvar_id(self): + self.temp_vars_count += 1 + return "v_" + str(self.temp_vars_count) + + def next_id(self): + self._count += 1 + return str(self._count) + + @visitor.on("node") + def visit(self, node=None): + pass + + @visitor.when(ProgramNode) + def visit(self, node): + self.context = node.context + + for declaration in node.declarations: + self.visit(declaration) + + self.current_type = None + self.current_method = None + + return ProgramCil(self.types, self.data, self.code) + + @visitor.when(ClassDeclarationNode) + def visit(self, node): + self.current_type = TypeCil(node.id) + self.types.append(self.current_type) + + for feature in node.features: + self.visit(feature) + + @visitor.when(AttrDeclarationNode) + def visit(self, node): + # Add attribute to current type's list of attributes (cool type of the attribute is ignored) + self.current_type.attributes.append(AttributeCil(node.id)) + + # Visit initial expression + self.visit(node.init_exp) + + @visitor.when(FuncDeclarationNode) + def visit(self, node): + ref = self.generate_next_method_id() + self.current_type.methods.append(MethodCil(node.id, ref)) + + function = FunctionCil(ref) + for pname, _ in node.params: + function.args.append(ArgCil(pname)) + + self.current_function = function + self.code.append(function) + + self.visit(node.body) + + @visitor.when(VarDeclarationNode) + def visit(self, node): + # Add LOCAL variable + local = LocalCil(node.id) + self.current_function.locals.append(local) + + # Add Assignment Node + if node.expr: + expr = self.visit(node.expr) + self.current_function.body.append(AssignmentCil(local.id, expr)) + + @visitor.when(AssignNode) + def visit(self, node): + expr = self.visit(node.expr) + self.current_function.body.append(AssignmentCil(node.id, expr)) + + @visitor.when(CallNode) + def visit(self, node): + auto_type = self.context.get_type("AUTO_TYPE") + typex = None + if node.obj is not None: + typex = self.visit(node.obj) + if typex == auto_type: + return auto_type + + else: + typex = self.current_type + + method = None + try: + if node.at_type is not None: + node_at_type = self.context.get_type(node.at_type) + method = node_at_type.get_method(node.id) + if not typex.conforms_to(node_at_type): + self.errors.append( + f"The static type to the left of @ ({typex.name}) must conform to the type specified to the right of @ ({node_at_type.name}) " + ) + return ErrorType() + else: + method = typex.get_method(node.id) + except SemanticError as error: + self.errors.append(error.text) + return ErrorType() + + if len(method.param_names) != len(node.args): + self.errors.append( + f"There is no definition of {method.name} that takes {len(node.args)} arguments " + ) + + for arg, ptype in zip(node.args, method.param_types): + arg_type = self.visit(arg) + if not arg_type.conforms_to(ptype): + self.errors.append(INCOMPATIBLE_TYPES % (arg_type.name, ptype.name)) + + if method.return_type == self.context.get_type("SELF_TYPE"): + return typex + + return method.return_type + + @visitor.when(IfNode) + def visit(self, node): + # Temp variable to store value of if_expr + if_temp = self.generate_next_tvar_id() + self.current_function.locals.append(LocalCil(if_temp)) + + # Assign value + if_expr = self.visit(node.if_expr) + self.current_function.body.append(AssignmentCil(if_temp, if_expr)) + + # IF x GOTO label + then_label = "THEN_" + self.next_id() + self.current_function.body.append(IfCil(if_temp, then_label)) + + # Temp variable to store value of else_expr + self.visit(node.else_expr) + + # GOTO end_label + end_label = "END_IF_" + self.next_id() # Example: END_IF_120 + self.current_function.body.append(GotoCil(end_label)) + + # Then label + self.current_function.body.append(LabelCil(then_label)) + self.visit(node.then_expr) + + # end_label + self.current_function.body.append(LabelCil(end_label)) + + # TODO: return something? + + @visitor.when(WhileNode) + def visit(self, node): + condition_type = self.visit(node.condition) + bool_type = self.context.get_type("Bool") + + if condition_type != bool_type and condition_type.name != "AUTO_TYPE": + self.errors.append( + f"Expression after 'while' must be bool, current is {condition_type.name}" + ) + return ErrorType() + + return self.context.get_type("Object") + + @visitor.when(BlockNode) + def visit(self, node): + typex = None + for expr in node.expression_list: + typex = self.visit(expr) + + return typex + + @visitor.when(LetNode) + def visit(self, node): + + child_scope = scope.create_child() + + for var_dec in node.identifiers: + self.visit(var_dec, child_scope) + + return self.visit(node.body, child_scope) + + @visitor.when(CaseNode) + def visit(self, node): + self.visit(node.expr) + + current_case_type = None + for item in node.case_items: + child_scope = scope.create_child() + case_item_type = self.visit(item, child_scope) + current_case_type = find_least_type( + current_case_type, case_item_type, self.context + ) + + return current_case_type + + @visitor.when(CaseItemNode) + def visit(self, node): + try: + static_type = self.context.get_type(node.type) + scope.define_variable(node.id, static_type) + except SemanticError as e: + self.errors.append(e) + return ErrorType() + + typex = self.visit(node.expr) + + return typex + + @visitor.when(InstantiateNode) # NewNode + def visit(self, node): + try: + typex = self.context.get_type(node.lex) + if typex.name == "SELF_TYPE": + return self.current_type + + return typex + except SemanticError as error: + self.errors.append(error.text) + return ErrorType() + + @visitor.when(IsvoidNode) + def visit(self, node): + self.visit(node.expr) + return self.context.get_type("Bool") + + @visitor.when(ArithmeticOperation) + def visit(self, node): + int_type = self.context.get_type("Int") + left_type = self.visit(node.left) + right_type = self.visit(node.right) + + if (left_type != int_type and left_type.name != "AUTO_TYPE") or ( + right_type != int_type and right_type.name != "AUTO_TYPE" + ): + self.errors.append(INVALID_OPERATION % (left_type.name, right_type.name)) + + return int_type + + @visitor.when(ComparisonOperation) + def visit(self, node): + int_type = self.context.get_type("Int") + left_type = self.visit(node.left) + right_type = self.visit(node.right) + + if (left_type != int_type and left_type.name != "AUTO_TYPE") or ( + right_type != int_type and right_type.name != "AUTO_TYPE" + ): + self.errors.append(INVALID_OPERATION % (left_type.name, right_type.name)) + + return self.context.get_type("Bool") + + @visitor.when(EqualNode) + def visit(self, node): + int_type = self.context.get_type("Int") + string_type = self.context.get_type("String") + bool_type = self.context.get_type("Bool") + built_in_types = [int_type, string_type, bool_type] + + left_type = self.visit(node.left) + right_type = self.visit(node.right) + + if left_type in built_in_types or right_type in built_in_types: + if ( + left_type != right_type + and left_type.name != "AUTO_TYPE" + and right_type.name != "AUTO_TYPE" + ): + self.errors.append( + f"One of the expressions of '=' operator is of type Int, String or Bool, the other must have the same static type. Left type: {left_type.name}.Right type: {right_type.name}" + ) + + return self.context.get_type("Bool") + + @visitor.when(NotNode) + def visit(self, node): + bool_type = self.context.get_type("Bool") + typex = self.visit(node.expr) + + if typex != bool_type and not typex.name == "AUTO_TYPE": + self.errors.append( + f"Expression after 'not' must be Bool, current is {typex.name}" + ) + return ErrorType() + + return bool_type + + @visitor.when(NegNode) + def visit(self, node): + int_type = self.context.get_type("Int") + typex = self.visit(node.expr) + + if typex != int_type and not typex.name == "AUTO_TYPE": + self.errors.append( + f"Expression after '~' must be Int, current is {typex.name}" + ) + return ErrorType() + + return int_type + + @visitor.when(ConstantNumNode) + def visit(self, node): + return self.context.get_type("Int") + + @visitor.when(VariableNode) + def visit(self, node): + var = scope.find_variable(node.lex) + if var is None: + self.errors.append( + VARIABLE_NOT_DEFINED % (node.lex, self.current_method.name) + ) + return ErrorType() + return var.type + + @visitor.when(StringNode) + def visit(self, node): + idx = "str_" + self.generate_next_id() + self.data.append(StringCil(idx, node.lex)) + + @visitor.when(BooleanNode) + def visit(self, node): + return self.context.get_type("Bool") diff --git a/src/code_gen/cil_nodes.py b/src/code_gen/cil_nodes.py new file mode 100644 index 000000000..0a45199cc --- /dev/null +++ b/src/code_gen/cil_nodes.py @@ -0,0 +1,73 @@ +class CIL_Node: + pass + + +class ProgramCil(CIL_Node): + def __init__(self, types, data, code): + self.types = types + self.data = data + self.code = code + + +class TypeCil(CIL_Node): + def __init__(self, idx, attributes=[], methods=[]): + self.id = idx + self.attributes = attributes + self.methods = methods + + +class AttributeCil(CIL_Node): + def __init__(self, idx): + self.id = idx + + +class MethodCil(CIL_Node): + def __init__(self, idx, ref): + self.id = idx + self.ref = ref + + +class FunctionCil(CIL_Node): + def __init__(self, idx, args=[], localsx=[], body=[]): + self.id = idx + self.args = args + self.locals = localsx + self.body = body + + +class IfCil(CIL_Node): + def __init__(self, condition, label): + self.condition = condition + self.label = label + + +class ArgCil(CIL_Node): + def __init__(self, idx): + self.id = idx + + +class LocalCil(CIL_Node): + def __init__(self, idx): + self.id = idx + + +class AssignmentCil(CIL_Node): + def __init__(self, idx, expr): + self.id = idx + self.expr = expr + + +class StringCil(CIL_Node): + def __init__(self, idx: str, text: str): + self.id = idx + self.text = text + + +class LabelCil(CIL_Node): + def __init__(self, idx): + self.id = idx + + +class GotoCil(CIL_Node): + def __init__(self, label): + self.label = label diff --git a/src/coolc.sh b/src/coolc.sh index d3cf16bd2..a20fe82b5 100755 --- a/src/coolc.sh +++ b/src/coolc.sh @@ -9,4 +9,4 @@ echo "Copyright (c) 2022: Amalia_Ibarra, Sandra_Martos, Gabriela_Martinez" # Llamar al compilador echo "Compiling $INPUT_FILE into $OUTPUT_FILE" -python -m main $@ \ No newline at end of file +python3 -m main $@ \ No newline at end of file From 24293d37a67e89b55c2c228c8095eb31c5b350e8 Mon Sep 17 00:00:00 2001 From: gabriela Date: Tue, 22 Feb 2022 01:31:27 -0500 Subject: [PATCH 038/162] Fix columns. Columns are correctly reported. --- src/tokens_rules.py | 42 ++++++++++++++++-------------------------- 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/src/tokens_rules.py b/src/tokens_rules.py index 09872412c..4f7b4a599 100644 --- a/src/tokens_rules.py +++ b/src/tokens_rules.py @@ -148,7 +148,7 @@ def t_comments_error(t): def t_comments_eof(t): if t.lexer.level > 0: # guardar este error y actuar acorde # print(f"code_start{t.lexer.code_start}") - t.lexer.errors.append(LexicographicError(t.lexer.lineno, t.lexer.lexpos - t.lexer.last_new_line_pos, "EOF in comment")) + t.lexer.errors.append(LexicographicError(t.lexer.lineno, t.lexer.lexpos - t.lexer.last_new_line_pos + 1, "EOF in comment")) return None @@ -182,17 +182,17 @@ def t_string(t): initial = t.lexer.lexpos index = t.lexer.lexpos final = len(text) - while index < final and text[index] != '"': - if text[index] == "\\": + while index < final and text[index] != '\"': + if text[index] == '\\': if text[index + 1] in ["t", "b", "f", "n"]: # string_to_append+=f'\\{text[index + 1]}' string_list.append(text[index : index + 2]) # \t,\b,\f, \n - elif text[index + 1] == "\n": # \n whith \ before + elif text[index + 1] == '\n': # \n whith \ before # string_to_append+='\n' t.lexer.lineno +=1 - t.lexer.last_new_line_pos = index + 1# saving last \n - string_list.append("\n") - elif text[index + 1] == "0": # null character \0 is not allowed + t.lexer.last_new_line_pos = index + 2# saving last \n + string_list.append('\n') + elif text[index + 1] == '0': # null character \0 is not allowed SACAR Y PONER EN UNA IDENTACION MAS AFUERA # print("Illegal character \\0 inside string") # do something about it # t.lexer.errors.append( # LexicographicError( @@ -204,11 +204,11 @@ def t_string(t): t.lexer.errors.append( LexicographicError( t.lexer.lineno, - index - t.lexer.last_new_line_pos + 1, + index - t.lexer.last_new_line_pos + 2, "Illegal character \\0 inside string", ) ) - t.lexer.lexpos = index+1 + t.lexer.lexpos = index+2 return t else: string_list.append(#CHEQUEAR PQ ESTO SE AHCE DOS VECES< COMO TRATAR DIFERENTE EL \n @@ -217,7 +217,7 @@ def t_string(t): # string_to_append += text[index + 1] index += 2 - elif text[index] == "\n": # non scape \n (whithout and extra \) is not allowed + elif text[index] == '\n': # non scape \n (whithout and extra \) is not allowed # print("Illegal character \\n inside string") # do something about it # t.lexer.errors.append( # LexicographicError( @@ -229,14 +229,14 @@ def t_string(t): t.lexer.errors.append( LexicographicError( t.lexer.lineno, - index - t.lexer.last_new_line_pos, + index - t.lexer.last_new_line_pos + 1, "Illegal character \\n inside string", ) ) t.lexer.lineno +=1 - t.lexer.last_new_line_pos = index# sabing last \n + t.lexer.last_new_line_pos = index + 1# sabing last \n # index += 1 - t.lexer.lexpos = index#new + t.lexer.lexpos = index + 1#new return t else: @@ -256,7 +256,7 @@ def t_string(t): t.lexer.errors.append( LexicographicError( t.lexer.lineno, - index - t.lexer.last_new_line_pos, + index - t.lexer.last_new_line_pos + 1, "String may not cross file boundaries", ) ) @@ -264,7 +264,7 @@ def t_string(t): t.lexer.lexpos = index return t else: - # index += 1 + index += 1#jumping '\"' character t.value = "".join(string_list) t.type = "string" @@ -278,7 +278,7 @@ def t_string(t): # Define a rule so we can track line numbers def t_newline(t): - r"\n" + r'\n' # t.lexer.lineno += len(t.value) t.lexer.last_new_line_pos = t.lexer.lexpos t.lexer.lineno += 1 @@ -293,16 +293,6 @@ def t_newline(t): # Error handling rule def t_error(t):#for some reason here lexpos is the current character, maybe because it could not be matched - print("ERROR") - print(t.lexer.lexpos) - print(t.lexer.last_new_line_pos) - print("In lex pos") - print(t.lexer.lexdata[t.lexer.lexpos]) - print("In last new line pos") - print(t.lexer.lexdata[t.lexer.last_new_line_pos]) - print(t.lexer.lexdata[t.lexer.last_new_line_pos-1]) - - t.lexer.errors.append( LexicographicError( t.lexer.lineno, From 11a67c40085ffbe38d768b3c5c84511655e4245b Mon Sep 17 00:00:00 2001 From: gabriela Date: Tue, 22 Feb 2022 17:51:20 -0500 Subject: [PATCH 039/162] Ignore { } characters in comments. --- src/tokens_rules.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tokens_rules.py b/src/tokens_rules.py index 4f7b4a599..bd2a0c8f4 100644 --- a/src/tokens_rules.py +++ b/src/tokens_rules.py @@ -123,7 +123,8 @@ def t_comments_ccom(t): def t_comments_any(t): # def t_ccode_nonspace(t): - r'[^\s\{\}\'\"]+' + # r'[^\s\{\}\'\"]+' + r'[^\s\'\"]+' # r'^[^ \n]+$' # r"\.*" # print("ANY") From 4a5f65be9a011b91049793cc3c0ca75c6caed784 Mon Sep 17 00:00:00 2001 From: gabriela Date: Tue, 22 Feb 2022 18:14:47 -0500 Subject: [PATCH 040/162] Correct detection of null character in strings. --- src/tokens_rules.py | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/src/tokens_rules.py b/src/tokens_rules.py index bd2a0c8f4..01748997f 100644 --- a/src/tokens_rules.py +++ b/src/tokens_rules.py @@ -193,24 +193,6 @@ def t_string(t): t.lexer.lineno +=1 t.lexer.last_new_line_pos = index + 2# saving last \n string_list.append('\n') - elif text[index + 1] == '0': # null character \0 is not allowed SACAR Y PONER EN UNA IDENTACION MAS AFUERA - # print("Illegal character \\0 inside string") # do something about it - # t.lexer.errors.append( - # LexicographicError( - # t.lexer.lineno + text[initial : index + 1].count("\n"), - # index - t.lexer.last_new_line_pos + 2, - # "Illegal character \\0 inside string", - # ) - # ) - t.lexer.errors.append( - LexicographicError( - t.lexer.lineno, - index - t.lexer.last_new_line_pos + 2, - "Illegal character \\0 inside string", - ) - ) - t.lexer.lexpos = index+2 - return t else: string_list.append(#CHEQUEAR PQ ESTO SE AHCE DOS VECES< COMO TRATAR DIFERENTE EL \n text[index : index + 2] @@ -239,7 +221,24 @@ def t_string(t): # index += 1 t.lexer.lexpos = index + 1#new return t - + elif text[index] == '\0': # null character \0 is not allowed SACAR Y PONER EN UNA IDENTACION MAS AFUERA + # print("Illegal character \\0 inside string") # do something about it + # t.lexer.errors.append( + # LexicographicError( + # t.lexer.lineno + text[initial : index + 1].count("\n"), + # index - t.lexer.last_new_line_pos + 2, + # "Illegal character \\0 inside string", + # ) + # ) + t.lexer.errors.append( + LexicographicError( + t.lexer.lineno, + index - t.lexer.last_new_line_pos + 1, + "Illegal character \\0 inside string", + ) + ) + t.lexer.lexpos = index+1 + return t else: string_list.append(text[index]) # string_to_append += text[index + 1] From 7befb2a3164c3fa6bc6c4578f0c103ddc2a96d04 Mon Sep 17 00:00:00 2001 From: gabriela Date: Tue, 22 Feb 2022 19:27:17 -0500 Subject: [PATCH 041/162] Fix string analisis in lexer. Continue with string analisis besides null character is found. --- src/tokens_rules.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/tokens_rules.py b/src/tokens_rules.py index 01748997f..1aca515ba 100644 --- a/src/tokens_rules.py +++ b/src/tokens_rules.py @@ -176,8 +176,8 @@ def t_comment1(t): # No return value. Token discarded -def t_string(t): - r"\" " +def t_string(t):# se va a develve el string vacio cada vez que no se puede matchear el string completo + r"\" "#xq habria que seguir analizando el string cuando se ha encontrado un caracter null y se ha de parar en otros casos? string_list = [] text = t.lexer.lexdata initial = t.lexer.lexpos @@ -237,8 +237,9 @@ def t_string(t): "Illegal character \\0 inside string", ) ) - t.lexer.lexpos = index+1 - return t + index += 1 + # t.lexer.lexpos = index+1 + # return t else: string_list.append(text[index]) # string_to_append += text[index + 1] From cf36521e3c0ae5e54e2a201bda0ffb86f2dc785f Mon Sep 17 00:00:00 2001 From: gabriela Date: Tue, 22 Feb 2022 20:06:57 -0500 Subject: [PATCH 042/162] Fix coolc.sh to run test correctly. --- src/coolc.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/coolc.sh b/src/coolc.sh index a20fe82b5..fc6c197c8 100755 --- a/src/coolc.sh +++ b/src/coolc.sh @@ -8,5 +8,6 @@ echo "EL_COMPI 1.0" echo "Copyright (c) 2022: Amalia_Ibarra, Sandra_Martos, Gabriela_Martinez" # Llamar al compilador -echo "Compiling $INPUT_FILE into $OUTPUT_FILE" -python3 -m main $@ \ No newline at end of file +# echo "Compiling $INPUT_FILE into $OUTPUT_FILE" +# python3 -m main $@ +exec python3 main.py $INPUT_FILE From 7d333b98b979be49b353a247a89270fd74a7c5a2 Mon Sep 17 00:00:00 2001 From: gabriela Date: Tue, 22 Feb 2022 20:51:25 -0500 Subject: [PATCH 043/162] Remove unnecesary comments. --- customized_tests/lexer/reserve_words.cl | 113 ++++++++++++++++++++++++ src/coolc.sh | 2 - src/lexical_analizer.py | 12 +-- src/tokens_rules.py | 98 +++----------------- 4 files changed, 130 insertions(+), 95 deletions(-) create mode 100644 customized_tests/lexer/reserve_words.cl diff --git a/customized_tests/lexer/reserve_words.cl b/customized_tests/lexer/reserve_words.cl new file mode 100644 index 000000000..06bf72036 --- /dev/null +++ b/customized_tests/lexer/reserve_words.cl @@ -0,0 +1,113 @@ +(* Integers, Identifiers, and Special Notation *) + +0007 123 +1 -1 +90 -09 +11113 -4r *a *self* c++ +5! = 120, 2 + 2 = 5 or E = mc2; p + 1 @ p = 1: for x in range(len(b)) +new / <- <<==> {( Int: Objet, Bool; String.string SELF_TYPE isvoid }) +class Class if then else fi testing Testing ~007agent_bond james_007B0N3SS___ +loop pool while tRuE or noT faLsE let in case of ESAC + +(* +#3 case 0007 +#3 inherits 123 +#3 '+' +#3 ; 1 +#3 '-' +#3 , 1 +#3 '+' +#3 . 90 +#3 '-' +#3 ( ) 09 +#3 '+' +#3 { } 11113 +#3 '-' +#3 @ 4 +#3 + r +#3 '*' +#3 - a +#3 '*' +#3 * self +#3 '*' +#3 / c +#3 '+' +#3 '+' +#4 < > 5 +#4 ERROR "!" +#4 '=' +#4 = 120 +#4 ',' +#4 ~ 2 +#4 '+' +#4 INT_CONST 2 +#4 '=' +#4 INT_CONST 5 +#4 OBJECTID or +#4 TYPEID E +#4 '=' +#4 OBJECTID mc2 +#4 ';' +#4 OBJECTID p +#4 '+' +#4 INT_CONST 1 +#4 '@' +#4 OBJECTID p +#4 '=' +#4 INT_CONST 1 +#4 ':' +#4 OBJECTID for +#4 OBJECTID x +#4 IN +#4 OBJECTID range +#4 '(' +#4 OBJECTID len +#4 '(' +#4 OBJECTID b +#4 ')' +#4 ')' +#5 NEW +#5 '/' +#5 ASSIGN +#5 '<' +#5 LE +#5 DARROW +#5 '{' +#5 '(' +#5 TYPEID Int +#5 ':' +#5 TYPEID Objet +#5 ',' +#5 TYPEID Bool +#5 ';' +#5 TYPEID String +#5 '.' +#5 OBJECTID string +#5 TYPEID SELF_TYPE +#5 ISVOID +#5 '}' +#5 ')' +#6 CLASS +#6 CLASS +#6 IF +#6 THEN +#6 ELSE +#6 FI +#6 OBJECTID testing +#6 TYPEID Testing +#6 '~' +#6 INT_CONST 007 +#6 OBJECTID agent_bond +#6 OBJECTID james_007B0N3SS___ +#7 LOOP +#7 POOL +#7 WHILE +#7 BOOL_CONST true +#7 OBJECTID or +#7 NOT +#7 BOOL_CONST false +#7 LET +#7 IN +#7 CASE +#7 OF +#7 ESAC +*) + +"asd \ No newline at end of file diff --git a/src/coolc.sh b/src/coolc.sh index fc6c197c8..1f7bffc38 100755 --- a/src/coolc.sh +++ b/src/coolc.sh @@ -8,6 +8,4 @@ echo "EL_COMPI 1.0" echo "Copyright (c) 2022: Amalia_Ibarra, Sandra_Martos, Gabriela_Martinez" # Llamar al compilador -# echo "Compiling $INPUT_FILE into $OUTPUT_FILE" -# python3 -m main $@ exec python3 main.py $INPUT_FILE diff --git a/src/lexical_analizer.py b/src/lexical_analizer.py index c5de0dec9..ea452039c 100644 --- a/src/lexical_analizer.py +++ b/src/lexical_analizer.py @@ -18,12 +18,11 @@ def pprint_tokens(tokens): print(" ".join([str(t.token_type) for t in pending])) -def tokenize_cool_text(grammar, idx, string, num, data, errors, printing=True): +def tokenize_cool_text(grammar, idx, string, num, data, errors, printing=False): # lexer starts with: lexpos = 0, lineno = 1, last_new_line = 0 - # lexpos Within token rule functions, this points to the first character after the matched text. + # lexpos: Within token rule functions, this points to the first character after the matched text. lexer = lex.lex(module = tokens_rules) - # lexer.lineno = 0# check if this cause any problems - lexer.last_new_line_pos = 0#no matter the index that it uses + lexer.last_new_line_pos = 0 lexer.errors = errors # Give the lexer some input @@ -34,9 +33,6 @@ def tokenize_cool_text(grammar, idx, string, num, data, errors, printing=True): for t in grammar.terminals if t not in {idx, string, num} } - print("First element") - print(lexer.token().value) - print("finito first elem") tokens = [] # Tokenize @@ -48,6 +44,7 @@ def tokenize_cool_text(grammar, idx, string, num, data, errors, printing=True): else: try: tokens.append(fixed_tokens[tok.type]) + # print(tok.type) except: try: # for <=, ->, <- tokens.append(fixed_tokens[tok.value]) @@ -61,5 +58,4 @@ def tokenize_cool_text(grammar, idx, string, num, data, errors, printing=True): if printing: pprint_tokens(tokens) - # print(tokens[0].lex) return tokens diff --git a/src/tokens_rules.py b/src/tokens_rules.py index 1aca515ba..8c5989614 100644 --- a/src/tokens_rules.py +++ b/src/tokens_rules.py @@ -9,28 +9,12 @@ UnexpectedTokenError, ) - -# def find_column(input, lexpos): -# # line_start = input.rfind("\n", 0, lexpos) + 1 -# # return (lexpos - line_start) + 1 -# line_numbers = input.rfind("\n", 0, lexpos) + 1 -# return (lexpos // line_numbers) + (lexpos % line_numbers) - - # Declare the states states = (("comments", "exclusive"),) # All lexers must provide a list tokens that defines all of the possible token names # that can be produced by the lexer. -# first_tokens = [ -# "larrow", -# "rarrow", -# "lessequal", -# "id", -# "int", -# "string", -# ] first_tokens = [ "larrow", "rarrow", @@ -38,8 +22,8 @@ "id", "int", "string", - "ccom" ] +# Add "ccom" to test comments reserved = { "class": "class", @@ -101,56 +85,36 @@ def t_comments_opsymb(t): # Define a rule so we can track line numbers def t_comments_newline(t): r"\n" - # t.lexer.lineno += len(t.value) t.lexer.last_new_line_pos = t.lexer.lexpos t.lexer.lineno += 1 -# t_foo_end(t) -# Comments closing symbol -# def t_comments_clsymb(t): +# end comments def t_comments_ccom(t): r"\*\)" t.lexer.level -= 1 if t.lexer.level == 0: - # t.value = t.lexer.lexdata[t.lexer.code_start : t.lexer.lexpos + 1] - t.value = t.lexer.lexdata[t.lexer.code_start : t.lexer.lexpos -2] # comments should not be returned, just skipped - t.type = "ccom" - # t.lexer.lineno += t.value.count("\n") - # t.lexer.lineno +=1#after the last closing symbol add new line + # t.value = t.lexer.lexdata[t.lexer.code_start : t.lexer.lexpos -2] # comments should not be returned, just skipped + # t.type = "ccom" + # return t t.lexer.begin("INITIAL") - return t def t_comments_any(t): -# def t_ccode_nonspace(t): # r'[^\s\{\}\'\"]+' r'[^\s\'\"]+' - # r'^[^ \n]+$' - # r"\.*" - # print("ANY") - # print(t.lexer.lexdata[t.lexer.lexpos -1]) # t.lexer.skip(1) # For bad characters. In this case we just skip over everything but (* or *) def t_comments_error(t): - # t.lexer.errors.append( - # LexicographicError( - # t.lexer.lineno, - # 0, - # "Illegal character inside comment", - # ) - # ) - # print("character skipped") - # print(t.lexer.lexdata[t.lexer.lexpos -1]) t.lexer.skip(1) # EOF handling rule def t_comments_eof(t): if t.lexer.level > 0: # guardar este error y actuar acorde - # print(f"code_start{t.lexer.code_start}") t.lexer.errors.append(LexicographicError(t.lexer.lineno, t.lexer.lexpos - t.lexer.last_new_line_pos + 1, "EOF in comment")) return None + # t.lexer.skip(1) # Rules for initial state (default state) @@ -186,29 +150,18 @@ def t_string(t):# se va a develve el string vacio cada vez que no se puede match while index < final and text[index] != '\"': if text[index] == '\\': if text[index + 1] in ["t", "b", "f", "n"]: - # string_to_append+=f'\\{text[index + 1]}' string_list.append(text[index : index + 2]) # \t,\b,\f, \n elif text[index + 1] == '\n': # \n whith \ before - # string_to_append+='\n' t.lexer.lineno +=1 t.lexer.last_new_line_pos = index + 2# saving last \n string_list.append('\n') else: - string_list.append(#CHEQUEAR PQ ESTO SE AHCE DOS VECES< COMO TRATAR DIFERENTE EL \n + string_list.append(# ESTO SE AHCE DOS VECES< COMO TRATAR DIFERENTE EL \t por ejempli text[index : index + 2] ) # ]character c: take the character in \c - # string_to_append += text[index + 1] index += 2 elif text[index] == '\n': # non scape \n (whithout and extra \) is not allowed - # print("Illegal character \\n inside string") # do something about it - # t.lexer.errors.append( - # LexicographicError( - # t.lexer.lineno + text[initial : index + 1].count("\n"), - # index - t.lexer.last_new_line_pos + 1, - # "Illegal character \\n inside string", - # ) - # ) t.lexer.errors.append( LexicographicError( t.lexer.lineno, @@ -217,19 +170,10 @@ def t_string(t):# se va a develve el string vacio cada vez que no se puede match ) ) t.lexer.lineno +=1 - t.lexer.last_new_line_pos = index + 1# sabing last \n - # index += 1 - t.lexer.lexpos = index + 1#new + t.lexer.last_new_line_pos = index + 1# saving last \n + t.lexer.lexpos = index + 1 return t - elif text[index] == '\0': # null character \0 is not allowed SACAR Y PONER EN UNA IDENTACION MAS AFUERA - # print("Illegal character \\0 inside string") # do something about it - # t.lexer.errors.append( - # LexicographicError( - # t.lexer.lineno + text[initial : index + 1].count("\n"), - # index - t.lexer.last_new_line_pos + 2, - # "Illegal character \\0 inside string", - # ) - # ) + elif text[index] == '\0': # null character \0 is not allowed t.lexer.errors.append( LexicographicError( t.lexer.lineno, @@ -238,22 +182,12 @@ def t_string(t):# se va a develve el string vacio cada vez que no se puede match ) ) index += 1 - # t.lexer.lexpos = index+1 # return t else: string_list.append(text[index]) - # string_to_append += text[index + 1] index += 1 if index == final: - # print("String may not cross file boundaries") # do something about it - # t.lexer.errors.append( - # LexicographicError( - # t.lexer.lineno + text[initial : index + 1].count("\n"), - # t.lexer.lexpos - t.lexer.last_new_line_pos + 1, - # "String may not cross file boundaries", - # ) - # ) t.lexer.errors.append( LexicographicError( t.lexer.lineno, @@ -261,26 +195,20 @@ def t_string(t):# se va a develve el string vacio cada vez que no se puede match "String may not cross file boundaries", ) ) - #AQUI NO HACE FALTA ACTUALIZAR index antes? t.lexer.lexpos = index return t else: - index += 1#jumping '\"' character + index += 1#jumping '\"' character (character for closing coments) t.value = "".join(string_list) t.type = "string" - # t.lexer.lexpos += index - initial #RECIEND BORRADO - t.lexer.lexpos = index# en index se supone este el " de cerrar los comentarios - # t.lexer.lineno += text[initial : index + 1].count("\n") - # print(t.value) - # print(string_to_append) + t.lexer.lexpos = index return t # Define a rule so we can track line numbers def t_newline(t): r'\n' - # t.lexer.lineno += len(t.value) t.lexer.last_new_line_pos = t.lexer.lexpos t.lexer.lineno += 1 @@ -293,7 +221,7 @@ def t_newline(t): # Error handling rule -def t_error(t):#for some reason here lexpos is the current character, maybe because it could not be matched +def t_error(t):#At the moment of entering this method lexpos is the current character (instead of the last matched character) because nothing could've been matched t.lexer.errors.append( LexicographicError( t.lexer.lineno, From 2a8914f1e5e3bd6cdc32b369a0702ddab5cb4d8d Mon Sep 17 00:00:00 2001 From: gabriela Date: Tue, 22 Feb 2022 21:12:40 -0500 Subject: [PATCH 044/162] Change errors messages. Changes error messages so they match with the teacher's text. --- src/tokens_rules.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tokens_rules.py b/src/tokens_rules.py index 8c5989614..4e391a4ef 100644 --- a/src/tokens_rules.py +++ b/src/tokens_rules.py @@ -166,7 +166,7 @@ def t_string(t):# se va a develve el string vacio cada vez que no se puede match LexicographicError( t.lexer.lineno, index - t.lexer.last_new_line_pos + 1, - "Illegal character \\n inside string", + "Unterminated string constant", ) ) t.lexer.lineno +=1 @@ -178,7 +178,7 @@ def t_string(t):# se va a develve el string vacio cada vez que no se puede match LexicographicError( t.lexer.lineno, index - t.lexer.last_new_line_pos + 1, - "Illegal character \\0 inside string", + "String contains null character", ) ) index += 1 @@ -187,12 +187,12 @@ def t_string(t):# se va a develve el string vacio cada vez que no se puede match string_list.append(text[index]) index += 1 - if index == final: + if index == final: # String may not cross file boundaries t.lexer.errors.append( LexicographicError( t.lexer.lineno, index - t.lexer.last_new_line_pos + 1, - "String may not cross file boundaries", + "EOF in string constant", ) ) t.lexer.lexpos = index From f05dfa9a58fded05204d8920703e474b5ae9ed64 Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Wed, 23 Feb 2022 13:34:18 -0500 Subject: [PATCH 045/162] feat: use provided cil hierarchy. Visit arithmetic and unary nodes. --- src/cmp/cil.py | 40 +++- src/code_gen/cil_builder.py | 461 +++++++++++++++++------------------- src/code_gen/cil_nodes.py | 26 ++ 3 files changed, 282 insertions(+), 245 deletions(-) diff --git a/src/cmp/cil.py b/src/cmp/cil.py index 21cbaedaa..5c62d776f 100644 --- a/src/cmp/cil.py +++ b/src/cmp/cil.py @@ -54,7 +54,12 @@ def __init__(self, dest, source): class ArithmeticNode(InstructionNode): - def __init__(self, dest, left, right): + def __init__( + self, + dest, + left, + right, + ): self.dest = dest self.left = left self.right = right @@ -76,6 +81,32 @@ class DivNode(ArithmeticNode): pass +class LessNode(ArithmeticNode): + pass + + +class LessEqualNode(ArithmeticNode): + pass + + +class EqualNode(ArithmeticNode): + pass + + +class UnaryNode(InstructionNode): + def __init__(self, dest, expr): + self.dest = dest + self.expr = expr + + +class NotNode(UnaryNode): + pass + + +class IntComplementNode(UnaryNode): + pass + + class GetAttribNode(InstructionNode): pass @@ -113,11 +144,14 @@ class LabelNode(InstructionNode): class GotoNode(InstructionNode): - pass + def __init__(self, label): + self.label = label class GotoIfNode(InstructionNode): - pass + def __init__(self, condition, label): + self.condition = condition + self.label = label class StaticCallNode(InstructionNode): diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index 2c94a81e4..8fe8cf553 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -1,36 +1,7 @@ import cmp.nbpackage import cmp.visitor as visitor -from ast_nodes import Node, ProgramNode, ExpressionNode -from ast_nodes import ClassDeclarationNode, FuncDeclarationNode, AttrDeclarationNode -from ast_nodes import VarDeclarationNode, AssignNode, CallNode -from ast_nodes import ( - AtomicNode, - BinaryNode, - ArithmeticOperation, - ComparisonOperation, - IfNode, - LetNode, - CaseNode, - CaseItemNode, - WhileNode, - BlockNode, - IsvoidNode, -) -from ast_nodes import ( - ConstantNumNode, - VariableNode, - InstantiateNode, - PlusNode, - MinusNode, - StarNode, - DivNode, - NegNode, - NotNode, - EqualNode, - BooleanNode, - StringNode, -) +import ast_nodes as cool from cil_nodes import ( StringCil, @@ -46,22 +17,51 @@ LabelCil, GotoCil, ) + +from cmp.cil import ( + ProgramNode, + TypeNode, + MethodNode, + DataNode, + FunctionNode, + ParamNode, + LocalNode, + AssignNode, + ArithmeticNode, + AllocateNode, + TypeOfNode, + LabelNode, + GotoIfNode, + GotoNode, + StaticCallNode, + DynamicCallNode, + ArgNode, + ReturnNode, + LoadNode, + LengthNode, + ConcatNode, + PrefixNode, + SubstringNode, + ToStrNode, + ReadNode, + PrintNode, + PlusNode, + MinusNode, + StarNode, + DivNode, + NotNode, + IntComplementNode, + LessNode, + LessEqualNode, + EqualNode +) from cool_visitor import FormatVisitor -from cmp.semantic import SemanticError from cmp.semantic import Attribute, Method, Type from cmp.semantic import VoidType, ErrorType, IntType from cmp.semantic import Context from cmp.semantic import Scope -from cmp.utils import find_least_type - -WRONG_SIGNATURE = 'Method "%s" already defined in "%s" with a different signature.' -SELF_IS_READONLY = 'Variable "self" is read-only.' -LOCAL_ALREADY_DEFINED = 'Variable "%s" is already defined in method "%s".' -INCOMPATIBLE_TYPES = 'Cannot convert "%s" into "%s".' -VARIABLE_NOT_DEFINED = 'Variable "%s" is not defined in "%s".' -INVALID_OPERATION = 'Operation is not defined between "%s" and "%s".' class CILBuilder: @@ -94,11 +94,12 @@ def next_id(self): self._count += 1 return str(self._count) + @visitor.on("node") def visit(self, node=None): pass - @visitor.when(ProgramNode) + @visitor.when(cool.ProgramNode) def visit(self, node): self.context = node.context @@ -108,295 +109,271 @@ def visit(self, node): self.current_type = None self.current_method = None - return ProgramCil(self.types, self.data, self.code) + return ProgramNode(self.types, self.data, self.code) - @visitor.when(ClassDeclarationNode) + @visitor.when(cool.ClassDeclarationNode) def visit(self, node): - self.current_type = TypeCil(node.id) + self.current_type = TypeNode(node.id) self.types.append(self.current_type) for feature in node.features: self.visit(feature) - @visitor.when(AttrDeclarationNode) + self.current_type = None + + @visitor.when(cool.AttrDeclarationNode) def visit(self, node): # Add attribute to current type's list of attributes (cool type of the attribute is ignored) - self.current_type.attributes.append(AttributeCil(node.id)) + self.current_type.attributes.append(node.id) - # Visit initial expression + # Visit initial expression #TODO: Is it necessary? self.visit(node.init_exp) - @visitor.when(FuncDeclarationNode) + @visitor.when(cool.FuncDeclarationNode) def visit(self, node): + self.current_method = self.context.get_type(self.current_type).get_method( + node.id + ) + + # Generate ref ref = self.generate_next_method_id() - self.current_type.methods.append(MethodCil(node.id, ref)) + self.current_type.methods.append((node.id, ref)) - function = FunctionCil(ref) + # Add params + function = FunctionNode(ref, [], [], []) for pname, _ in node.params: - function.args.append(ArgCil(pname)) + function.params.append(ParamNode(pname)) + # Add function to .CODE self.current_function = function self.code.append(function) - self.visit(node.body) + # Body + value = None + for instruction in node.body: + value = self.visit(instruction) + + # Handle return + if isinstance(self.current_method.return_type, VoidType): + value = None + + self.code.append(ReturnNode(value)) + self.current_method = None + self.current_function = None - @visitor.when(VarDeclarationNode) + @visitor.when(cool.VarDeclarationNode) def visit(self, node): # Add LOCAL variable - local = LocalCil(node.id) + local = LocalNode(node.id) self.current_function.locals.append(local) # Add Assignment Node if node.expr: expr = self.visit(node.expr) - self.current_function.body.append(AssignmentCil(local.id, expr)) + self.current_function.body.append(AssignNode(local.id, expr)) - @visitor.when(AssignNode) + @visitor.when(cool.AssignNode) def visit(self, node): expr = self.visit(node.expr) - self.current_function.body.append(AssignmentCil(node.id, expr)) + self.current_function.body.append(AssignNode(node.id, expr)) - @visitor.when(CallNode) - def visit(self, node): - auto_type = self.context.get_type("AUTO_TYPE") - typex = None - if node.obj is not None: - typex = self.visit(node.obj) - if typex == auto_type: - return auto_type - - else: - typex = self.current_type - - method = None - try: - if node.at_type is not None: - node_at_type = self.context.get_type(node.at_type) - method = node_at_type.get_method(node.id) - if not typex.conforms_to(node_at_type): - self.errors.append( - f"The static type to the left of @ ({typex.name}) must conform to the type specified to the right of @ ({node_at_type.name}) " - ) - return ErrorType() - else: - method = typex.get_method(node.id) - except SemanticError as error: - self.errors.append(error.text) - return ErrorType() - - if len(method.param_names) != len(node.args): - self.errors.append( - f"There is no definition of {method.name} that takes {len(node.args)} arguments " - ) - - for arg, ptype in zip(node.args, method.param_types): - arg_type = self.visit(arg) - if not arg_type.conforms_to(ptype): - self.errors.append(INCOMPATIBLE_TYPES % (arg_type.name, ptype.name)) - - if method.return_type == self.context.get_type("SELF_TYPE"): - return typex - - return method.return_type - - @visitor.when(IfNode) + @visitor.when(cool.CallNode) def visit(self, node): - # Temp variable to store value of if_expr - if_temp = self.generate_next_tvar_id() - self.current_function.locals.append(LocalCil(if_temp)) - - # Assign value - if_expr = self.visit(node.if_expr) - self.current_function.body.append(AssignmentCil(if_temp, if_expr)) + pass - # IF x GOTO label + @visitor.when(cool.IfNode) + def visit(self, node): + # IF condition GOTO label + condition_value = self.visit(node.if_expr) then_label = "THEN_" + self.next_id() - self.current_function.body.append(IfCil(if_temp, then_label)) + self.current_function.body.append(GotoIfNode(condition_value, then_label)) - # Temp variable to store value of else_expr + # Else self.visit(node.else_expr) # GOTO end_label end_label = "END_IF_" + self.next_id() # Example: END_IF_120 - self.current_function.body.append(GotoCil(end_label)) + self.current_function.body.append(GotoNode(end_label)) # Then label - self.current_function.body.append(LabelCil(then_label)) + self.current_function.body.append(LabelNode(then_label)) self.visit(node.then_expr) # end_label - self.current_function.body.append(LabelCil(end_label)) + self.current_function.body.append(LabelNode(end_label)) # TODO: return something? - @visitor.when(WhileNode) + @visitor.when(cool.WhileNode) def visit(self, node): - condition_type = self.visit(node.condition) - bool_type = self.context.get_type("Bool") + # While label + while_label = "WHILE_" + self.next_id() + self.current_function.body.append(LabelNode(while_label)) - if condition_type != bool_type and condition_type.name != "AUTO_TYPE": - self.errors.append( - f"Expression after 'while' must be bool, current is {condition_type.name}" - ) - return ErrorType() + # Condition + c = self.visit(node.condition) # TODO: pop from stack - return self.context.get_type("Object") + # If condition GOTO body_label + body_label = "BODY_" + self.next_id() + self.current_function.body.append(GotoIfNode(c, body_label)) - @visitor.when(BlockNode) - def visit(self, node): - typex = None - for expr in node.expression_list: - typex = self.visit(expr) + # GOTO end_while label + end_while_label = "END_WHILE_" + self.next_id() + self.current_function.body.append(GotoNode(end_while_label)) - return typex + # Body + self.current_function.body.append(LabelNode(body_label)) + self.visit(node.body) - @visitor.when(LetNode) - def visit(self, node): + # GOTO while label + self.current_function.body.append(GotoNode(while_label)) - child_scope = scope.create_child() + # End while label + self.current_function.body.append(LabelNode(end_while_label)) - for var_dec in node.identifiers: - self.visit(var_dec, child_scope) + @visitor.when(cool.BlockNode) + def visit(self, node): + value = None + for expr in node.expression_list: + value = self.visit(expr) - return self.visit(node.body, child_scope) + return value - @visitor.when(CaseNode) + @visitor.when(cool.LetNode) def visit(self, node): - self.visit(node.expr) - - current_case_type = None - for item in node.case_items: - child_scope = scope.create_child() - case_item_type = self.visit(item, child_scope) - current_case_type = find_least_type( - current_case_type, case_item_type, self.context - ) + for var_dec in node.identifiers: + self.visit(var_dec.expr) + self.current_function.localvars.append(LocalNode(var_dec.id)) - return current_case_type + self.visit(node.body) - @visitor.when(CaseItemNode) + @visitor.when(cool.CaseNode) def visit(self, node): - try: - static_type = self.context.get_type(node.type) - scope.define_variable(node.id, static_type) - except SemanticError as e: - self.errors.append(e) - return ErrorType() + pass #TODO: Pending!!! + - typex = self.visit(node.expr) + @visitor.when(cool.CaseItemNode) + def visit(self, node): + pass #TODO: Pending!!! - return typex - @visitor.when(InstantiateNode) # NewNode + # Arithmetic and comparison operators + @visitor.when(cool.PlusNode) def visit(self, node): - try: - typex = self.context.get_type(node.lex) - if typex.name == "SELF_TYPE": - return self.current_type + left = self.visit(node.left) + right = self.visit(node.right) - return typex - except SemanticError as error: - self.errors.append(error.text) - return ErrorType() + local = self.generate_next_tvar_id() + self.current_function.instructions.append(LocalNode(local)) + self.current_function.instructions.append( + PlusNode(local, left, right) + ) - @visitor.when(IsvoidNode) + @visitor.when(cool.MinusNode) def visit(self, node): - self.visit(node.expr) - return self.context.get_type("Bool") + left = self.visit(node.left) + right = self.visit(node.right) - @visitor.when(ArithmeticOperation) - def visit(self, node): - int_type = self.context.get_type("Int") - left_type = self.visit(node.left) - right_type = self.visit(node.right) + local = self.generate_next_tvar_id() + self.current_function.instructions.append(LocalNode(local)) + self.current_function.instructions.append( + MinusNode(local, left, right) + ) - if (left_type != int_type and left_type.name != "AUTO_TYPE") or ( - right_type != int_type and right_type.name != "AUTO_TYPE" - ): - self.errors.append(INVALID_OPERATION % (left_type.name, right_type.name)) + @visitor.when(cool.StarNode) + def visit(self, node): + left = self.visit(node.left) + right = self.visit(node.right) - return int_type + local = self.generate_next_tvar_id() + self.current_function.instructions.append(LocalNode(local)) + self.current_function.instructions.append( + StarNode(local, left, right) + ) - @visitor.when(ComparisonOperation) + @visitor.when(cool.DivNode) def visit(self, node): - int_type = self.context.get_type("Int") - left_type = self.visit(node.left) - right_type = self.visit(node.right) - - if (left_type != int_type and left_type.name != "AUTO_TYPE") or ( - right_type != int_type and right_type.name != "AUTO_TYPE" - ): - self.errors.append(INVALID_OPERATION % (left_type.name, right_type.name)) + left = self.visit(node.left) + right = self.visit(node.right) + + local = self.generate_next_tvar_id() + self.current_function.instructions.append(LocalNode(local)) + self.current_function.instructions.append( + DivNode(local, left, right) + ) + @visitor.when(cool.LessEqualNode) + def visit(self, node): + left = self.visit(node.left) + right = self.visit(node.right) - return self.context.get_type("Bool") + local = self.generate_next_tvar_id() + self.current_function.instructions.append(LocalNode(local)) + self.current_function.instructions.append( + LessEqualNode(local, left, right) + ) - @visitor.when(EqualNode) + @visitor.when(cool.LessNode) def visit(self, node): - int_type = self.context.get_type("Int") - string_type = self.context.get_type("String") - bool_type = self.context.get_type("Bool") - built_in_types = [int_type, string_type, bool_type] - - left_type = self.visit(node.left) - right_type = self.visit(node.right) - - if left_type in built_in_types or right_type in built_in_types: - if ( - left_type != right_type - and left_type.name != "AUTO_TYPE" - and right_type.name != "AUTO_TYPE" - ): - self.errors.append( - f"One of the expressions of '=' operator is of type Int, String or Bool, the other must have the same static type. Left type: {left_type.name}.Right type: {right_type.name}" - ) - - return self.context.get_type("Bool") - - @visitor.when(NotNode) + left = self.visit(node.left) + right = self.visit(node.right) + + local = self.generate_next_tvar_id() + self.current_function.instructions.append(LocalNode(local)) + self.current_function.instructions.append( + LessNode(local, left, right) + ) + @visitor.when(cool.EqualNode) def visit(self, node): - bool_type = self.context.get_type("Bool") - typex = self.visit(node.expr) - - if typex != bool_type and not typex.name == "AUTO_TYPE": - self.errors.append( - f"Expression after 'not' must be Bool, current is {typex.name}" - ) - return ErrorType() + left = self.visit(node.left) + right = self.visit(node.right) + + local = self.generate_next_tvar_id() + self.current_function.instructions.append(LocalNode(local)) + self.current_function.instructions.append( + EqualNode(local, left, right) + ) + #Unary operators + @visitor.when(cool.InstantiateNode) # NewNode + def visit(self, node): + new_local = self.generate_next_tvar_id() + self.current_function.instructions.append(LocalNode(new_local)) + self.current_function.instructions.append(AllocateNode(node.lex, new_local)) - return bool_type + @visitor.when(cool.IsvoidNode) + def visit(self, node): + value = self.visit(node.expr) + return value - @visitor.when(NegNode) + @visitor.when(cool.NotNode) def visit(self, node): - int_type = self.context.get_type("Int") - typex = self.visit(node.expr) + value = self.visit(node.expr) + local = self.generate_next_tvar_id() + self.current_function.instructions.append(LocalNode(local)) + self.current_function.instructions.append(NotNode(local, value)) - if typex != int_type and not typex.name == "AUTO_TYPE": - self.errors.append( - f"Expression after '~' must be Int, current is {typex.name}" - ) - return ErrorType() - return int_type + @visitor.when(cool.NegNode) + def visit(self, node): + value = self.visit(node.expr) + local = self.generate_next_tvar_id() + self.current_function.instructions.append(LocalNode(local)) + self.current_function.instructions.append(IntComplementNode(local, value)) + - @visitor.when(ConstantNumNode) + @visitor.when(cool.ConstantNumNode) def visit(self, node): - return self.context.get_type("Int") + return node.lex - @visitor.when(VariableNode) + @visitor.when(cool.VariableNode) def visit(self, node): - var = scope.find_variable(node.lex) - if var is None: - self.errors.append( - VARIABLE_NOT_DEFINED % (node.lex, self.current_method.name) - ) - return ErrorType() - return var.type - - @visitor.when(StringNode) + return node.lex + + @visitor.when(cool.StringNode) def visit(self, node): - idx = "str_" + self.generate_next_id() - self.data.append(StringCil(idx, node.lex)) + idx = self.generate_next_string_id() + self.data.append(DataNode(idx, node.lex)) + return idx - @visitor.when(BooleanNode) + @visitor.when(cool.BooleanNode) def visit(self, node): - return self.context.get_type("Bool") + return node.lex == "true": 1 : 0 \ No newline at end of file diff --git a/src/code_gen/cil_nodes.py b/src/code_gen/cil_nodes.py index 0a45199cc..5d0e66952 100644 --- a/src/code_gen/cil_nodes.py +++ b/src/code_gen/cil_nodes.py @@ -71,3 +71,29 @@ def __init__(self, idx): class GotoCil(CIL_Node): def __init__(self, label): self.label = label + + +class GetAttrCil(CIL_Node): + def __init__(self, typex, attr): + self.type = typex + self.attr = attr + + +class SetAttr(CIL_Node): + def __init__(self, typex, attr, value): + self.type = typex + self.attr = attr + self.value = value + + +class GetIndex(CIL_Node): + def __init__(self, array, index): + self.array = array + self.index = index + + +class SetIndex(CIL_Node): + def __init__(self, array, index, value): + self.array = array + self.index = index + self.value = value From 78f5cd38d34494b4e264af1263220caae6197947 Mon Sep 17 00:00:00 2001 From: gabriela Date: Wed, 23 Feb 2022 16:34:11 -0500 Subject: [PATCH 046/162] Modify lexer to detect dif types of ids. Identify Type identifiers (the ones with capital letters) and object identifiers (the ones with lowercase initials). --- customized_tests/run_pipeline.py | 4 ++-- src/cool_grammar.py | 26 +++++++++++++------------- src/lexical_analizer.py | 7 ++++--- src/main.py | 23 +++++++++++++++++------ src/tokens_rules.py | 13 ++++++++++++- 5 files changed, 48 insertions(+), 25 deletions(-) diff --git a/customized_tests/run_pipeline.py b/customized_tests/run_pipeline.py index cd653c2ab..d156994d9 100644 --- a/customized_tests/run_pipeline.py +++ b/customized_tests/run_pipeline.py @@ -11,11 +11,11 @@ def run_pipeline(text): # define grammar - grammar, idx, string, num = define_cool_grammar() + grammar, idx, typeIdx, string, num = define_cool_grammar() # tokenize text # tokens = tokenize_cool_text(grammar, text, idx, num, True) - tokens = tokenize_cool_text(grammar, idx, string, num, text, True) + tokens = tokenize_cool_text(grammar, idx, typeIdx, typeIdx, string, num, text, [], True) # print(tokens) # try: diff --git a/src/cool_grammar.py b/src/cool_grammar.py index a7c4c6e46..69f2de688 100644 --- a/src/cool_grammar.py +++ b/src/cool_grammar.py @@ -61,7 +61,7 @@ def define_cool_grammar(print_grammar=False): equal, plus, minus, star, div, less, equal, lesseq, neg = G.Terminals( "= + - * / < = <= ~" ) - idx, num, new, string, true, false = G.Terminals("id int new string true false") + idx, type_id, num, new, string, true, false = G.Terminals("id type_id int new string true false") # productions program %= class_list, lambda h, s: ProgramNode(s[1]) @@ -70,11 +70,11 @@ def define_cool_grammar(print_grammar=False): class_list %= def_class, lambda h, s: [s[1]] def_class %= ( - classx + idx + ocur + feature_list + ccur + semi, + classx + type_id + ocur + feature_list + ccur + semi, lambda h, s: ClassDeclarationNode(s[2], s[4]), ) def_class %= ( - classx + idx + inherits + idx + ocur + feature_list + ccur + semi, + classx + type_id + inherits + type_id + ocur + feature_list + ccur + semi, lambda h, s: ClassDeclarationNode(s[2], s[6], s[4]), ) @@ -83,13 +83,13 @@ def define_cool_grammar(print_grammar=False): feature_list %= G.Epsilon, lambda h, s: [] def_attr %= ( - idx + colon + idx + larrow + expr, + idx + colon + type_id + larrow + expr, lambda h, s: AttrDeclarationNode(s[1], s[3], s[5]), ) - def_attr %= idx + colon + idx, lambda h, s: AttrDeclarationNode(s[1], s[3]) + def_attr %= idx + colon + type_id, lambda h, s: AttrDeclarationNode(s[1], s[3]) def_func %= ( - idx + opar + param_list + cpar + colon + idx + ocur + expr + ccur, + idx + opar + param_list + cpar + colon + type_id + ocur + expr + ccur, lambda h, s: FuncDeclarationNode(s[1], s[3], s[6], s[8]), ) @@ -97,7 +97,7 @@ def define_cool_grammar(print_grammar=False): param_list %= param, lambda h, s: [s[1]] param_list %= G.Epsilon, lambda h, s: [] - param %= idx + colon + idx, lambda h, s: (s[1], s[3]) + param %= idx + colon + type_id, lambda h, s: (s[1], s[3]) expr %= idx + larrow + expr, lambda h, s: AssignNode(s[1], s[3]) expr %= let + identifiers_list + inx + expr, lambda h, s: LetNode(s[2], s[4]) @@ -117,15 +117,15 @@ def define_cool_grammar(print_grammar=False): identifiers_list %= identifier_init, lambda h, s: [s[1]] identifier_init %= ( - idx + colon + idx + larrow + expr, + idx + colon + type_id + larrow + expr, lambda h, s: VarDeclarationNode(s[1], s[3], s[5]), ) - identifier_init %= idx + colon + idx, lambda h, s: VarDeclarationNode(s[1], s[3]) + identifier_init %= idx + colon + type_id, lambda h, s: VarDeclarationNode(s[1], s[3]) case_block %= case_item + case_block, lambda h, s: [s[1]] + s[2] case_block %= case_item, lambda h, s: [s[1]] case_item %= ( - idx + colon + idx + rarrow + expr + semi, + idx + colon + type_id + rarrow + expr + semi, lambda h, s: CaseItemNode(s[1], s[3], s[5]), ) @@ -144,14 +144,14 @@ def define_cool_grammar(print_grammar=False): factor %= isvoid + element, lambda h, s: IsvoidNode(s[2]) factor %= neg + element, lambda h, s: NegNode(s[2]) - factor %= new + idx, lambda h, s: InstantiateNode(s[2]) + factor %= new + type_id, lambda h, s: InstantiateNode(s[2]) factor %= element, lambda h, s: s[1] element %= opar + expr + cpar, lambda h, s: s[2] element %= ocur + block + ccur, lambda h, s: BlockNode(s[2]) element %= (element + dot + func_call, lambda h, s: CallNode(*s[3], obj=s[1])) element %= ( - element + at + idx + dot + func_call, + element + at + type_id + dot + func_call, lambda h, s: CallNode(*s[5], obj=s[1], at_type=s[3]), ) element %= func_call, lambda h, s: CallNode(*s[1]) @@ -177,4 +177,4 @@ def define_cool_grammar(print_grammar=False): if print_grammar: print(G) - return (G, idx, string, num) + return (G, idx, type_id, string, num) diff --git a/src/lexical_analizer.py b/src/lexical_analizer.py index ea452039c..92eb77dee 100644 --- a/src/lexical_analizer.py +++ b/src/lexical_analizer.py @@ -18,7 +18,7 @@ def pprint_tokens(tokens): print(" ".join([str(t.token_type) for t in pending])) -def tokenize_cool_text(grammar, idx, string, num, data, errors, printing=False): +def tokenize_cool_text(grammar, idx, type_id, string, num, data, errors, printing=False): # lexer starts with: lexpos = 0, lineno = 1, last_new_line = 0 # lexpos: Within token rule functions, this points to the first character after the matched text. lexer = lex.lex(module = tokens_rules) @@ -31,7 +31,7 @@ def tokenize_cool_text(grammar, idx, string, num, data, errors, printing=False): fixed_tokens = { t.Name: Token(t.Name, t) for t in grammar.terminals - if t not in {idx, string, num} + if t not in {idx, type_id, string, num} } tokens = [] @@ -44,7 +44,6 @@ def tokenize_cool_text(grammar, idx, string, num, data, errors, printing=False): else: try: tokens.append(fixed_tokens[tok.type]) - # print(tok.type) except: try: # for <=, ->, <- tokens.append(fixed_tokens[tok.value]) @@ -53,6 +52,8 @@ def tokenize_cool_text(grammar, idx, string, num, data, errors, printing=False): tokens.append(Token(tok.value, string)) elif tok.type == "id": tokens.append(Token(tok.value, idx)) + elif tok.type == "type_id": + tokens.append(Token(tok.value, type_id)) else: tokens.append(Token(tok.value, num)) diff --git a/src/main.py b/src/main.py index ed0655348..276f14524 100644 --- a/src/main.py +++ b/src/main.py @@ -39,9 +39,10 @@ def pipeline(input_file: Path, output_file: Path = None): # main_error2 = ['"main" method in class Main does not receive any parameters'] # define grammar - grammar, idx, string, num = define_cool_grammar() + grammar, idx, type_id, string, num = define_cool_grammar() - tokens = tokenize_cool_text(grammar, idx, string, num, text, errors) + tokens = tokenize_cool_text(grammar, idx, type_id, string, num, text, errors) + # print(tokens) if len(errors) > 0: report_and_exit(errors) parser = LR1Parser(grammar, errors) @@ -51,9 +52,19 @@ def pipeline(input_file: Path, output_file: Path = None): parse, operations = parser([t.token_type for t in tokens]) + print("Parse") + print(parse) + + if len(errors) > 0: + report_and_exit(errors) + + #get parsing tree ast = evaluate_reverse_parse(parse, operations, tokens) - # formatter = FormatVisitorST() - # tree = formatter.visit(ast) + + #printing tree + formatter = FormatVisitorST() + tree = formatter.visit(ast) + print(tree) visitors = [TypeCollector(errors), TypeBuilder(errors)] for visitor in visitors: @@ -62,8 +73,8 @@ def pipeline(input_file: Path, output_file: Path = None): if len(errors) > 0: report_and_exit(errors) - if output_file is None: - output_file = input.with_suffix(".mips") + # if output_file is None: + # output_file = input.with_suffix(".mips") if __name__ == "__main__": diff --git a/src/tokens_rules.py b/src/tokens_rules.py index 4e391a4ef..9835ce69d 100644 --- a/src/tokens_rules.py +++ b/src/tokens_rules.py @@ -20,6 +20,7 @@ "rarrow", "lessequal", "id", + "type_id", "int", "string", ] @@ -118,13 +119,23 @@ def t_comments_eof(t): # Rules for initial state (default state) + +#Object identifiers def t_id(t): - r"[a-zA-Z][a-zA-Z_0-9]*" + r"[a-z][a-zA-Z_0-9]*" t.type = reserved.get( t.value, "id" ) # Check for reserved words. If it isn't a reserved word is categorized as identifier return t +#Type identifiers +def t_type_id(t): + r"[A-Z][a-zA-Z_0-9]*" + t.type = reserved.get( + t.value, "type_id" + ) # Check for reserved words. If it isn't a reserved word is categorized as identifier + return t + # matching int numbers def t_int(t): r"\d+" From 47ed5cca7713ae7e63146e810b821073453bdbfc Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Wed, 23 Feb 2022 18:20:58 -0500 Subject: [PATCH 047/162] feat: add entry function. Reset visitor state after visit --- src/code_gen/cil_builder.py | 75 ++++++++++++++++++++++++++----------- 1 file changed, 54 insertions(+), 21 deletions(-) diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index 8fe8cf553..32ad84b8c 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -94,6 +94,11 @@ def next_id(self): self._count += 1 return str(self._count) + def to_function_name(self, method_name, type_name): + return f'function_{method_name}_at_{type_name}' + + def register_instruction(self, instruction): + self.register_instruction(instruction) @visitor.on("node") def visit(self, node=None): @@ -103,11 +108,39 @@ def visit(self, node=None): def visit(self, node): self.context = node.context + #Add entry function and call Main.main() + self.current_function = FunctionNode("entry", [],[],[]) + self.code.append(self.current_function) + + instance = self.generate_next_tvar_id() + self.register_instruction(LocalNode(instance)) + + result = self.generate_next_tvar_id() + self.register_instruction(LocalNode(result)) + + main_method_name = self.to_function_name("Main", "main") + self.register_instruction(AllocateNode("Main",instance)) + self.register_instruction(ArgNode(instance)) + self.register_instruction(StaticCallNode(main_method_name, result)) + self.register_instruction(ReturnNode(0)) + + self.current_function = None + for declaration in node.declarations: self.visit(declaration) + #Reset state + self.types = [] + self.code = [] + self.data = [] self.current_type = None - self.current_method = None + self.current_function = None + self.errors = errors + self.method_count = 0 + self.string_count = 0 + self.temp_vars_count = 0 + self._count = 0 + self.context = None return ProgramNode(self.types, self.data, self.code) @@ -264,8 +297,8 @@ def visit(self, node): right = self.visit(node.right) local = self.generate_next_tvar_id() - self.current_function.instructions.append(LocalNode(local)) - self.current_function.instructions.append( + self.register_instruction(LocalNode(local)) + self.register_instruction( PlusNode(local, left, right) ) @@ -275,8 +308,8 @@ def visit(self, node): right = self.visit(node.right) local = self.generate_next_tvar_id() - self.current_function.instructions.append(LocalNode(local)) - self.current_function.instructions.append( + self.register_instruction(LocalNode(local)) + self.register_instruction( MinusNode(local, left, right) ) @@ -286,8 +319,8 @@ def visit(self, node): right = self.visit(node.right) local = self.generate_next_tvar_id() - self.current_function.instructions.append(LocalNode(local)) - self.current_function.instructions.append( + self.register_instruction(LocalNode(local)) + self.register_instruction( StarNode(local, left, right) ) @@ -297,8 +330,8 @@ def visit(self, node): right = self.visit(node.right) local = self.generate_next_tvar_id() - self.current_function.instructions.append(LocalNode(local)) - self.current_function.instructions.append( + self.register_instruction(LocalNode(local)) + self.register_instruction( DivNode(local, left, right) ) @visitor.when(cool.LessEqualNode) @@ -307,8 +340,8 @@ def visit(self, node): right = self.visit(node.right) local = self.generate_next_tvar_id() - self.current_function.instructions.append(LocalNode(local)) - self.current_function.instructions.append( + self.register_instruction(LocalNode(local)) + self.register_instruction( LessEqualNode(local, left, right) ) @@ -318,8 +351,8 @@ def visit(self, node): right = self.visit(node.right) local = self.generate_next_tvar_id() - self.current_function.instructions.append(LocalNode(local)) - self.current_function.instructions.append( + self.register_instruction(LocalNode(local)) + self.register_instruction( LessNode(local, left, right) ) @visitor.when(cool.EqualNode) @@ -328,16 +361,16 @@ def visit(self, node): right = self.visit(node.right) local = self.generate_next_tvar_id() - self.current_function.instructions.append(LocalNode(local)) - self.current_function.instructions.append( + self.register_instruction(LocalNode(local)) + self.register_instruction( EqualNode(local, left, right) ) #Unary operators @visitor.when(cool.InstantiateNode) # NewNode def visit(self, node): new_local = self.generate_next_tvar_id() - self.current_function.instructions.append(LocalNode(new_local)) - self.current_function.instructions.append(AllocateNode(node.lex, new_local)) + self.register_instruction(LocalNode(new_local)) + self.register_instruction(AllocateNode(node.lex, new_local)) @visitor.when(cool.IsvoidNode) def visit(self, node): @@ -348,16 +381,16 @@ def visit(self, node): def visit(self, node): value = self.visit(node.expr) local = self.generate_next_tvar_id() - self.current_function.instructions.append(LocalNode(local)) - self.current_function.instructions.append(NotNode(local, value)) + self.register_instruction(LocalNode(local)) + self.register_instruction(NotNode(local, value)) @visitor.when(cool.NegNode) def visit(self, node): value = self.visit(node.expr) local = self.generate_next_tvar_id() - self.current_function.instructions.append(LocalNode(local)) - self.current_function.instructions.append(IntComplementNode(local, value)) + self.register_instruction(LocalNode(local)) + self.register_instruction(IntComplementNode(local, value)) @visitor.when(cool.ConstantNumNode) From 250a4b713e947fdaee7caeaf4aafecf12eef9cdb Mon Sep 17 00:00:00 2001 From: gabriela Date: Wed, 23 Feb 2022 18:24:47 -0500 Subject: [PATCH 048/162] Report token's row and column in parser. Edit pipeline so the parser has access to the row and column of the current token. --- src/lexical_analizer.py | 8 +++++++- src/main.py | 4 ++-- src/shift_reduce_parsers.py | 35 +++++++++++++++++++++++++---------- src/tokens_rules.py | 1 + src/utils.py | 3 +++ 5 files changed, 38 insertions(+), 13 deletions(-) create mode 100644 src/utils.py diff --git a/src/lexical_analizer.py b/src/lexical_analizer.py index 92eb77dee..89c01d4bc 100644 --- a/src/lexical_analizer.py +++ b/src/lexical_analizer.py @@ -35,11 +35,13 @@ def tokenize_cool_text(grammar, idx, type_id, string, num, data, errors, printin } tokens = [] + pos_data = [] # Tokenize while True: tok = lexer.token() if not tok: tokens.append(Token("$", grammar.EOF)) + pos_data.append([-1,-1]) break # No more input else: try: @@ -53,10 +55,14 @@ def tokenize_cool_text(grammar, idx, type_id, string, num, data, errors, printin elif tok.type == "id": tokens.append(Token(tok.value, idx)) elif tok.type == "type_id": + print(tok.value) + print(tok.lineno) + print(tok.lexpos) tokens.append(Token(tok.value, type_id)) else: tokens.append(Token(tok.value, num)) + pos_data.append([tok.lineno,tok.lexpos]) if printing: pprint_tokens(tokens) - return tokens + return tokens, pos_data diff --git a/src/main.py b/src/main.py index 276f14524..8fb085c76 100644 --- a/src/main.py +++ b/src/main.py @@ -41,7 +41,7 @@ def pipeline(input_file: Path, output_file: Path = None): # define grammar grammar, idx, type_id, string, num = define_cool_grammar() - tokens = tokenize_cool_text(grammar, idx, type_id, string, num, text, errors) + tokens, pos_data = tokenize_cool_text(grammar, idx, type_id, string, num, text, errors) # print(tokens) if len(errors) > 0: report_and_exit(errors) @@ -50,7 +50,7 @@ def pipeline(input_file: Path, output_file: Path = None): if len(errors) > 0: report_and_exit(errors) - parse, operations = parser([t.token_type for t in tokens]) + parse, operations = parser([t.token_type for t in tokens], [t.lex for t in tokens], pos_data, text) print("Parse") print(parse) diff --git a/src/shift_reduce_parsers.py b/src/shift_reduce_parsers.py index 33f0e72fd..71282f74a 100644 --- a/src/shift_reduce_parsers.py +++ b/src/shift_reduce_parsers.py @@ -6,7 +6,7 @@ from methods import compute_firsts, compute_local_first, compute_follows from cmp.automata import State from errors import shift_reduce_error, invalid_sentence_error, SyntacticError - +from utils import find_column class ShiftReduceParser: SHIFT = "SHIFT" @@ -24,7 +24,7 @@ def __init__(self, G, errors, verbose=False): def _build_parsing_table(self): raise NotImplementedError() - def __call__(self, w): + def __call__(self, w, values, pos, text): stack = [0] cursor = 0 output = [] @@ -41,13 +41,27 @@ def __call__(self, w): action, tag = self.action[state, lookahead] except KeyError: + print("State before error") + print(state) + print(lookahead) + print("cursor") + print(cursor) + + # self.errors.append( + # SyntacticError( + # cursor, + # 0, + # "No transition available. Sentence given does not belong to the grammar", + # ) + # ) self.errors.append( SyntacticError( - cursor, - 0, - "No transition available. Sentence given does not belong to the grammar", + pos[cursor][0], + find_column(text, pos[cursor][1]), + "ERROR at or near "+ str(values[cursor]) ) ) + return output, operations # Exception( # "No transition available" @@ -74,18 +88,19 @@ def __call__(self, w): else: self.errors.append( SyntacticError( - cursor, - 0, - "Invalid case. Sentence given does not belong to the grammar", + pos[cursor][0], + find_column(text, pos[cursor][1]), + "ERROR at or near"+ values[cursor] ) ) return output, operations + # "Invalid case. Sentence given does not belong to the grammar", if cursor >= len(w): # or not stack self.errors.append( SyntacticError( - cursor - 1, - 0, + pos[cursor][-1], + find_column(text, pos[cursor][-1]), "Exceed word length while looking for a viable derivation. Sentence given does not belong to the grammar", ) ) diff --git a/src/tokens_rules.py b/src/tokens_rules.py index 9835ce69d..50b65f070 100644 --- a/src/tokens_rules.py +++ b/src/tokens_rules.py @@ -134,6 +134,7 @@ def t_type_id(t): t.type = reserved.get( t.value, "type_id" ) # Check for reserved words. If it isn't a reserved word is categorized as identifier + # t.lexpos = t.lexpos - t.lexer.last_new_line_pos + 1 return t # matching int numbers diff --git a/src/utils.py b/src/utils.py new file mode 100644 index 000000000..6ac51a3d2 --- /dev/null +++ b/src/utils.py @@ -0,0 +1,3 @@ +def find_column(input, lexpos): + line_start = input.rfind('\n', 0, lexpos) + 1 + return (lexpos - line_start) + 1 \ No newline at end of file From 27ade0e12db7651bdc2f608a044bc94e14b85ba1 Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Wed, 23 Feb 2022 19:27:25 -0500 Subject: [PATCH 049/162] fix: fix compile and runtime errors to run hello_world test --- customized_tests/test_hello_world.cl | 7 ++ src/cmp/cil.py | 126 +++++++++++----------- src/code_gen/cil_builder.py | 151 +++++++++++++-------------- src/main.py | 18 +++- 4 files changed, 158 insertions(+), 144 deletions(-) create mode 100644 customized_tests/test_hello_world.cl diff --git a/customized_tests/test_hello_world.cl b/customized_tests/test_hello_world.cl new file mode 100644 index 000000000..032d82dc9 --- /dev/null +++ b/customized_tests/test_hello_world.cl @@ -0,0 +1,7 @@ +class Main inherits IO { + msg : String <- " Hello World "; + + main() : IO{ + self.print(msg) + }; +}; \ No newline at end of file diff --git a/src/cmp/cil.py b/src/cmp/cil.py index 5c62d776f..32bc74800 100644 --- a/src/cmp/cil.py +++ b/src/cmp/cil.py @@ -215,86 +215,86 @@ def __init__(self, str_addr): self.str_addr = str_addr -def get_formatter(): - class PrintVisitor(object): - @visitor.on("node") - def visit(self, node): - pass +class PrintVisitor(object): + @visitor.on("node") + def visit(self, node): + pass - @visitor.when(ProgramNode) - def visit(self, node): - dottypes = "\n".join(self.visit(t) for t in node.dottypes) - dotdata = "\n".join(self.visit(t) for t in node.dotdata) - dotcode = "\n".join(self.visit(t) for t in node.dotcode) + @visitor.when(ProgramNode) + def visit(self, node): + dottypes = "\n".join(self.visit(t) for t in node.dottypes) + dotdata = "\n".join(self.visit(t) for t in node.dotdata) + dotcode = "\n".join(self.visit(t) for t in node.dotcode) - return f".TYPES\n{dottypes}\n\n.DATA\n{dotdata}\n\n.CODE\n{dotcode}" + return f".TYPES\n{dottypes}\n\n.DATA\n{dotdata}\n\n.CODE\n{dotcode}" - @visitor.when(TypeNode) - def visit(self, node): - attributes = "\n\t".join(f"attribute {x}" for x in node.attributes) - methods = "\n\t".join(f"method {x}: {y}" for x, y in node.methods) + @visitor.when(TypeNode) + def visit(self, node): + attributes = "\n\t".join(f"attribute {x}" for x in node.attributes) + methods = "\n\t".join(f"method {x}: {y}" for x, y in node.methods) - return f"type {node.name} {{\n\t{attributes}\n\n\t{methods}\n}}" + return f"type {node.name} {{\n\t{attributes}\n\n\t{methods}\n}}" - @visitor.when(FunctionNode) - def visit(self, node): - params = "\n\t".join(self.visit(x) for x in node.params) - localvars = "\n\t".join(self.visit(x) for x in node.localvars) - instructions = "\n\t".join(self.visit(x) for x in node.instructions) + @visitor.when(FunctionNode) + def visit(self, node): + params = "\n\t".join(self.visit(x) for x in node.params) + localvars = "\n\t".join(self.visit(x) for x in node.localvars) + instructions = "\n\t".join(self.visit(x) for x in node.instructions) - return f"function {node.name} {{\n\t{params}\n\n\t{localvars}\n\n\t{instructions}\n}}" + return f"function {node.name} {{\n\t{params}\n\n\t{localvars}\n\n\t{instructions}\n}}" - @visitor.when(ParamNode) - def visit(self, node): - return f"PARAM {node.name}" + @visitor.when(ParamNode) + def visit(self, node): + return f"PARAM {node.name}" - @visitor.when(LocalNode) - def visit(self, node): - return f"LOCAL {node.name}" + @visitor.when(LocalNode) + def visit(self, node): + return f"LOCAL {node.name}" - @visitor.when(AssignNode) - def visit(self, node): - return f"{node.dest} = {node.source}" + @visitor.when(AssignNode) + def visit(self, node): + return f"{node.dest} = {node.source}" - @visitor.when(PlusNode) - def visit(self, node): - return f"{node.dest} = {node.left} + {node.right}" + @visitor.when(PlusNode) + def visit(self, node): + return f"{node.dest} = {node.left} + {node.right}" - @visitor.when(MinusNode) - def visit(self, node): - return f"{node.dest} = {node.left} - {node.right}" + @visitor.when(MinusNode) + def visit(self, node): + return f"{node.dest} = {node.left} - {node.right}" - @visitor.when(StarNode) - def visit(self, node): - return f"{node.dest} = {node.left} * {node.right}" + @visitor.when(StarNode) + def visit(self, node): + return f"{node.dest} = {node.left} * {node.right}" - @visitor.when(DivNode) - def visit(self, node): - return f"{node.dest} = {node.left} / {node.right}" + @visitor.when(DivNode) + def visit(self, node): + return f"{node.dest} = {node.left} / {node.right}" - @visitor.when(AllocateNode) - def visit(self, node): - return f"{node.dest} = ALLOCATE {node.type}" + @visitor.when(AllocateNode) + def visit(self, node): + return f"{node.dest} = ALLOCATE {node.type}" - @visitor.when(TypeOfNode) - def visit(self, node): - return f"{node.dest} = TYPEOF {node.type}" + @visitor.when(TypeOfNode) + def visit(self, node): + return f"{node.dest} = TYPEOF {node.type}" - @visitor.when(StaticCallNode) - def visit(self, node): - return f"{node.dest} = CALL {node.function}" + @visitor.when(StaticCallNode) + def visit(self, node): + return f"{node.dest} = CALL {node.function}" - @visitor.when(DynamicCallNode) - def visit(self, node): - return f"{node.dest} = VCALL {node.type} {node.method}" + @visitor.when(DynamicCallNode) + def visit(self, node): + return f"{node.dest} = VCALL {node.type} {node.method}" - @visitor.when(ArgNode) - def visit(self, node): - return f"ARG {node.name}" + @visitor.when(ArgNode) + def visit(self, node): + return f"ARG {node.name}" - @visitor.when(ReturnNode) - def visit(self, node): - return f'RETURN {node.value if node.value is not None else ""}' + @visitor.when(ReturnNode) + def visit(self, node): + return f'RETURN {node.value if node.value is not None else ""}' - printer = PrintVisitor() - return lambda ast: printer.visit(ast) + +# printer = PrintVisitor() +# return lambda ast: printer.visit(ast) diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index 32ad84b8c..bcb275b5f 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -3,25 +3,9 @@ import ast_nodes as cool -from cil_nodes import ( - StringCil, - TypeCil, - AttributeCil, - MethodCil, - ProgramCil, - FunctionCil, - ArgCil, - LocalCil, - AssignmentCil, - IfCil, - LabelCil, - GotoCil, -) - from cmp.cil import ( ProgramNode, TypeNode, - MethodNode, DataNode, FunctionNode, ParamNode, @@ -53,7 +37,7 @@ IntComplementNode, LessNode, LessEqualNode, - EqualNode + EqualNode, ) from cool_visitor import FormatVisitor @@ -95,10 +79,15 @@ def next_id(self): return str(self._count) def to_function_name(self, method_name, type_name): - return f'function_{method_name}_at_{type_name}' + return f"function_{method_name}_at_{type_name}" def register_instruction(self, instruction): - self.register_instruction(instruction) + self.current_function.instructions.append(instruction) + + def register_type(self, name): + type_node = TypeNode(name) + self.types.append(type_node) + return type_node @visitor.on("node") def visit(self, node=None): @@ -108,8 +97,8 @@ def visit(self, node=None): def visit(self, node): self.context = node.context - #Add entry function and call Main.main() - self.current_function = FunctionNode("entry", [],[],[]) + # Add entry function and call Main.main() + self.current_function = FunctionNode("entry", [], [], []) self.code.append(self.current_function) instance = self.generate_next_tvar_id() @@ -119,7 +108,7 @@ def visit(self, node): self.register_instruction(LocalNode(result)) main_method_name = self.to_function_name("Main", "main") - self.register_instruction(AllocateNode("Main",instance)) + self.register_instruction(AllocateNode("Main", instance)) self.register_instruction(ArgNode(instance)) self.register_instruction(StaticCallNode(main_method_name, result)) self.register_instruction(ReturnNode(0)) @@ -129,13 +118,13 @@ def visit(self, node): for declaration in node.declarations: self.visit(declaration) - #Reset state + # Reset state self.types = [] self.code = [] self.data = [] self.current_type = None self.current_function = None - self.errors = errors + self.errors = [] self.method_count = 0 self.string_count = 0 self.temp_vars_count = 0 @@ -146,9 +135,33 @@ def visit(self, node): @visitor.when(cool.ClassDeclarationNode) def visit(self, node): - self.current_type = TypeNode(node.id) + self.current_type = self.context.get_type(node.id) self.types.append(self.current_type) + type_node = self.register_type(self.current_type.name) + + visited_func = [] + current_type = self.current_type + while current_type is not None: + attributes = [attr.name for attr in current_type.attributes] + methods = [ + func.name + for func in current_type.methods + if func.name not in visited_func + ] + visited_func.extend(methods) + type_node.attributes.extend(attributes[::-1]) + type_node.methods.extend( + [ + (item, self.to_function_name(item, current_type.name)) + for item in methods[::-1] + ] + ) + current_type = current_type.parent + + type_node.attributes.reverse() + type_node.methods.reverse() + for feature in node.features: self.visit(feature) @@ -156,17 +169,11 @@ def visit(self, node): @visitor.when(cool.AttrDeclarationNode) def visit(self, node): - # Add attribute to current type's list of attributes (cool type of the attribute is ignored) - self.current_type.attributes.append(node.id) - - # Visit initial expression #TODO: Is it necessary? - self.visit(node.init_exp) + pass @visitor.when(cool.FuncDeclarationNode) def visit(self, node): - self.current_method = self.context.get_type(self.current_type).get_method( - node.id - ) + self.current_method = self.current_type.get_method(node.id) # Generate ref ref = self.generate_next_method_id() @@ -182,15 +189,13 @@ def visit(self, node): self.code.append(function) # Body - value = None - for instruction in node.body: - value = self.visit(instruction) + value = self.visit(node.body) # Handle return if isinstance(self.current_method.return_type, VoidType): value = None - self.code.append(ReturnNode(value)) + self.register_instruction(ReturnNode(value)) self.current_method = None self.current_function = None @@ -198,17 +203,17 @@ def visit(self, node): def visit(self, node): # Add LOCAL variable local = LocalNode(node.id) - self.current_function.locals.append(local) + self.current_function.localvars.append(local) # Add Assignment Node if node.expr: expr = self.visit(node.expr) - self.current_function.body.append(AssignNode(local.id, expr)) + self.register_instruction(AssignNode(local.id, expr)) @visitor.when(cool.AssignNode) def visit(self, node): expr = self.visit(node.expr) - self.current_function.body.append(AssignNode(node.id, expr)) + self.register_instruction(AssignNode(node.id, expr)) @visitor.when(cool.CallNode) def visit(self, node): @@ -219,21 +224,21 @@ def visit(self, node): # IF condition GOTO label condition_value = self.visit(node.if_expr) then_label = "THEN_" + self.next_id() - self.current_function.body.append(GotoIfNode(condition_value, then_label)) + self.register_instruction(GotoIfNode(condition_value, then_label)) # Else self.visit(node.else_expr) # GOTO end_label end_label = "END_IF_" + self.next_id() # Example: END_IF_120 - self.current_function.body.append(GotoNode(end_label)) + self.register_instruction(GotoNode(end_label)) # Then label - self.current_function.body.append(LabelNode(then_label)) + self.register_instruction(LabelNode(then_label)) self.visit(node.then_expr) # end_label - self.current_function.body.append(LabelNode(end_label)) + self.register_instruction(LabelNode(end_label)) # TODO: return something? @@ -241,28 +246,28 @@ def visit(self, node): def visit(self, node): # While label while_label = "WHILE_" + self.next_id() - self.current_function.body.append(LabelNode(while_label)) + self.register_instruction(LabelNode(while_label)) # Condition c = self.visit(node.condition) # TODO: pop from stack # If condition GOTO body_label body_label = "BODY_" + self.next_id() - self.current_function.body.append(GotoIfNode(c, body_label)) + self.register_instruction(GotoIfNode(c, body_label)) # GOTO end_while label end_while_label = "END_WHILE_" + self.next_id() - self.current_function.body.append(GotoNode(end_while_label)) + self.register_instruction(GotoNode(end_while_label)) # Body - self.current_function.body.append(LabelNode(body_label)) + self.register_instruction(LabelNode(body_label)) self.visit(node.body) # GOTO while label - self.current_function.body.append(GotoNode(while_label)) + self.register_instruction(GotoNode(while_label)) # End while label - self.current_function.body.append(LabelNode(end_while_label)) + self.register_instruction(LabelNode(end_while_label)) @visitor.when(cool.BlockNode) def visit(self, node): @@ -282,13 +287,11 @@ def visit(self, node): @visitor.when(cool.CaseNode) def visit(self, node): - pass #TODO: Pending!!! - + pass # TODO: Pending!!! @visitor.when(cool.CaseItemNode) def visit(self, node): - pass #TODO: Pending!!! - + pass # TODO: Pending!!! # Arithmetic and comparison operators @visitor.when(cool.PlusNode) @@ -298,9 +301,7 @@ def visit(self, node): local = self.generate_next_tvar_id() self.register_instruction(LocalNode(local)) - self.register_instruction( - PlusNode(local, left, right) - ) + self.register_instruction(PlusNode(local, left, right)) @visitor.when(cool.MinusNode) def visit(self, node): @@ -309,9 +310,7 @@ def visit(self, node): local = self.generate_next_tvar_id() self.register_instruction(LocalNode(local)) - self.register_instruction( - MinusNode(local, left, right) - ) + self.register_instruction(MinusNode(local, left, right)) @visitor.when(cool.StarNode) def visit(self, node): @@ -320,9 +319,7 @@ def visit(self, node): local = self.generate_next_tvar_id() self.register_instruction(LocalNode(local)) - self.register_instruction( - StarNode(local, left, right) - ) + self.register_instruction(StarNode(local, left, right)) @visitor.when(cool.DivNode) def visit(self, node): @@ -331,9 +328,8 @@ def visit(self, node): local = self.generate_next_tvar_id() self.register_instruction(LocalNode(local)) - self.register_instruction( - DivNode(local, left, right) - ) + self.register_instruction(DivNode(local, left, right)) + @visitor.when(cool.LessEqualNode) def visit(self, node): left = self.visit(node.left) @@ -341,9 +337,7 @@ def visit(self, node): local = self.generate_next_tvar_id() self.register_instruction(LocalNode(local)) - self.register_instruction( - LessEqualNode(local, left, right) - ) + self.register_instruction(LessEqualNode(local, left, right)) @visitor.when(cool.LessNode) def visit(self, node): @@ -352,9 +346,8 @@ def visit(self, node): local = self.generate_next_tvar_id() self.register_instruction(LocalNode(local)) - self.register_instruction( - LessNode(local, left, right) - ) + self.register_instruction(LessNode(local, left, right)) + @visitor.when(cool.EqualNode) def visit(self, node): left = self.visit(node.left) @@ -362,10 +355,9 @@ def visit(self, node): local = self.generate_next_tvar_id() self.register_instruction(LocalNode(local)) - self.register_instruction( - EqualNode(local, left, right) - ) - #Unary operators + self.register_instruction(EqualNode(local, left, right)) + + # Unary operators @visitor.when(cool.InstantiateNode) # NewNode def visit(self, node): new_local = self.generate_next_tvar_id() @@ -384,7 +376,6 @@ def visit(self, node): self.register_instruction(LocalNode(local)) self.register_instruction(NotNode(local, value)) - @visitor.when(cool.NegNode) def visit(self, node): value = self.visit(node.expr) @@ -392,7 +383,6 @@ def visit(self, node): self.register_instruction(LocalNode(local)) self.register_instruction(IntComplementNode(local, value)) - @visitor.when(cool.ConstantNumNode) def visit(self, node): return node.lex @@ -409,4 +399,7 @@ def visit(self, node): @visitor.when(cool.BooleanNode) def visit(self, node): - return node.lex == "true": 1 : 0 \ No newline at end of file + if node.lex == "true": + return 1 + else: + return 0 diff --git a/src/main.py b/src/main.py index ed0655348..c678f924c 100644 --- a/src/main.py +++ b/src/main.py @@ -12,6 +12,9 @@ from cmp.evaluation import evaluate_reverse_parse from pathlib import Path from errors import InvalidInputFileError +from cool_visitor import FormatVisitor +from code_gen.cil_builder import CILBuilder +from cmp.cil import PrintVisitor import typer @@ -59,11 +62,22 @@ def pipeline(input_file: Path, output_file: Path = None): for visitor in visitors: ast = visitor.visit(ast) + formatter = FormatVisitor() + tree = formatter.visit(ast) + print(tree) + if len(errors) > 0: report_and_exit(errors) - if output_file is None: - output_file = input.with_suffix(".mips") + cool_to_cil_visitor = CILBuilder(errors) + cil_ast = cool_to_cil_visitor.visit(ast) + + formatter = PrintVisitor() + tree = formatter.visit(cil_ast) + print(tree) + + # if output_file is None: + # output_file = input.with_suffix(".mips") if __name__ == "__main__": From 83ee3439249fab82a810a4a2cd270fb49feba973 Mon Sep 17 00:00:00 2001 From: smartos99 Date: Wed, 23 Feb 2022 19:27:31 -0500 Subject: [PATCH 050/162] Initial cil to mips code, still not working --- src/code_gen/mips_builder.py | 98 ++++++++++++++++++++++++++++++++++++ src/code_gen/mips_nodes.py | 86 +++++++++++++++++++++++++++++++ src/code_gen/mips_writer.py | 12 +++++ src/code_gen/util_values.py | 0 4 files changed, 196 insertions(+) create mode 100644 src/code_gen/mips_builder.py create mode 100644 src/code_gen/mips_nodes.py create mode 100644 src/code_gen/mips_writer.py create mode 100644 src/code_gen/util_values.py diff --git a/src/code_gen/mips_builder.py b/src/code_gen/mips_builder.py new file mode 100644 index 000000000..de67ddd13 --- /dev/null +++ b/src/code_gen/mips_builder.py @@ -0,0 +1,98 @@ +from atexit import register +from email.quoprimime import body_length +import cmp.visitor as visitor +import cmp.cil as cil + +import mips_nodes as mips + +t0 = "$t0" +t1 = "$t1" +t2 = "$t2" +t3 = "$t3" +t6 = "$t6" # convenios +t7 = "$t7" # convenios +a0 = "$a0" +a1 = "$a1" +fp = "$fp" +sp = "$sp" +ra = "$ra" +lo = "lo" +hi = "hi" +v0 = "$v0" +s0 = "$s0" +s1 = "$s1" +s2 = "$s2" +s3 = "$s3" +zero = "$zero" + +#type_info offsets +TYPENAME_OFFSET = 0 +PARENT_OFFSET = 4 +SIZE_OFFSET = 8 + + +SYSCALL_PRINT_INT = 1 +SYSCALL_PRINT_STR = 4 +SYSCALL_READ_INT = 5 +SYSCALL_READ_STR = 8 +SYSCALL_SBRK = 9 +SYSCALL_EXIT = 10 + + +class MIPSBuilder: + def __init__(self,errors,cil_ast): + self.mips_code = "" + self.cil_ast = cil_ast + self.cil_types = cil_ast.types + self.cil_code = cil_ast.code + self.cil_data = cil_ast.data + self.main_procedure = mips.ProcedureNode("main") + self.current_procedure = self.main_procedure + self.text = [self.main_procedure] + self.data = [] + + def register_instruction(self, instruction_type, *args): + instruction = instruction_type(*args) + self.current_procedure.instructions.append(instruction) + + def register_data(self,data_type,*args): + data = data_type(*args) + self.data.append(data) + + @visitor.on("node") + def visit(self, node=None): + pass + + @visitor.when(cil.ProgramNode) + def visit(self, node): + for type in node.types: + self.visit(type) + + + for str_data in node.data: + self.visit(str_data) + + for instruction in node.code: + self.visit(instruction) + + + return mips.ProgramNode(self.data,self.text) + + + @visitor.when(cil.TypeNode) + def visit(self, node): + + #for func in node.methods: + values = [-1]*(len(node.methods)+1) + self.register_data(mips.DataTypeNode,'.word',node.name,values) + self.register_data(mips.DataTypeNode, f'{node.name}_cname','.asciiz', [f'"{node.name}"']) + + + #Filling type VT + self.register_instruction(mips.CommentNode(f"Filling {node.name} VT")) + self.register_instruction(mips.LoadAddress(t0,node.name)) + + + + + \ No newline at end of file diff --git a/src/code_gen/mips_nodes.py b/src/code_gen/mips_nodes.py new file mode 100644 index 000000000..c23902e76 --- /dev/null +++ b/src/code_gen/mips_nodes.py @@ -0,0 +1,86 @@ +from soupsieve import select + + +class MIPS_Node: + pass + + +class ProgramNode(MIPS_Node): + def __init__(self, data, code): + self.data = data + self.text = code + +class MIPSDataNode(MIPS_Node): + pass + +class MIPSInstructionNode(MIPS_Node): + pass + +class DataTransferNode(MIPSInstructionNode): + pass + +class ProcedureNode(MIPSInstructionNode): + def __init__(self, label): + self.label = label + self.instructions = [] + + + +class DataTransferWithOffset(DataTransferNode): + def __init__(self,source,offset,dest): + self.source = source + self.offset = offset + self.destination = dest + +class LoadWordNode(DataTransferWithOffset): + def __str__(self): + return f'lw {self.source}, {str(self.offset)}({self.destination})' + +class StoreWordNode(DataTransferWithOffset): + def __str__(self): + return f'sw {self.source}, {str(self.offset)}({self.destination})' + +class LoadNode(DataTransferNode): + def __init__(self,dest,value): + self.destination = dest + self.value + +class LoadInmediate(LoadNode): + def __str__(self): + return f'li {self.destination}, {self.value}' + +class LoadAddress(LoadNode): + def __str__(self): + return f'la {self.destination}, {self.value}' + +class MoveNode(DataTransferNode): + def __init__(self, destination, source): + self.destination = destination + self.source = source + + def __str__(self): + return f"move {self.destination} {self.source}" + + + + + + +class DataTypeNode(MIPSDataNode): + def __init__(self, name, datatype,vt_values): + self.name = name + self.datatype = datatype + self.vt_values = vt_values + + def __str__(self): + values = "" + for value in self.vt_values: + values += f", {value}" + return f"{self.name} : {self.datatype}{values}" + +class CommentNode(MIPS_Node): + def __init__(self,text): + self.text = text + + def __str__(self): + return f"#{self.text}" \ No newline at end of file diff --git a/src/code_gen/mips_writer.py b/src/code_gen/mips_writer.py new file mode 100644 index 000000000..d945879e5 --- /dev/null +++ b/src/code_gen/mips_writer.py @@ -0,0 +1,12 @@ +import cmp.visitor as visitor + + +from mips_nodes import ( + MIPSProgramNode, + MIPSDataTypeNode +) + + + + + \ No newline at end of file diff --git a/src/code_gen/util_values.py b/src/code_gen/util_values.py new file mode 100644 index 000000000..e69de29bb From 9be0a4d50a2dfed1aa69afcc45aec2f193442900 Mon Sep 17 00:00:00 2001 From: gabriela Date: Wed, 23 Feb 2022 19:31:56 -0500 Subject: [PATCH 051/162] Consider case insentive keywords. --- src/cmp/evaluation.py | 1 - src/lexical_analizer.py | 3 --- src/main.py | 3 ++- src/tokens_rules.py | 13 +++++++++---- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/cmp/evaluation.py b/src/cmp/evaluation.py index f54d09279..ebe01f5c5 100644 --- a/src/cmp/evaluation.py +++ b/src/cmp/evaluation.py @@ -30,7 +30,6 @@ def evaluate_reverse_parse(right_parse, operations, tokens): stack.append(rule(None, None)) else: raise Exception("Invalid action!!!") - assert len(stack) == 1 assert isinstance(next(tokens).token_type, EOF) return stack[0] diff --git a/src/lexical_analizer.py b/src/lexical_analizer.py index 89c01d4bc..f71a54ed9 100644 --- a/src/lexical_analizer.py +++ b/src/lexical_analizer.py @@ -55,9 +55,6 @@ def tokenize_cool_text(grammar, idx, type_id, string, num, data, errors, printin elif tok.type == "id": tokens.append(Token(tok.value, idx)) elif tok.type == "type_id": - print(tok.value) - print(tok.lineno) - print(tok.lexpos) tokens.append(Token(tok.value, type_id)) else: tokens.append(Token(tok.value, num)) diff --git a/src/main.py b/src/main.py index 8fb085c76..aa553572a 100644 --- a/src/main.py +++ b/src/main.py @@ -42,7 +42,8 @@ def pipeline(input_file: Path, output_file: Path = None): grammar, idx, type_id, string, num = define_cool_grammar() tokens, pos_data = tokenize_cool_text(grammar, idx, type_id, string, num, text, errors) - # print(tokens) + print(tokens) + if len(errors) > 0: report_and_exit(errors) parser = LR1Parser(grammar, errors) diff --git a/src/tokens_rules.py b/src/tokens_rules.py index 50b65f070..78f9c0f9b 100644 --- a/src/tokens_rules.py +++ b/src/tokens_rules.py @@ -23,6 +23,7 @@ "type_id", "int", "string", + "if", ] # Add "ccom" to test comments @@ -124,16 +125,20 @@ def t_comments_eof(t): def t_id(t): r"[a-z][a-zA-Z_0-9]*" t.type = reserved.get( - t.value, "id" + t.value.lower(), "id" ) # Check for reserved words. If it isn't a reserved word is categorized as identifier return t #Type identifiers def t_type_id(t): r"[A-Z][a-zA-Z_0-9]*" - t.type = reserved.get( - t.value, "type_id" - ) # Check for reserved words. If it isn't a reserved word is categorized as identifier + value_in_lowercase = t.value.lower() + if value_in_lowercase != "false" and value_in_lowercase != "true": + t.type = reserved.get( + value_in_lowercase, "type_id" + ) # Check for reserved words. If it isn't a reserved word is categorized as identifier + else: + t.type = "type_id"#this may be extra as t.type is already setted as type_id # t.lexpos = t.lexpos - t.lexer.last_new_line_pos + 1 return t From b6e67a021ab2623e8d654a082f1b04326d9db675 Mon Sep 17 00:00:00 2001 From: gabriela Date: Wed, 23 Feb 2022 19:39:39 -0500 Subject: [PATCH 052/162] Fix error token if multiply defined. Remove if keyword from first_tokens in lexer. --- src/tokens_rules.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tokens_rules.py b/src/tokens_rules.py index 78f9c0f9b..e4f4bf6fa 100644 --- a/src/tokens_rules.py +++ b/src/tokens_rules.py @@ -23,7 +23,6 @@ "type_id", "int", "string", - "if", ] # Add "ccom" to test comments From b3f6c3c0f6deaeb0dfcd627c6e049b108183fa4b Mon Sep 17 00:00:00 2001 From: gabriela Date: Wed, 23 Feb 2022 19:47:40 -0500 Subject: [PATCH 053/162] Remove unnecessary prints. --- src/main.py | 4 ++-- src/shift_reduce_parsers.py | 18 +----------------- 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/src/main.py b/src/main.py index 1bc3f1431..7536aefce 100644 --- a/src/main.py +++ b/src/main.py @@ -56,8 +56,8 @@ def pipeline(input_file: Path, output_file: Path = None): parse, operations = parser([t.token_type for t in tokens], [t.lex for t in tokens], pos_data, text) - print("Parse") - print(parse) + # print("Parse") + # print(parse) if len(errors) > 0: report_and_exit(errors) diff --git a/src/shift_reduce_parsers.py b/src/shift_reduce_parsers.py index 71282f74a..c970efca2 100644 --- a/src/shift_reduce_parsers.py +++ b/src/shift_reduce_parsers.py @@ -41,19 +41,6 @@ def __call__(self, w, values, pos, text): action, tag = self.action[state, lookahead] except KeyError: - print("State before error") - print(state) - print(lookahead) - print("cursor") - print(cursor) - - # self.errors.append( - # SyntacticError( - # cursor, - # 0, - # "No transition available. Sentence given does not belong to the grammar", - # ) - # ) self.errors.append( SyntacticError( pos[cursor][0], @@ -63,9 +50,6 @@ def __call__(self, w, values, pos, text): ) return output, operations - # Exception( - # "No transition available" - # ) # string does not belong to this grammar # Shift case if action == self.SHIFT: @@ -94,7 +78,7 @@ def __call__(self, w, values, pos, text): ) ) return output, operations - # "Invalid case. Sentence given does not belong to the grammar", + # "Invalid case. Sentence given does not belong to the grammar", if cursor >= len(w): # or not stack self.errors.append( From 4da9d41f9ef8591f28b883b673eb20cf06becd95 Mon Sep 17 00:00:00 2001 From: gabriela Date: Wed, 23 Feb 2022 20:21:58 -0500 Subject: [PATCH 054/162] Change "new x"'s lvl in cool grammar. --- src/cool_grammar.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cool_grammar.py b/src/cool_grammar.py index 69f2de688..49abd0e7f 100644 --- a/src/cool_grammar.py +++ b/src/cool_grammar.py @@ -144,9 +144,9 @@ def define_cool_grammar(print_grammar=False): factor %= isvoid + element, lambda h, s: IsvoidNode(s[2]) factor %= neg + element, lambda h, s: NegNode(s[2]) - factor %= new + type_id, lambda h, s: InstantiateNode(s[2]) factor %= element, lambda h, s: s[1] + element %= new + type_id, lambda h, s: InstantiateNode(s[2]) element %= opar + expr + cpar, lambda h, s: s[2] element %= ocur + block + ccur, lambda h, s: BlockNode(s[2]) element %= (element + dot + func_call, lambda h, s: CallNode(*s[3], obj=s[1])) From a180fa338b99091ae26a4f121655e4318d0b26ac Mon Sep 17 00:00:00 2001 From: gabriela Date: Wed, 23 Feb 2022 23:47:28 -0500 Subject: [PATCH 055/162] Change "not" level in grammar. Change "not" expression's level in cool grammar so test operation3 is completed successfully. --- src/cool_grammar.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cool_grammar.py b/src/cool_grammar.py index 49abd0e7f..87674af8e 100644 --- a/src/cool_grammar.py +++ b/src/cool_grammar.py @@ -107,7 +107,7 @@ def define_cool_grammar(print_grammar=False): ) expr %= whilex + expr + loop + expr + pool, lambda h, s: WhileNode(s[2], s[4]) expr %= case + expr + of + case_block + esac, lambda h, s: CaseNode(s[2], s[4]) - expr %= notx + expr, lambda h, s: NotNode(s[2]) + # expr %= notx + expr, lambda h, s: NotNode(s[2]) expr %= comp, lambda h, s: s[1] identifiers_list %= ( @@ -134,6 +134,7 @@ def define_cool_grammar(print_grammar=False): comp %= comp + lesseq + arith, lambda h, s: LessEqualNode(s[1], s[3]) comp %= arith, lambda h, s: s[1] + arith %= notx + term, lambda h, s: NotNode(s[2]) #used to be in expr's level arith %= arith + plus + term, lambda h, s: PlusNode(s[1], s[3]) arith %= arith + minus + term, lambda h, s: MinusNode(s[1], s[3]) arith %= term, lambda h, s: s[1] From 8a689d366c54d81dec6bc2c997d40a677dbe3972 Mon Sep 17 00:00:00 2001 From: gabriela Date: Thu, 24 Feb 2022 00:57:22 -0500 Subject: [PATCH 056/162] Modify grammar to detect missing parameters. --- src/cool_grammar.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/cool_grammar.py b/src/cool_grammar.py index 87674af8e..f3f5a54b9 100644 --- a/src/cool_grammar.py +++ b/src/cool_grammar.py @@ -41,13 +41,13 @@ def define_cool_grammar(print_grammar=False): feature_list, def_attr, def_func = G.NonTerminals( " " ) - param_list, param = G.NonTerminals(" ") + param_list, param_list_rest, param = G.NonTerminals(" ") expr, comp, arith, term, factor, element, atom = G.NonTerminals( " " ) identifiers_list, identifier_init = G.NonTerminals(" ") block, case_block, case_item = G.NonTerminals(" ") - func_call, arg_list = G.NonTerminals(" ") + func_call, arg_list, arg_list_rest = G.NonTerminals(" ") # terminals classx, inherits, notx, isvoid = G.Terminals("class inherits not isvoid") @@ -93,10 +93,13 @@ def define_cool_grammar(print_grammar=False): lambda h, s: FuncDeclarationNode(s[1], s[3], s[6], s[8]), ) - param_list %= param + comma + param_list, lambda h, s: [s[1]] + s[3] + param_list %= param + param_list_rest, lambda h, s: [s[1]] + s[2] param_list %= param, lambda h, s: [s[1]] param_list %= G.Epsilon, lambda h, s: [] + param_list_rest %= comma + param + param_list_rest, lambda h, s: [s[2]] + s[3] + param_list_rest %= comma + param, lambda h, s: [s[2]] + param %= idx + colon + type_id, lambda h, s: (s[1], s[3]) expr %= idx + larrow + expr, lambda h, s: AssignNode(s[1], s[3]) @@ -107,7 +110,6 @@ def define_cool_grammar(print_grammar=False): ) expr %= whilex + expr + loop + expr + pool, lambda h, s: WhileNode(s[2], s[4]) expr %= case + expr + of + case_block + esac, lambda h, s: CaseNode(s[2], s[4]) - # expr %= notx + expr, lambda h, s: NotNode(s[2]) expr %= comp, lambda h, s: s[1] identifiers_list %= ( @@ -134,7 +136,7 @@ def define_cool_grammar(print_grammar=False): comp %= comp + lesseq + arith, lambda h, s: LessEqualNode(s[1], s[3]) comp %= arith, lambda h, s: s[1] - arith %= notx + term, lambda h, s: NotNode(s[2]) #used to be in expr's level + arith %= notx + term, lambda h, s: NotNode(s[2]) arith %= arith + plus + term, lambda h, s: PlusNode(s[1], s[3]) arith %= arith + minus + term, lambda h, s: MinusNode(s[1], s[3]) arith %= term, lambda h, s: s[1] @@ -172,10 +174,13 @@ def define_cool_grammar(print_grammar=False): func_call %= idx + opar + arg_list + cpar, lambda h, s: (s[1], s[3]) - arg_list %= expr + comma + arg_list, lambda h, s: [s[1]] + s[3] + arg_list %= expr + arg_list_rest, lambda h, s: [s[1]] + s[2] arg_list %= expr, lambda h, s: [s[1]] arg_list %= G.Epsilon, lambda h, s: [] + arg_list_rest %= comma + expr + arg_list_rest, lambda h, s: [s[2]] + s[3] + arg_list_rest %= comma + expr, lambda h, s: [s[2]] + if print_grammar: print(G) return (G, idx, type_id, string, num) From 3bf6a5f70d5d4422beb3f1ea355341f6d31f2b71 Mon Sep 17 00:00:00 2001 From: gabriela Date: Thu, 24 Feb 2022 11:34:26 -0500 Subject: [PATCH 057/162] Change lvl of if-t-else, while and case exps. Modify grammar to give the language more flexibility: sum if then else instruction without parentesis for example. --- customized_tests/parser/missingcpar.cl | 15 +++ .../parser/sum_if_then_else_objid.cl | 101 ++++++++++++++++++ src/cool_grammar.py | 26 ++--- 3 files changed, 129 insertions(+), 13 deletions(-) create mode 100644 customized_tests/parser/missingcpar.cl create mode 100644 customized_tests/parser/sum_if_then_else_objid.cl diff --git a/customized_tests/parser/missingcpar.cl b/customized_tests/parser/missingcpar.cl new file mode 100644 index 000000000..f208d50b1 --- /dev/null +++ b/customized_tests/parser/missingcpar.cl @@ -0,0 +1,15 @@ + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + + +class Test { + testing8(x: Int, y: Int): Bool { + let z: Int <- 3, w: Int <- 4 + -- Missing ')' + in isvoid (3 + a * (x / w + new Int) - y - (((if tRue = not faLSe then ~z else 3 <= 4 + "hey".length() fi + a)/(0)*(((4 * 4))))) + }; +}; \ No newline at end of file diff --git a/customized_tests/parser/sum_if_then_else_objid.cl b/customized_tests/parser/sum_if_then_else_objid.cl new file mode 100644 index 000000000..32478666b --- /dev/null +++ b/customized_tests/parser/sum_if_then_else_objid.cl @@ -0,0 +1,101 @@ +(* Cool has four binary arithmetic operations: +, -, *, /. *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int <- 0, pow: Int + in { + -- count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; + + testing7(): Object { + case 2 + 2 of + x: Int => new IO.out_string("Es un entero!"); + y: String => new IO.out_string("Es una cadena!"); + z: Bool => new IO.out_string("Es un booleano!"); + esac + }; + + a: Int <- 1; + + testing8(x: Int, y: Int): Bool { + let z: Int <- 3, w: Int <- 4 + -- Object identifiers starts with a lowercase letter + in isvoid (3 + a * (x / w + new Int) - y - (((if tRue = not faLSe then ~mazinger_Z else 3 <= 4 + "hey".length() fi) + a)/(0)*(((4 * 4))))) + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; \ No newline at end of file diff --git a/src/cool_grammar.py b/src/cool_grammar.py index f3f5a54b9..012cb5f16 100644 --- a/src/cool_grammar.py +++ b/src/cool_grammar.py @@ -104,12 +104,6 @@ def define_cool_grammar(print_grammar=False): expr %= idx + larrow + expr, lambda h, s: AssignNode(s[1], s[3]) expr %= let + identifiers_list + inx + expr, lambda h, s: LetNode(s[2], s[4]) - expr %= ( - ifx + expr + then + expr + elsex + expr + fi, - lambda h, s: IfNode(s[2], s[4], s[6]), - ) - expr %= whilex + expr + loop + expr + pool, lambda h, s: WhileNode(s[2], s[4]) - expr %= case + expr + of + case_block + esac, lambda h, s: CaseNode(s[2], s[4]) expr %= comp, lambda h, s: s[1] identifiers_list %= ( @@ -124,13 +118,6 @@ def define_cool_grammar(print_grammar=False): ) identifier_init %= idx + colon + type_id, lambda h, s: VarDeclarationNode(s[1], s[3]) - case_block %= case_item + case_block, lambda h, s: [s[1]] + s[2] - case_block %= case_item, lambda h, s: [s[1]] - case_item %= ( - idx + colon + type_id + rarrow + expr + semi, - lambda h, s: CaseItemNode(s[1], s[3], s[5]), - ) - comp %= comp + less + arith, lambda h, s: LessNode(s[1], s[3]) comp %= comp + equal + arith, lambda h, s: EqualNode(s[1], s[3]) comp %= comp + lesseq + arith, lambda h, s: LessEqualNode(s[1], s[3]) @@ -149,6 +136,12 @@ def define_cool_grammar(print_grammar=False): factor %= neg + element, lambda h, s: NegNode(s[2]) factor %= element, lambda h, s: s[1] + element %= ( + ifx + expr + then + expr + elsex + expr + fi, + lambda h, s: IfNode(s[2], s[4], s[6]), + ) + element %= whilex + expr + loop + expr + pool, lambda h, s: WhileNode(s[2], s[4]) + element %= case + expr + of + case_block + esac, lambda h, s: CaseNode(s[2], s[4]) element %= new + type_id, lambda h, s: InstantiateNode(s[2]) element %= opar + expr + cpar, lambda h, s: s[2] element %= ocur + block + ccur, lambda h, s: BlockNode(s[2]) @@ -160,6 +153,13 @@ def define_cool_grammar(print_grammar=False): element %= func_call, lambda h, s: CallNode(*s[1]) element %= atom, lambda h, s: s[1] + case_block %= case_item + case_block, lambda h, s: [s[1]] + s[2] + case_block %= case_item, lambda h, s: [s[1]] + case_item %= ( + idx + colon + type_id + rarrow + expr + semi, + lambda h, s: CaseItemNode(s[1], s[3], s[5]), + ) + atom %= num, lambda h, s: ConstantNumNode(s[1]) atom %= idx, lambda h, s: VariableNode(s[1]) atom %= ( From bf99b5e94b4aaf28253ad4feb93c6996a9d36821 Mon Sep 17 00:00:00 2001 From: gabriela Date: Thu, 24 Feb 2022 12:26:35 -0500 Subject: [PATCH 058/162] Correct indexes of EOF token. --- src/lexical_analizer.py | 10 ++++++++-- src/shift_reduce_parsers.py | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/lexical_analizer.py b/src/lexical_analizer.py index f71a54ed9..09e4e4b8a 100644 --- a/src/lexical_analizer.py +++ b/src/lexical_analizer.py @@ -39,9 +39,15 @@ def tokenize_cool_text(grammar, idx, type_id, string, num, data, errors, printin # Tokenize while True: tok = lexer.token() - if not tok: + if not tok:#append EOF + if len(pos_data) > 0: + last_lineno, last_col = pos_data[-1] + col = last_col + len(tokens[-1].lex) + else:#empty program + last_lineno = 0 + col = -1 + pos_data.append([last_lineno, col]) tokens.append(Token("$", grammar.EOF)) - pos_data.append([-1,-1]) break # No more input else: try: diff --git a/src/shift_reduce_parsers.py b/src/shift_reduce_parsers.py index c970efca2..25d16a9bc 100644 --- a/src/shift_reduce_parsers.py +++ b/src/shift_reduce_parsers.py @@ -74,7 +74,7 @@ def __call__(self, w, values, pos, text): SyntacticError( pos[cursor][0], find_column(text, pos[cursor][1]), - "ERROR at or near"+ values[cursor] + "ERROR at or near"+ str(values[cursor]) ) ) return output, operations From 510a66494f593958711be2506dce0b728657cd62 Mon Sep 17 00:00:00 2001 From: smartos99 Date: Thu, 24 Feb 2022 18:59:01 -0500 Subject: [PATCH 059/162] Some visitorsadded --- src/cmp/cil.py | 168 ++++++++++++------------------ src/code_gen/mips_builder.py | 196 ++++++++++++++++++++++++++++++++--- src/code_gen/mips_nodes.py | 96 ++++++++++++++++- 3 files changed, 343 insertions(+), 117 deletions(-) diff --git a/src/cmp/cil.py b/src/cmp/cil.py index 32bc74800..fff879026 100644 --- a/src/cmp/cil.py +++ b/src/cmp/cil.py @@ -54,12 +54,7 @@ def __init__(self, dest, source): class ArithmeticNode(InstructionNode): - def __init__( - self, - dest, - left, - right, - ): + def __init__(self, dest, left, right): self.dest = dest self.left = left self.right = right @@ -81,32 +76,6 @@ class DivNode(ArithmeticNode): pass -class LessNode(ArithmeticNode): - pass - - -class LessEqualNode(ArithmeticNode): - pass - - -class EqualNode(ArithmeticNode): - pass - - -class UnaryNode(InstructionNode): - def __init__(self, dest, expr): - self.dest = dest - self.expr = expr - - -class NotNode(UnaryNode): - pass - - -class IntComplementNode(UnaryNode): - pass - - class GetAttribNode(InstructionNode): pass @@ -122,7 +91,7 @@ class GetIndexNode(InstructionNode): class SetIndexNode(InstructionNode): pass - + class AllocateNode(InstructionNode): def __init__(self, itype, dest): self.type = itype @@ -144,14 +113,11 @@ class LabelNode(InstructionNode): class GotoNode(InstructionNode): - def __init__(self, label): - self.label = label + pass class GotoIfNode(InstructionNode): - def __init__(self, condition, label): - self.condition = condition - self.label = label + pass class StaticCallNode(InstructionNode): @@ -215,86 +181,86 @@ def __init__(self, str_addr): self.str_addr = str_addr -class PrintVisitor(object): - @visitor.on("node") - def visit(self, node): - pass - - @visitor.when(ProgramNode) - def visit(self, node): - dottypes = "\n".join(self.visit(t) for t in node.dottypes) - dotdata = "\n".join(self.visit(t) for t in node.dotdata) - dotcode = "\n".join(self.visit(t) for t in node.dotcode) +def get_formatter(): + class PrintVisitor(object): + @visitor.on("node") + def visit(self, node): + pass - return f".TYPES\n{dottypes}\n\n.DATA\n{dotdata}\n\n.CODE\n{dotcode}" + @visitor.when(ProgramNode) + def visit(self, node): + dottypes = "\n".join(self.visit(t) for t in node.dottypes) + dotdata = "\n".join(self.visit(t) for t in node.dotdata) + dotcode = "\n".join(self.visit(t) for t in node.dotcode) - @visitor.when(TypeNode) - def visit(self, node): - attributes = "\n\t".join(f"attribute {x}" for x in node.attributes) - methods = "\n\t".join(f"method {x}: {y}" for x, y in node.methods) + return f".TYPES\n{dottypes}\n\n.DATA\n{dotdata}\n\n.CODE\n{dotcode}" - return f"type {node.name} {{\n\t{attributes}\n\n\t{methods}\n}}" + @visitor.when(TypeNode) + def visit(self, node): + attributes = "\n\t".join(f"attribute {x}" for x in node.attributes) + methods = "\n\t".join(f"method {x}: {y}" for x, y in node.methods) - @visitor.when(FunctionNode) - def visit(self, node): - params = "\n\t".join(self.visit(x) for x in node.params) - localvars = "\n\t".join(self.visit(x) for x in node.localvars) - instructions = "\n\t".join(self.visit(x) for x in node.instructions) + return f"type {node.name} {{\n\t{attributes}\n\n\t{methods}\n}}" - return f"function {node.name} {{\n\t{params}\n\n\t{localvars}\n\n\t{instructions}\n}}" + @visitor.when(FunctionNode) + def visit(self, node): + params = "\n\t".join(self.visit(x) for x in node.params) + localvars = "\n\t".join(self.visit(x) for x in node.localvars) + instructions = "\n\t".join(self.visit(x) for x in node.instructions) - @visitor.when(ParamNode) - def visit(self, node): - return f"PARAM {node.name}" + return f"function {node.name} {{\n\t{params}\n\n\t{localvars}\n\n\t{instructions}\n}}" - @visitor.when(LocalNode) - def visit(self, node): - return f"LOCAL {node.name}" + @visitor.when(ParamNode) + def visit(self, node): + return f"PARAM {node.name}" - @visitor.when(AssignNode) - def visit(self, node): - return f"{node.dest} = {node.source}" + @visitor.when(LocalNode) + def visit(self, node): + return f"LOCAL {node.name}" - @visitor.when(PlusNode) - def visit(self, node): - return f"{node.dest} = {node.left} + {node.right}" + @visitor.when(AssignNode) + def visit(self, node): + return f"{node.dest} = {node.source}" - @visitor.when(MinusNode) - def visit(self, node): - return f"{node.dest} = {node.left} - {node.right}" + @visitor.when(PlusNode) + def visit(self, node): + return f"{node.dest} = {node.left} + {node.right}" - @visitor.when(StarNode) - def visit(self, node): - return f"{node.dest} = {node.left} * {node.right}" + @visitor.when(MinusNode) + def visit(self, node): + return f"{node.dest} = {node.left} - {node.right}" - @visitor.when(DivNode) - def visit(self, node): - return f"{node.dest} = {node.left} / {node.right}" + @visitor.when(StarNode) + def visit(self, node): + return f"{node.dest} = {node.left} * {node.right}" - @visitor.when(AllocateNode) - def visit(self, node): - return f"{node.dest} = ALLOCATE {node.type}" + @visitor.when(DivNode) + def visit(self, node): + return f"{node.dest} = {node.left} / {node.right}" - @visitor.when(TypeOfNode) - def visit(self, node): - return f"{node.dest} = TYPEOF {node.type}" + @visitor.when(AllocateNode) + def visit(self, node): + return f"{node.dest} = ALLOCATE {node.type}" - @visitor.when(StaticCallNode) - def visit(self, node): - return f"{node.dest} = CALL {node.function}" + @visitor.when(TypeOfNode) + def visit(self, node): + return f"{node.dest} = TYPEOF {node.type}" - @visitor.when(DynamicCallNode) - def visit(self, node): - return f"{node.dest} = VCALL {node.type} {node.method}" + @visitor.when(StaticCallNode) + def visit(self, node): + return f"{node.dest} = CALL {node.function}" - @visitor.when(ArgNode) - def visit(self, node): - return f"ARG {node.name}" + @visitor.when(DynamicCallNode) + def visit(self, node): + return f"{node.dest} = VCALL {node.type} {node.method}" - @visitor.when(ReturnNode) - def visit(self, node): - return f'RETURN {node.value if node.value is not None else ""}' + @visitor.when(ArgNode) + def visit(self, node): + return f"ARG {node.name}" + @visitor.when(ReturnNode) + def visit(self, node): + return f'RETURN {node.value if node.value is not None else ""}' -# printer = PrintVisitor() -# return lambda ast: printer.visit(ast) + printer = PrintVisitor() + return lambda ast: printer.visit(ast) diff --git a/src/code_gen/mips_builder.py b/src/code_gen/mips_builder.py index de67ddd13..866cd802b 100644 --- a/src/code_gen/mips_builder.py +++ b/src/code_gen/mips_builder.py @@ -1,20 +1,48 @@ from atexit import register from email.quoprimime import body_length +import enum +from operator import le + +from soupsieve import select import cmp.visitor as visitor import cmp.cil as cil +import random import mips_nodes as mips + + +#type_info offsets +TYPENAME_OFFSET = 0 +FUNCTION_OFFSET = 4 +RA_OFFSET = 4 + +FP_ARGS_DISTANCE = 3 # how far finishes $fp from arguments in method call +FP_LOCALS_DISTANCE = 0 # how far finishes $fp from localvars in method call + +#temporary registers t0 = "$t0" t1 = "$t1" t2 = "$t2" t3 = "$t3" +t4 = "$t4" +t5 = "$t5" t6 = "$t6" # convenios t7 = "$t7" # convenios +t8 = "$t8" +t9 = "$t9" + +#Arguments Registers a0 = "$a0" a1 = "$a1" +a2 = "$a2" +a3 = "$a3" + +#frame pointer fp = "$fp" +#stack pointer sp = "$sp" + ra = "$ra" lo = "lo" hi = "hi" @@ -25,11 +53,25 @@ s3 = "$s3" zero = "$zero" -#type_info offsets -TYPENAME_OFFSET = 0 -PARENT_OFFSET = 4 -SIZE_OFFSET = 8 - +class MemoryManager: + def __init__(self): + self.all_reg = [t0,t1,t2,t3,t4,t5,t6,t7,t8,t9] + self.used_reg = [] + self.stored = [] + + def get_unused_reg(self): + unused = list(set(self.all_reg) - set(self.used_reg)) + list(set(self.used_reg) - set(self.all_reg)) + reg = random.choice(unused) + self.used_reg.append(reg) + return reg + + def clean(self): + self.used_reg = self.stored + self.stored = [] + + def save(self): + self.stored = self.used_reg.copy() + SYSCALL_PRINT_INT = 1 SYSCALL_PRINT_STR = 4 @@ -43,13 +85,23 @@ class MIPSBuilder: def __init__(self,errors,cil_ast): self.mips_code = "" self.cil_ast = cil_ast - self.cil_types = cil_ast.types - self.cil_code = cil_ast.code - self.cil_data = cil_ast.data self.main_procedure = mips.ProcedureNode("main") self.current_procedure = self.main_procedure self.text = [self.main_procedure] self.data = [] + self.params = [] + self.locals = [] + self.types = {} + self.memo = MemoryManager() + + + def get_dir_in_memo(self,x): + if x in self.locals: + index = self.locals.index(x) + return -4*index + elif x in self.params: + index = self.params.index(x) + return (4*index)+4 def register_instruction(self, instruction_type, *args): instruction = instruction_type(*args) @@ -57,7 +109,17 @@ def register_instruction(self, instruction_type, *args): def register_data(self,data_type,*args): data = data_type(*args) - self.data.append(data) + self.data.append(data) + + + def register_push(self, reg): + self.register_instruction(mips.StoreWordNode, reg, 0, sp) + self.register_instruction(mips.AddiNode, sp, sp, -4) + + def register_pop(self, reg): + self.register_instruction(mips.LoadWordNode, reg, 4, sp) + self.register_instruction(mips.AddiNode, sp, sp, 4) + @visitor.on("node") def visit(self, node=None): @@ -82,17 +144,127 @@ def visit(self, node): @visitor.when(cil.TypeNode) def visit(self, node): + self.types[node.name] = node #for func in node.methods: values = [-1]*(len(node.methods)+1) self.register_data(mips.DataTypeNode,'.word',node.name,values) self.register_data(mips.DataTypeNode, f'{node.name}_cname','.asciiz', [f'"{node.name}"']) - #Filling type VT + #Filling type type info self.register_instruction(mips.CommentNode(f"Filling {node.name} VT")) - self.register_instruction(mips.LoadAddress(t0,node.name)) + self.register_instruction(mips.LoadAddress,t0,node.name) + self.register_instruction(mips.LoadAddress,t1,f'{node.name}_cname') + + self.register_instruction(mips.StoreWordNode,t1,TYPENAME_OFFSET,t0) + + #Filling type VT + for i,func in enumerate(node.methods): + offset = FUNCTION_OFFSET*i + self.register_instruction(mips.LoadAddress,t1,func.name) + self.register_instruction(mips.StoreWordNode,t1,offset,t0) + + @visitor.when(cil.DataNode) + def visit(self, node): + self.register_data(mips.DataTypeNode,'.ascii',node.vname,[node.value]) + + @visitor.when(cil.LocalNode) + def visit(self,node): + self.memo.save() + reg = self.memo.get_unused_reg() + self.register_instruction(mips.LoadInmediate,reg,node.name) + self.register_instruction(mips.StoreWordNode,reg,0,sp) + + self.register_instruction(mips.AddiNode,sp,sp,-4) + self.locals.append(node.name) + self.memo.clean() + + @visitor.when(cil.ParamNode) + def visit(self,node): + self.memo.save() + reg = self.memo.get_unused_reg() + + self.params.append(node.name) + + self.register_instruction(mips.LoadInmediate,reg,node.name) + self.register_instruction(mips.StoreWordNode,reg,len(self.params)*4,fp) + + self.memo.clean() + + @visitor.when(cil.ArgNode) + def visit(self,node): + pass + + + @visitor.when(cil.FunctionNode) + def visit(self,node): + self.current_procedure = mips.ProcedureNode(node.name) + + self.register_instruction(mips.CommentNode,"Pushing $ra") + self.register_push(ra) + + self.register_instruction(mips.CommentNode,"Saving $fp") + self.register_instruction(mips.MoveNode, fp, sp) + + self.register_instruction(mips.CommentNode("Executing instructions")) + for inst in node.instructions: + self.visit(inst) + + + self.register_instruction(mips.CommentNode("Restoring saved $ra")) + self.register_instruction(mips.LoadWordNode, ra, RA_OFFSET, fp)#stored $ra + + + self.register_comment("Restoring saved $fp") + self.register_instruction(mips.LoadWordNode, fp, OLD_FP_OFFSET, fp)#stored (old)$fp + + AR = 4*(len(node.localvars) + len(node.arguments) + 2) + self.register_instruction(mips.CommentNode("Cleaning stack after call")) + self.register_instruction(mips.AddiNode, sp, sp, AR) + + self.register_instruction(mips.CommentNode("Return jump")) + self.register_instruction(mips.JumpRegister, ra) + + + self.text.append(self.current_procedure) + + + @visitor.when(cil.LoadNode) + def visit(self,node): + self.memo.save() + reg = self.memo.used_reg() + + if isinstance(node.msg,int): + self.register_instruction(mips.LoadInmediate,reg,node.msg) + else: + self.register_instruction(mips.LoadAddress,reg,node.msg) + + + dir = self.get_dir_in_memo(node.dest) + self.register_instruction(mips.StoreWordNode,reg,dir,fp) + self.memo.clean() + + + + @visitor.when(cil.ReturnNode) + def visit(self): + pass + + @visitor.when(cil.GotoNode) + def visit(self): + pass + + @visitor.when(cil.AllocateNode) + def visit(self,node): + _size = (len(self.types[node.type].attributes)+1)*4 + self.register_instruction(mips.LoadInmediate,a0,_size) + self.register_instruction(mips.SyscallNode) + + dir = self.get_dir_in_memo(node.dest) + self.register_instruction(mips.StoreWordNode,v0,dir,fp) + self.memo.clean() - \ No newline at end of file + \ No newline at end of file diff --git a/src/code_gen/mips_nodes.py b/src/code_gen/mips_nodes.py index c23902e76..a550706a8 100644 --- a/src/code_gen/mips_nodes.py +++ b/src/code_gen/mips_nodes.py @@ -1,5 +1,8 @@ +from re import L from soupsieve import select +from src.cmp.cil import InstructionNode + class MIPS_Node: pass @@ -62,10 +65,6 @@ def __str__(self): return f"move {self.destination} {self.source}" - - - - class DataTypeNode(MIPSDataNode): def __init__(self, name, datatype,vt_values): self.name = name @@ -78,6 +77,95 @@ def __str__(self): values += f", {value}" return f"{self.name} : {self.datatype}{values}" +class ArithAnfLogicNode(MIPSInstructionNode): + def __init__(self, destination,left,right): + self.destination = destination + self.left = left + self.right = right +class AddNode(ArithAnfLogicNode): + def __str__(self): + return f"add {self.destination}, {self.left}, {self.right}" + +class AddiNode(ArithAnfLogicNode): + def __str__(self): + return f"addi {self.destination}, {self.left}, {self.right}" + +class SubNode(ArithAnfLogicNode): + def __str__(self): + return f"sub {self.destination}, {self.left}, {self.right}" + +class ConditionalBranch(InstructionNode): + def __init__(self,c1,c2,jump): + self.c1 = c1 + self.c2 = c2 + self.jump = jump + +class BranchOnEqualNode(ConditionalBranch): + def __str__(self): + return f"beq {self.c1}, {self.c2}, {self.jump}" + +class BranchOnNotEqualNode(ConditionalBranch): + def __str__(self): + return f"bne {self.c1}, {self.c2}, {self.jump}" + +class BranchOnGreaterThanNode(ConditionalBranch): + def __str__(self): + return f"bgt {self.c1}, {self.c2}, {self.jump}" + +class BranchOnGreaterOrEqNode(ConditionalBranch): + def __str__(self): + return f"bge {self.c1}, {self.c2}, {self.jump}" + +class BranchOnLessThanNode(ConditionalBranch): + def __str__(self): + return f"blt {self.c1}, {self.c2}, {self.jump}" + +class BranchOnLessOrEqNode(ConditionalBranch): + def __str__(self): + return f"ble {self.c1}, {self.c2}, {self.jump}" + +class ComparisonNode(InstructionNode): + def __init__(self,m1,m2,dest): + self.m1 = m1 + self.m2 = m2 + self.destination = dest + +class SetOnLessThan(ComparisonNode): + def __str__(self): + return f"slt {self.dest}, {self.m1}, {self.m2}" + +class SetOnLessThanInmediate(ComparisonNode): + def __str__(self): + return f"slt {self.dest}, {self.m1}, {self.m2}" + +class UnconditionalJumpNode(InstructionNode): + def __init__(self,jump): + self.jump = jump + +class Jump(UnconditionalJumpNode): + def __str__(self): + return f"j {self.jump}" + +class JumpRegister(UnconditionalJumpNode): + def __str__(self): + return f"jr {self.jump}" + +class JumpAndLink(UnconditionalJumpNode): + def __str__(self): + return f"jal {self.jump}" + +class Label(InstructionNode): + def __init__(self,label): + self.label = label + + def __str__(self): + return f"{self.label}:" + +class SyscallNode(InstructionNode): + def __str__(self): + return f"syscall" + + class CommentNode(MIPS_Node): def __init__(self,text): self.text = text From a0b34873ccd1691ff9e223464e3c820e0eaaa292 Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Fri, 25 Feb 2022 00:27:07 -0500 Subject: [PATCH 060/162] feat: add builtin functions --- customized_tests/test_hello_world.cl | 4 +- src/cmp/cil.py | 90 +++++++++- src/cmp/semantic.py | 4 +- src/code_gen/cil_builder.py | 241 +++++++++++++++++++++++++-- src/type_builder.py | 38 ++--- 5 files changed, 331 insertions(+), 46 deletions(-) diff --git a/customized_tests/test_hello_world.cl b/customized_tests/test_hello_world.cl index 032d82dc9..9de631736 100644 --- a/customized_tests/test_hello_world.cl +++ b/customized_tests/test_hello_world.cl @@ -1,7 +1,7 @@ class Main inherits IO { - msg : String <- " Hello World "; + msg : String <- "Hello World"; main() : IO{ - self.print(msg) + out_string(msg) }; }; \ No newline at end of file diff --git a/src/cmp/cil.py b/src/cmp/cil.py index 32bc74800..cad17f04c 100644 --- a/src/cmp/cil.py +++ b/src/cmp/cil.py @@ -13,10 +13,10 @@ def __init__(self, dottypes, dotdata, dotcode): class TypeNode(Node): - def __init__(self, name): + def __init__(self, name, attributes=[], methods=[]): self.name = name - self.attributes = [] - self.methods = [] + self.attributes = attributes + self.methods = methods class DataNode(Node): @@ -32,6 +32,12 @@ def __init__(self, fname, params, localvars, instructions): self.localvars = localvars self.instructions = instructions + # def __str__(self): + # print("NAME:", self.name) + # # print("PARAMS:", self.params) + # # print("LOCALS:", self.localvars) + # print("INSTRUCTIONS", self.instructions) + class ParamNode(Node): def __init__(self, name): @@ -184,11 +190,16 @@ def __init__(self, dest, msg): class LengthNode(InstructionNode): - pass + def __init__(self, dest, source): + self.dest = dest + self.source = source class ConcatNode(InstructionNode): - pass + def __init__(self, dest, left, right): + self.dest = dest + self.left = left + self.right = right class PrefixNode(InstructionNode): @@ -196,7 +207,11 @@ class PrefixNode(InstructionNode): class SubstringNode(InstructionNode): - pass + def __init__(self, dest, source, idx, length): + self.dest = dest + self.source = source + self.id = idx + self.length = length class ToStrNode(InstructionNode): @@ -210,11 +225,34 @@ def __init__(self, dest): self.dest = dest +class RuntimeErrorNode(InstructionNode): + def __init__(self, signal): + self.signal = signal + + +class CopyNode(InstructionNode): + def __init__(self, dest, source): + self.dest = dest + self.source = source + + +class STRNode(InstructionNode): + def __init__(self, dest, source): + self.dest = dest + self.source = source + + class PrintNode(InstructionNode): def __init__(self, str_addr): self.str_addr = str_addr +class TypeNameNode(InstructionNode): + def __init__(self, dest, source): + self.dest = dest + self.source = source + + class PrintVisitor(object): @visitor.on("node") def visit(self, node): @@ -243,6 +281,10 @@ def visit(self, node): return f"function {node.name} {{\n\t{params}\n\n\t{localvars}\n\n\t{instructions}\n}}" + @visitor.when(DataNode) + def visit(self, node): + return f'{node.name} = "{node.value}"' + @visitor.when(ParamNode) def visit(self, node): return f"PARAM {node.name}" @@ -295,6 +337,42 @@ def visit(self, node): def visit(self, node): return f'RETURN {node.value if node.value is not None else ""}' + @visitor.when(RuntimeErrorNode) + def visit(self, node): + return f"ABORT {node.signal}" + + @visitor.when(CopyNode) + def visit(self, node): + return f"{node.dest} = COPY {node.source}" + + @visitor.when(TypeNameNode) + def visit(self, node): + return f"{node.dest} = TYPE_NAME {node.source}" + + @visitor.when(ToStrNode) + def visit(self, node): + return f"{node.dest} = STR {node.ivalue}" + + @visitor.when(ReadNode) + def visit(self, node): + return f"{node.dest} = READ" + + @visitor.when(PrintNode) + def visit(self, node): + return f"PRINT {node.str_addr}" + + @visitor.when(LengthNode) + def visit(self, node): + return f"{node.dest} = LENGTH {node.source}" + + @visitor.when(ConcatNode) + def visit(self, node): + return f"{node.dest} = CONCAT {node.left} {node.right}" + + @visitor.when(SubstringNode) + def visit(self, node): + return f"{node.dest} = SUBSTRING {node.source} {node.id} {node.length}" + # printer = PrintVisitor() # return lambda ast: printer.visit(ast) diff --git a/src/cmp/semantic.py b/src/cmp/semantic.py index b4f6424c0..22f6e9092 100644 --- a/src/cmp/semantic.py +++ b/src/cmp/semantic.py @@ -263,9 +263,11 @@ def __copy__(self): class VariableInfo: - def __init__(self, name, vtype): + def __init__(self, name, vtype=None, is_attr=False): self.name = name self.type = vtype + self.is_attr = is_attr + self.offset = None class Scope: diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index bcb275b5f..68a75ef8d 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -38,12 +38,16 @@ LessNode, LessEqualNode, EqualNode, + RuntimeErrorNode, + CopyNode, + TypeNameNode, + STRNode, ) from cool_visitor import FormatVisitor from cmp.semantic import Attribute, Method, Type from cmp.semantic import VoidType, ErrorType, IntType -from cmp.semantic import Context +from cmp.semantic import Context, VariableInfo from cmp.semantic import Scope @@ -60,6 +64,7 @@ def __init__(self, errors=[]): self.string_count = 0 self.temp_vars_count = 0 self._count = 0 + self.internal_count = 0 self.context = None def generate_next_method_id(self): @@ -81,6 +86,21 @@ def next_id(self): def to_function_name(self, method_name, type_name): return f"function_{method_name}_at_{type_name}" + def to_data_name(self, type_name, value): + return f"{type_name}_{value}" + + @property + def params(self): + return self.current_function.params + + @property + def localvars(self): + return self.current_function.localvars + + @property + def instructions(self): + return self.current_function.instructions + def register_instruction(self, instruction): self.current_function.instructions.append(instruction) @@ -89,6 +109,176 @@ def register_type(self, name): self.types.append(type_node) return type_node + def register_function(self, function_name): + function_node = FunctionNode(function_name, [], [], []) + self.code.append(function_node) + return function_node + + def register_local(self, vinfo): + vinfo.name = f"local_{self.current_function.name[9:]}_{vinfo.name}_{len(self.current_function.localvars)}" + local_node = LocalNode(vinfo.name) + self.current_function.localvars.append(local_node) + return vinfo.name + + def register_param(self, vinfo): + vinfo.name = self.build_internal_vname(vinfo.name) + arg_node = ParamNode(vinfo.name) + self.params.append(arg_node) + return vinfo + + def build_internal_vname(self, vname): + vname = f"{self.internal_count}_{self.current_function.name[9:]}_{vname}" + self.internal_count += 1 + return vname + + def define_internal_local(self): + vinfo = VariableInfo("internal", None) + return self.register_local(vinfo) + + def register_data(self, name, value): + data_node = DataNode(name, value) + self.data.append(data_node) + return data_node + + def build_constructor(self, node): + pass + + def add_builtin_functions(self): + # Object + obj_functions = [ + self.cil_predef_method("abort", "Object", self.object_abort), + self.cil_predef_method("copy", "Object", self.object_copy), + self.cil_predef_method("type_name", "Object", self.object_type_name), + ] + object_type = TypeNode("Object", [], obj_functions) + + # "IO" + functions = [ + self.cil_predef_method("out_string", "IO", self.io_outstring), + self.cil_predef_method("out_int", "IO", self.io_outint), + self.cil_predef_method("in_string", "IO", self.io_instring), + self.cil_predef_method("in_int", "IO", self.io_inint), + ] + io_type = TypeNode("IO", [], obj_functions + functions) + + # String + functions = [ + self.cil_predef_method("length", "String", self.string_length), + self.cil_predef_method("concat", "String", self.string_concat), + self.cil_predef_method("substr", "String", self.string_substr), + ] + string_type = TypeNode( + "String", + [VariableInfo("length").name, VariableInfo("str_ref").name], + obj_functions + functions, + ) + + # Int + int_type = TypeNode( + "Int", + [VariableInfo("value", is_attr=True).name], + obj_functions, + ) + + # Bool + bool_type = TypeNode( + "Bool", + [VariableInfo("value", is_attr=True).name], + obj_functions, + ) + for typex in [object_type, io_type, string_type, int_type, bool_type]: + self.types.append(typex) + + # predefined functions cil + def cil_predef_method(self, mname, cname, specif_code): + self.current_type = self.context.get_type(cname) + self.current_method = self.current_type.get_method(mname) + self.current_function = FunctionNode( + self.to_function_name(mname, cname), [], [], [] + ) + + specif_code() + + self.code.append(self.current_function) + self.current_function = None + self.current_type = None + + return (mname, self.to_function_name(mname, cname)) + + def string_length(self): + self.params.append(ParamNode("self")) + + result = self.define_internal_local() + + self.register_instruction(LengthNode(result, "self")) + self.register_instruction(ReturnNode(result)) + + def string_concat(self): + self.params.append(ParamNode("self")) + other_arg = VariableInfo("other_arg") + self.register_param(other_arg) + + ret_vinfo = self.define_internal_local() + + self.register_instruction(ConcatNode(ret_vinfo, "self", other_arg.name)) + self.register_instruction(ReturnNode(ret_vinfo)) + + def string_substr(self): + self.params.append(ParamNode("self")) + idx_arg = VariableInfo("idx_arg") + self.register_param(idx_arg) + length_arg = VariableInfo("length_arg") + self.register_param(length_arg) + + ret_vinfo = self.define_internal_local() + + self.register_instruction( + SubstringNode(ret_vinfo, "self", idx_arg.name, length_arg.name) + ) + self.register_instruction(ReturnNode(ret_vinfo)) + + def object_abort(self): + self.register_instruction(RuntimeErrorNode("ABORT_SIGNAL")) + + def object_copy(self): + self.params.append(ParamNode("self")) + ret_vinfo = self.define_internal_local() + self.register_instruction(CopyNode(ret_vinfo, "self")) + self.register_instruction(ReturnNode(ret_vinfo)) + + def object_type_name(self): + self.params.append(ParamNode("self")) + ret_vinfo = self.define_internal_local() + self.register_instruction(TypeNameNode(ret_vinfo, "self")) + self.register_instruction(ReturnNode(ret_vinfo)) + + def io_outstring(self): + self.params.append(ParamNode("self")) + str_arg = VariableInfo("str") + self.register_param(str_arg) + self.register_instruction(PrintNode(str_arg.name)) + self.register_instruction(ReturnNode("self")) + + def io_outint(self): + self.params.append(ParamNode("self")) + int_arg = VariableInfo("int") + self.register_param(int_arg) + result = self.define_internal_local() + self.register_instruction(ToStrNode(result, int_arg.name)) + self.register_instruction(ReturnNode(VariableInfo(result).name)) + + def io_instring(self): + self.params.append(ParamNode("self")) + ret_vinfo = self.define_internal_local() + self.register_instruction(ReadNode(ret_vinfo)) + self.register_instruction(ReturnNode(ret_vinfo)) + + def io_inint(self): + self.params.append(ParamNode("self")) + ret_vinfo = self.define_internal_local() + self.register_instruction(ReadNode(ret_vinfo)) # TODO: ReadInt? + self.register_instruction(ReturnNode(ret_vinfo)) + @visitor.on("node") def visit(self, node=None): pass @@ -97,14 +287,16 @@ def visit(self, node=None): def visit(self, node): self.context = node.context + self.add_builtin_functions() + # Add entry function and call Main.main() self.current_function = FunctionNode("entry", [], [], []) self.code.append(self.current_function) - instance = self.generate_next_tvar_id() + instance = "l_instance" self.register_instruction(LocalNode(instance)) - result = self.generate_next_tvar_id() + result = "l_result" self.register_instruction(LocalNode(result)) main_method_name = self.to_function_name("Main", "main") @@ -118,6 +310,8 @@ def visit(self, node): for declaration in node.declarations: self.visit(declaration) + program_node = ProgramNode(self.types, self.data, self.code) + # Reset state self.types = [] self.code = [] @@ -131,19 +325,22 @@ def visit(self, node): self._count = 0 self.context = None - return ProgramNode(self.types, self.data, self.code) + return program_node @visitor.when(cool.ClassDeclarationNode) def visit(self, node): self.current_type = self.context.get_type(node.id) - self.types.append(self.current_type) type_node = self.register_type(self.current_type.name) + self.build_constructor(node) + visited_func = [] current_type = self.current_type while current_type is not None: - attributes = [attr.name for attr in current_type.attributes] + attributes = [ + (node.id + "_" + attr.name) for attr in current_type.attributes + ] methods = [ func.name for func in current_type.methods @@ -169,33 +366,31 @@ def visit(self, node): @visitor.when(cool.AttrDeclarationNode) def visit(self, node): - pass + self.visit(node.init_exp) @visitor.when(cool.FuncDeclarationNode) def visit(self, node): self.current_method = self.current_type.get_method(node.id) - # Generate ref - ref = self.generate_next_method_id() - self.current_type.methods.append((node.id, ref)) + # Add function to .CODE + self.current_function = self.register_function( + self.to_function_name(node.id, self.current_type.name) + ) # Add params - function = FunctionNode(ref, [], [], []) + self.current_function.params.append(ParamNode("self")) for pname, _ in node.params: - function.params.append(ParamNode(pname)) - - # Add function to .CODE - self.current_function = function - self.code.append(function) + self.current_function.params.append(ParamNode(pname)) # Body value = self.visit(node.body) - # Handle return + # Return if isinstance(self.current_method.return_type, VoidType): value = None self.register_instruction(ReturnNode(value)) + self.current_method = None self.current_function = None @@ -217,7 +412,17 @@ def visit(self, node): @visitor.when(cool.CallNode) def visit(self, node): - pass + for arg in node.args: + temp = self.define_internal_local() + value = self.visit(arg) + self.register_instruction(AssignNode(temp, value)) + self.register_instruction(ArgNode(temp)) + + method_name = self.to_function_name(node.id, self.current_type.name) + result = self.define_internal_local() + self.register_instruction(StaticCallNode(method_name, result)) + + return result @visitor.when(cool.IfNode) def visit(self, node): diff --git a/src/type_builder.py b/src/type_builder.py index 29a52848d..88dde82b1 100644 --- a/src/type_builder.py +++ b/src/type_builder.py @@ -35,6 +35,21 @@ def visit(self, node): string_type = self.context.get_type("String") object_type = self.context.get_type("Object") + # Object + parent_tset = Tset() + parent_tset.locals["abort"] = {"Object"} + parent_tset.locals["copy"] = {"SELF_TYPE"} + parent_tset.locals["type_name"] = {"String"} + + method = object_type.define_method("abort", [], [], object_type) + method.tset = Tset(parent_tset) + + method = object_type.define_method("copy", [], [], self_type) + method.tset = Tset(parent_tset) + + method = object_type.define_method("type_name", [], [], string_type) + method.tset = Tset(parent_tset) + # IO parent_tset = Tset() parent_tset.locals["out_string"] = {"SELF_TYPE"} @@ -58,9 +73,12 @@ def visit(self, node): # String parent_tset = Tset() + parent_tset.locals["length"] = {"Int"} parent_tset.locals["concat"] = {"String"} parent_tset.locals["substr"] = {"String"} - parent_tset.locals["length"] = {"Int"} + + method = string_type.define_method("length", [], [], int_type) + method.tset = Tset(parent_tset) method = string_type.define_method("concat", ["s"], [string_type], string_type) method.tset = Tset(parent_tset) @@ -73,24 +91,6 @@ def visit(self, node): method.tset.locals["i"] = {"Int"} method.tset.locals["l"] = {"Int"} - method = string_type.define_method("length", [], [], int_type) - method.tset = Tset(parent_tset) - - # Object - parent_tset = Tset() - parent_tset.locals["abort"] = {"Object"} - parent_tset.locals["type_name"] = {"String"} - parent_tset.locals["copy"] = {"SELF_TYPE"} - - method = object_type.define_method("abort", [], [], object_type) - method.tset = Tset(parent_tset) - - method = object_type.define_method("type_name", [], [], string_type) - method.tset = Tset(parent_tset) - - method = object_type.define_method("copy", [], [], self_type) - method.tset = Tset(parent_tset) - # ------checking for in order definitions and cyclic heritage parent_child_dict = {} queue = deque() From 50ba3b66d162214d6c467dd0a239d97857a5b136 Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Fri, 25 Feb 2022 01:48:04 -0500 Subject: [PATCH 061/162] feat: add type constructors --- src/cmp/cil.py | 18 ++++++++++++++++-- src/code_gen/cil_builder.py | 32 +++++++++++++++++++++++++++++--- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/src/cmp/cil.py b/src/cmp/cil.py index cad17f04c..f5cf63f15 100644 --- a/src/cmp/cil.py +++ b/src/cmp/cil.py @@ -114,11 +114,17 @@ class IntComplementNode(UnaryNode): class GetAttribNode(InstructionNode): - pass + def __init__(self, dest, typex, attr): + self.dest = dest + self.type = typex + self.attr = attr class SetAttribNode(InstructionNode): - pass + def __init__(self, typex, attr, value): + self.type = typex + self.value = value + self.attr = attr class GetIndexNode(InstructionNode): @@ -317,6 +323,14 @@ def visit(self, node): def visit(self, node): return f"{node.dest} = ALLOCATE {node.type}" + @visitor.when(SetAttribNode) + def visit(self, node): + return f" SETATTR {node.type} {node.attr} {node.value}" + + @visitor.when(GetAttribNode) + def visit(self, node): + return f" {node.dest} = GETATTR {node.type} {node.attr}" + @visitor.when(TypeOfNode) def visit(self, node): return f"{node.dest} = TYPEOF {node.type}" diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index 68a75ef8d..a17e665af 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -42,6 +42,8 @@ CopyNode, TypeNameNode, STRNode, + SetAttribNode, + GetAttribNode, ) from cool_visitor import FormatVisitor @@ -140,8 +142,27 @@ def register_data(self, name, value): self.data.append(data_node) return data_node + def is_attribute(self, vname): + return vname not in [var.name for var in self.current_function.localvars] + def build_constructor(self, node): - pass + attributeNodes = [ + feat for feat in node.features if isinstance(feat, cool.AttrDeclarationNode) + ] + + expr_list = [] + # for attr in attributeNodes: # Assign default value first + # assign = cool.AssignNode(attr.id, cool.DefaultValueNode(attr.type)) + # expr_list.append(assign) + + for attr in attributeNodes: # Assign init_expr if not None + if attr.init_exp: + assign = cool.AssignNode(attr.id, attr.init_exp) + expr_list.append(assign) + + body = cool.BlockNode(expr_list) + self.current_type.define_method("constructor", [], [], "Object") + return cool.FuncDeclarationNode("constructor", [], "Object", body) def add_builtin_functions(self): # Object @@ -333,7 +354,7 @@ def visit(self, node): type_node = self.register_type(self.current_type.name) - self.build_constructor(node) + constructor = self.build_constructor(node) visited_func = [] current_type = self.current_type @@ -359,6 +380,7 @@ def visit(self, node): type_node.attributes.reverse() type_node.methods.reverse() + self.visit(constructor) for feature in node.features: self.visit(feature) @@ -408,7 +430,11 @@ def visit(self, node): @visitor.when(cool.AssignNode) def visit(self, node): expr = self.visit(node.expr) - self.register_instruction(AssignNode(node.id, expr)) + + if self.is_attribute(node.id): + self.register_instruction(SetAttribNode("self", node.id, expr)) + else: + self.register_instruction(AssignNode(node.id, expr)) @visitor.when(cool.CallNode) def visit(self, node): From cbba86258b2e31047ca9ffefaf1e5a31b76a9d74 Mon Sep 17 00:00:00 2001 From: smartos99 Date: Fri, 25 Feb 2022 10:09:24 -0500 Subject: [PATCH 062/162] Visitors Added --- src/code_gen/mips_builder.py | 96 ++++++++++++++++++++++++++++++++++-- src/code_gen/mips_nodes.py | 1 + 2 files changed, 92 insertions(+), 5 deletions(-) diff --git a/src/code_gen/mips_builder.py b/src/code_gen/mips_builder.py index 866cd802b..4b3536d43 100644 --- a/src/code_gen/mips_builder.py +++ b/src/code_gen/mips_builder.py @@ -172,7 +172,7 @@ def visit(self, node): def visit(self,node): self.memo.save() reg = self.memo.get_unused_reg() - self.register_instruction(mips.LoadInmediate,reg,node.name) + self.register_instruction(mips.LoadAddress,reg,node.name) self.register_instruction(mips.StoreWordNode,reg,0,sp) self.register_instruction(mips.AddiNode,sp,sp,-4) @@ -193,7 +193,20 @@ def visit(self,node): @visitor.when(cil.ArgNode) def visit(self,node): - pass + self.memo.save() + reg = self.memo.get_unused_reg() + + dir = self.get_dir_in_memo(node.name) + self.register_instruction(mips.LoadWordNode,reg,dir,fp) + + self.register_instruction(mips.StoreWordNode,reg,0,sp) + + self.register_instruction(mips.AddiNode,sp,sp,4) + + self.memo.clean() + + + @visitor.when(cil.FunctionNode) @@ -204,7 +217,10 @@ def visit(self,node): self.register_push(ra) self.register_instruction(mips.CommentNode,"Saving $fp") - self.register_instruction(mips.MoveNode, fp, sp) + self.register_instruction(mips.MoveNode, fp, sp) + + self.register_comment("Reserving space for locals") + self.register_instruction(mips.AddiNode, sp, sp, -4*len(node.localvars)) self.register_instruction(mips.CommentNode("Executing instructions")) for inst in node.instructions: @@ -251,12 +267,17 @@ def visit(self): pass @visitor.when(cil.GotoNode) - def visit(self): + def visit(self,node): + self.register_instruction(mips.UnconditionalJumpNode,node.label) + + @visitor.when(cil.GotoIfNode) + def visit(self,node): pass @visitor.when(cil.AllocateNode) def visit(self,node): _size = (len(self.types[node.type].attributes)+1)*4 + self.register_instruction(mips.LoadInmediate,v0,9) self.register_instruction(mips.LoadInmediate,a0,_size) self.register_instruction(mips.SyscallNode) @@ -266,5 +287,70 @@ def visit(self,node): self.memo.clean() + + + + @visitor.when(cil.AssignNode) + def visit(self,node): + self.save() + + reg = self.memo.get_unused_reg() + + source_dir = self.get_dir_in_memo(node.source) + dest_dir = self.get_dir_in_memo(node.dest) + + self.register_instruction(mips.LoadWordNode,reg,source_dir,fp) + + self.register_instruction(mips.StoreWordNode,reg,dest_dir,fp) + + self.memo.clean() + + + + + @visitor.when(cil.PlusNode) + def visit(self,node): + self.save() + + reg1 = self.memo.get_unused_reg() + reg2 = self.memo.get_unused_reg() + reg3 = self.memo.get_unused_reg() + + self.register_instruction(mips.LoadInmediate,reg1,node.left) + self.register_instruction(mips.LoadInmediate,reg2,node.right) + + self.register_instruction(mips.AddNode,reg3,reg1,reg2) + + dir = self.get_dir_in_memo(node.dest) + self.register_instruction(mips.StoreWordNode,reg3,dir,fp) + + self.memo.clean() + + @visitor.when(cil.MinusNode) + def visit(self,node): + self.save() + + reg1 = self.memo.get_unused_reg() + reg2 = self.memo.get_unused_reg() + reg3 = self.memo.get_unused_reg() + + self.register_instruction(mips.LoadInmediate,reg1,node.left) + self.register_instruction(mips.LoadInmediate,reg2,node.right) + + self.register_instruction(mips.SubNode,reg3,reg1,reg2) + + dir = self.get_dir_in_memo(node.dest) + self.register_instruction(mips.StoreWordNode,reg3,dir,fp) + + self.memo.clean() + + @visitor.when(cil.TypeOfNode) + def visit(self,node): + self.memo.save() + + reg1 = self.get_dir_in_memo() + reg2 = self.get_dir_in_memo() + + - \ No newline at end of file + \ No newline at end of file diff --git a/src/code_gen/mips_nodes.py b/src/code_gen/mips_nodes.py index a550706a8..75793f695 100644 --- a/src/code_gen/mips_nodes.py +++ b/src/code_gen/mips_nodes.py @@ -82,6 +82,7 @@ def __init__(self, destination,left,right): self.destination = destination self.left = left self.right = right + class AddNode(ArithAnfLogicNode): def __str__(self): return f"add {self.destination}, {self.left}, {self.right}" From b3fbd6b944e188cfa3cdc8d2860b8d48b79e3bab Mon Sep 17 00:00:00 2001 From: smartos99 Date: Fri, 25 Feb 2022 10:44:38 -0500 Subject: [PATCH 063/162] Conflicts fixed in cil.py --- src/cmp/cil.py | 93 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 70 insertions(+), 23 deletions(-) diff --git a/src/cmp/cil.py b/src/cmp/cil.py index 4f976f35d..f5cf63f15 100644 --- a/src/cmp/cil.py +++ b/src/cmp/cil.py @@ -60,7 +60,12 @@ def __init__(self, dest, source): class ArithmeticNode(InstructionNode): - def __init__(self, dest, left, right): + def __init__( + self, + dest, + left, + right, + ): self.dest = dest self.left = left self.right = right @@ -82,6 +87,32 @@ class DivNode(ArithmeticNode): pass +class LessNode(ArithmeticNode): + pass + + +class LessEqualNode(ArithmeticNode): + pass + + +class EqualNode(ArithmeticNode): + pass + + +class UnaryNode(InstructionNode): + def __init__(self, dest, expr): + self.dest = dest + self.expr = expr + + +class NotNode(UnaryNode): + pass + + +class IntComplementNode(UnaryNode): + pass + + class GetAttribNode(InstructionNode): def __init__(self, dest, typex, attr): self.dest = dest @@ -103,7 +134,7 @@ class GetIndexNode(InstructionNode): class SetIndexNode(InstructionNode): pass - + class AllocateNode(InstructionNode): def __init__(self, itype, dest): self.type = itype @@ -125,11 +156,14 @@ class LabelNode(InstructionNode): class GotoNode(InstructionNode): - pass + def __init__(self, label): + self.label = label class GotoIfNode(InstructionNode): - pass + def __init__(self, condition, label): + self.condition = condition + self.label = label class StaticCallNode(InstructionNode): @@ -224,13 +258,12 @@ def __init__(self, dest, source): self.dest = dest self.source = source + class PrintVisitor(object): @visitor.on("node") def visit(self, node): pass - - @visitor.when(ProgramNode) def visit(self, node): dottypes = "\n".join(self.visit(t) for t in node.dottypes) @@ -253,6 +286,7 @@ def visit(self, node): instructions = "\n\t".join(self.visit(x) for x in node.instructions) return f"function {node.name} {{\n\t{params}\n\n\t{localvars}\n\n\t{instructions}\n}}" + @visitor.when(DataNode) def visit(self, node): return f'{node.name} = "{node.value}"' @@ -261,7 +295,6 @@ def visit(self, node): def visit(self, node): return f"PARAM {node.name}" - @visitor.when(LocalNode) def visit(self, node): return f"LOCAL {node.name}" @@ -289,6 +322,7 @@ def visit(self, node): @visitor.when(AllocateNode) def visit(self, node): return f"{node.dest} = ALLOCATE {node.type}" + @visitor.when(SetAttribNode) def visit(self, node): return f" SETATTR {node.type} {node.attr} {node.value}" @@ -301,45 +335,58 @@ def visit(self, node): def visit(self, node): return f"{node.dest} = TYPEOF {node.type}" - - @visitor.when(StaticCallNode) def visit(self, node): - return f"{node.dest} = CALL {node.function}" + return f"{node.dest} = CALL {node.function}" + @visitor.when(DynamicCallNode) def visit(self, node): - return f"{node.dest} = VCALL {node.type} {node.method}" + return f"{node.dest} = VCALL {node.type} {node.method}" + @visitor.when(ArgNode) def visit(self, node): - return f"ARG {node.name}" + return f"ARG {node.name}" + @visitor.when(ReturnNode) def visit(self, node): - return f'RETURN {node.value if node.value is not None else ""}' + return f'RETURN {node.value if node.value is not None else ""}' + @visitor.when(RuntimeErrorNode) def visit(self, node): - return f"ABORT {node.signal}" + return f"ABORT {node.signal}" + @visitor.when(CopyNode) def visit(self, node): - return f"{node.dest} = COPY {node.source}" + return f"{node.dest} = COPY {node.source}" + @visitor.when(TypeNameNode) def visit(self, node): - return f"{node.dest} = TYPE_NAME {node.source}" + return f"{node.dest} = TYPE_NAME {node.source}" + @visitor.when(ToStrNode) def visit(self, node): - return f"{node.dest} = STR {node.ivalue}" + return f"{node.dest} = STR {node.ivalue}" + @visitor.when(ReadNode) def visit(self, node): - return f"{node.dest} = READ" + return f"{node.dest} = READ" + @visitor.when(PrintNode) def visit(self, node): - return f"PRINT {node.str_addr}" + return f"PRINT {node.str_addr}" + @visitor.when(LengthNode) def visit(self, node): - return f"{node.dest} = LENGTH {node.source}" + return f"{node.dest} = LENGTH {node.source}" + @visitor.when(ConcatNode) def visit(self, node): - return f"{node.dest} = CONCAT {node.left} {node.right}" + return f"{node.dest} = CONCAT {node.left} {node.right}" + @visitor.when(SubstringNode) def visit(self, node): - return f"{node.dest} = SUBSTRING {node.source} {node.id} {node.length}" - \ No newline at end of file + return f"{node.dest} = SUBSTRING {node.source} {node.id} {node.length}" + + +# printer = PrintVisitor() +# return lambda ast: printer.visit(ast) From 004f02a73e5c79aaa7d64a14b1adfe31eaa0f7ae Mon Sep 17 00:00:00 2001 From: gabriela Date: Fri, 25 Feb 2022 10:56:30 -0500 Subject: [PATCH 064/162] Fix small error in type_checker. Modify copy sentence so it runs. --- src/type_checker.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/type_checker.py b/src/type_checker.py index 16c0159e4..7cd1b69e7 100644 --- a/src/type_checker.py +++ b/src/type_checker.py @@ -40,6 +40,7 @@ from cmp.semantic import Scope from cmp.utils import find_least_type +import copy WRONG_SIGNATURE = 'Method "%s" already defined in "%s" with a different signature.' SELF_IS_READONLY = 'Variable "self" is read-only.' @@ -63,7 +64,7 @@ def visit(self, node, scope=None): @visitor.when(ProgramNode) def visit(self, node): scope = Scope() - self.context = node.context.copy() + self.context = copy.copy(node.context) for declaration in node.declarations: self.visit(declaration, scope.create_child()) From 3f969385e83e9ea040c1de80a550347ed2972b6b Mon Sep 17 00:00:00 2001 From: gabriela Date: Fri, 25 Feb 2022 11:02:19 -0500 Subject: [PATCH 065/162] Modify flow to pass tokens with location info. --- src/ast_nodes.py | 57 ++++++++++++++++++++++++------------- src/cmp/evaluation.py | 2 +- src/cmp/utils.py | 11 ++++--- src/cool_grammar.py | 55 +++++++++++++++++------------------ src/lexical_analizer.py | 30 +++++++++---------- src/main.py | 8 ++++-- src/shift_reduce_parsers.py | 23 ++++++++------- 7 files changed, 107 insertions(+), 79 deletions(-) diff --git a/src/ast_nodes.py b/src/ast_nodes.py index 869599488..c2b3d7aa8 100644 --- a/src/ast_nodes.py +++ b/src/ast_nodes.py @@ -1,12 +1,14 @@ from cmp.semantic import Context - +from cmp.utils import Token class Node: - pass + def __init__(self, token): + self.token = token class ProgramNode(Node): - def __init__(self, declarations, context=None): + def __init__( declarations, context=None): + super().__init__(self, Token("", "", (0,0))) # symbolic initial token self.declarations = declarations self.context = context @@ -16,99 +18,116 @@ class ExpressionNode(Node): class ClassDeclarationNode: - def __init__(self, idx, features, parent=None): + def __init__(self, idx, features, token, parent=None): self.id = idx self.parent = parent self.features = features + self.token = token class FuncDeclarationNode: - def __init__(self, idx, params, return_type, body): + def __init__(self, idx, params, return_type, body, token): self.id = idx self.params = params self.type = return_type self.body = body + self.token = token class AttrDeclarationNode: - def __init__(self, idx, typex, init_exp=None): + def __init__(self, idx, typex, init_exp=None, token = Token("", "", (0,0))): self.id = idx self.type = typex self.init_exp = init_exp + self.token = token class AssignNode(ExpressionNode): - def __init__(self, idx, expr): + def __init__(self, idx, expr, token): self.id = idx self.expr = expr + self.token = token class LetNode(ExpressionNode): - def __init__(self, identifiers, body): + def __init__(self, identifiers, body, token): self.identifiers = identifiers self.body = body + self.token = token +#No tiene uno asi class VarDeclarationNode: def __init__(self, idx, typex, expr=None): self.id = idx self.type = typex self.expr = expr + self.token = token class IfNode(ExpressionNode): - def __init__(self, if_exp, then_exp, else_exp): + def __init__(self, if_exp, then_exp, else_exp, token): self.if_expr = if_exp self.then_expr = then_exp self.else_expr = else_exp + self.token = token class WhileNode(ExpressionNode): - def __init__(self, condition, body): + def __init__(self, condition, body, token): self.condition = condition self.body = body + self.token = token class CaseNode(ExpressionNode): - def __init__(self, exp, case_items): + def __init__(self, exp, case_items, token): self.expr = exp self.case_items = case_items + self.token = token - +#este no existe en la otra jerarquia class CaseItemNode(ExpressionNode): - def __init__(self, idx, typex, exp): + def __init__(self, idx, typex, exp, token): self.id = idx self.type = typex self.expr = exp + self.token = token class CallNode(ExpressionNode): - def __init__(self, idx, args, obj=None, at_type=None): + def __init__(self, idx, args, obj=None, at_type=None, token = Token("", "", (0,0))): self.obj = obj self.id = idx self.args = args self.at_type = at_type + self.token = token class BlockNode(ExpressionNode): - def __init__(self, expression_list): + def __init__(self, expression_list, token): self.expression_list = expression_list - + self.token = token + class AtomicNode(ExpressionNode): - def __init__(self, lex): + def __init__(self, lex, token): self.lex = lex + self.token = token +#aqui y abajo se llama symbol class UnaryNode(ExpressionNode): - def __init__(self, expr): + def __init__(self, expr, token): self.expr = expr + self.token = token class BinaryNode(ExpressionNode): - def __init__(self, left, right): + def __init__(self, left, right, token): self.left = left self.right = right + self.token = token class ArithmeticOperation(BinaryNode): diff --git a/src/cmp/evaluation.py b/src/cmp/evaluation.py index ebe01f5c5..48c5c28eb 100644 --- a/src/cmp/evaluation.py +++ b/src/cmp/evaluation.py @@ -12,7 +12,7 @@ def evaluate_reverse_parse(right_parse, operations, tokens): for operation in operations: if operation == ShiftReduceParser.SHIFT: token = next(tokens) - stack.append(token.lex) + stack.append(token) elif operation == ShiftReduceParser.REDUCE: production = next(right_parse) head, body = production diff --git a/src/cmp/utils.py b/src/cmp/utils.py index cad362fdb..e7e5502b9 100644 --- a/src/cmp/utils.py +++ b/src/cmp/utils.py @@ -127,11 +127,14 @@ class Token: Token's lexeme. token_type : Enum Token's type. + location : (Int, Int) + (Row, position since the start of the text). """ - def __init__(self, lex, token_type): + def __init__(self, lex, token_type, location): self.lex = lex self.token_type = token_type + self.location = location def __str__(self): return f"{self.token_type}: {self.lex}" @@ -145,11 +148,11 @@ def is_valid(self): class UnknownToken(Token): - def __init__(self, lex): - Token.__init__(self, lex, None) + def __init__(self, lex, location): + Token.__init__(self, lex, None, location) def transform_to(self, token_type): - return Token(self.lex, token_type) + return Token(self.lex, token_type, self.location) @property def is_valid(self): diff --git a/src/cool_grammar.py b/src/cool_grammar.py index 012cb5f16..af4ec858f 100644 --- a/src/cool_grammar.py +++ b/src/cool_grammar.py @@ -71,11 +71,11 @@ def define_cool_grammar(print_grammar=False): def_class %= ( classx + type_id + ocur + feature_list + ccur + semi, - lambda h, s: ClassDeclarationNode(s[2], s[4]), + lambda h, s: ClassDeclarationNode(s[2], s[4], s[1]), ) def_class %= ( classx + type_id + inherits + type_id + ocur + feature_list + ccur + semi, - lambda h, s: ClassDeclarationNode(s[2], s[6], s[4]), + lambda h, s: ClassDeclarationNode(s[2], s[6], s[1], s[4]), ) feature_list %= def_attr + semi + feature_list, lambda h, s: [s[1]] + s[3] @@ -83,14 +83,14 @@ def define_cool_grammar(print_grammar=False): feature_list %= G.Epsilon, lambda h, s: [] def_attr %= ( - idx + colon + type_id + larrow + expr, - lambda h, s: AttrDeclarationNode(s[1], s[3], s[5]), + idx + colon + type_id + larrow + expr, # el token podria ser el del id en estos 3 + lambda h, s: AttrDeclarationNode(s[1], s[3], s[5], s[4]), ) - def_attr %= idx + colon + type_id, lambda h, s: AttrDeclarationNode(s[1], s[3]) + def_attr %= idx + colon + type_id, lambda h, s: AttrDeclarationNode(s[1], s[3], token = s[2]) - def_func %= ( + def_func %= (#verificar el token que se manda idx + opar + param_list + cpar + colon + type_id + ocur + expr + ccur, - lambda h, s: FuncDeclarationNode(s[1], s[3], s[6], s[8]), + lambda h, s: FuncDeclarationNode(s[1], s[3], s[6], s[8], s[2]), ) param_list %= param + param_list_rest, lambda h, s: [s[1]] + s[2] @@ -99,13 +99,14 @@ def define_cool_grammar(print_grammar=False): param_list_rest %= comma + param + param_list_rest, lambda h, s: [s[2]] + s[3] param_list_rest %= comma + param, lambda h, s: [s[2]] - + #aqui podria ser conveniente annadir un token para registrar la pos ante un error param %= idx + colon + type_id, lambda h, s: (s[1], s[3]) - expr %= idx + larrow + expr, lambda h, s: AssignNode(s[1], s[3]) - expr %= let + identifiers_list + inx + expr, lambda h, s: LetNode(s[2], s[4]) + expr %= idx + larrow + expr, lambda h, s: AssignNode(s[1], s[3], s[2]) + expr %= let + identifiers_list + inx + expr, lambda h, s: LetNode(s[2], s[4], s[1]) expr %= comp, lambda h, s: s[1] + # igual, deberia considerarse registrar estos tokens identifiers_list %= ( identifier_init + comma + identifiers_list, lambda h, s: [s[1]] + s[3], @@ -118,39 +119,39 @@ def define_cool_grammar(print_grammar=False): ) identifier_init %= idx + colon + type_id, lambda h, s: VarDeclarationNode(s[1], s[3]) - comp %= comp + less + arith, lambda h, s: LessNode(s[1], s[3]) - comp %= comp + equal + arith, lambda h, s: EqualNode(s[1], s[3]) - comp %= comp + lesseq + arith, lambda h, s: LessEqualNode(s[1], s[3]) + comp %= comp + less + arith, lambda h, s: LessNode(s[1], s[3], s[2]) + comp %= comp + equal + arith, lambda h, s: EqualNode(s[1], s[3], s[2]) + comp %= comp + lesseq + arith, lambda h, s: LessEqualNode(s[1], s[3], s[2]) comp %= arith, lambda h, s: s[1] - arith %= notx + term, lambda h, s: NotNode(s[2]) - arith %= arith + plus + term, lambda h, s: PlusNode(s[1], s[3]) - arith %= arith + minus + term, lambda h, s: MinusNode(s[1], s[3]) + arith %= notx + term, lambda h, s: NotNode(s[2], s[1]) + arith %= arith + plus + term, lambda h, s: PlusNode(s[1], s[3], s[2]) + arith %= arith + minus + term, lambda h, s: MinusNode(s[1], s[3], s[2]) arith %= term, lambda h, s: s[1] - term %= term + star + factor, lambda h, s: StarNode(s[1], s[3]) - term %= term + div + factor, lambda h, s: DivNode(s[1], s[3]) + term %= term + star + factor, lambda h, s: StarNode(s[1], s[3], s[2]) + term %= term + div + factor, lambda h, s: DivNode(s[1], s[3], s[2]) term %= factor, lambda h, s: s[1] - factor %= isvoid + element, lambda h, s: IsvoidNode(s[2]) - factor %= neg + element, lambda h, s: NegNode(s[2]) + factor %= isvoid + element, lambda h, s: IsvoidNode(s[2], s[1]) + factor %= neg + element, lambda h, s: NegNode(s[2], s[1]) factor %= element, lambda h, s: s[1] element %= ( ifx + expr + then + expr + elsex + expr + fi, - lambda h, s: IfNode(s[2], s[4], s[6]), + lambda h, s: IfNode(s[2], s[4], s[6], s[1]), ) - element %= whilex + expr + loop + expr + pool, lambda h, s: WhileNode(s[2], s[4]) - element %= case + expr + of + case_block + esac, lambda h, s: CaseNode(s[2], s[4]) - element %= new + type_id, lambda h, s: InstantiateNode(s[2]) + element %= whilex + expr + loop + expr + pool, lambda h, s: WhileNode(s[2], s[4], s[1]) + element %= case + expr + of + case_block + esac, lambda h, s: CaseNode(s[2], s[4], s[1]) + element %= new + type_id, lambda h, s: InstantiateNode(s[2], s[1]) element %= opar + expr + cpar, lambda h, s: s[2] element %= ocur + block + ccur, lambda h, s: BlockNode(s[2]) - element %= (element + dot + func_call, lambda h, s: CallNode(*s[3], obj=s[1])) + element %= (element + dot + func_call, lambda h, s: CallNode(*s[3], obj=s[1], token = s[2]))#arreglar element %= ( element + at + type_id + dot + func_call, - lambda h, s: CallNode(*s[5], obj=s[1], at_type=s[3]), + lambda h, s: CallNode(*s[5], obj=s[1], at_type=s[3], token = s[2]), ) - element %= func_call, lambda h, s: CallNode(*s[1]) + element %= func_call, lambda h, s: CallNode(*s[1],) element %= atom, lambda h, s: s[1] case_block %= case_item + case_block, lambda h, s: [s[1]] + s[2] diff --git a/src/lexical_analizer.py b/src/lexical_analizer.py index 09e4e4b8a..c31247f69 100644 --- a/src/lexical_analizer.py +++ b/src/lexical_analizer.py @@ -28,8 +28,8 @@ def tokenize_cool_text(grammar, idx, type_id, string, num, data, errors, printin # Give the lexer some input lexer.input(data) - fixed_tokens = { - t.Name: Token(t.Name, t) + fixed_tokens_names = { + t.Name: (t.Name, t) for t in grammar.terminals if t not in {idx, type_id, string, num} } @@ -39,33 +39,33 @@ def tokenize_cool_text(grammar, idx, type_id, string, num, data, errors, printin # Tokenize while True: tok = lexer.token() - if not tok:#append EOF + if not tok: # append EOF if len(pos_data) > 0: last_lineno, last_col = pos_data[-1] col = last_col + len(tokens[-1].lex) - else:#empty program + else: # empty program last_lineno = 0 col = -1 - pos_data.append([last_lineno, col]) - tokens.append(Token("$", grammar.EOF)) + tokens.append(Token("$", grammar.EOF, (last_lineno, col))) break # No more input else: try: - tokens.append(fixed_tokens[tok.type]) + tval, ttype = fixed_tokens_names[tok.type] except: - try: # for <=, ->, <- - tokens.append(fixed_tokens[tok.value]) + try: # for <=, ->, <- #this may be unnecessary + tval, ttype = fixed_tokens_names[tok.value] except: + tval = tok.value if tok.type == "string": - tokens.append(Token(tok.value, string)) + ttype = string elif tok.type == "id": - tokens.append(Token(tok.value, idx)) + ttype = idx elif tok.type == "type_id": - tokens.append(Token(tok.value, type_id)) + ttype = type_id else: - tokens.append(Token(tok.value, num)) - pos_data.append([tok.lineno,tok.lexpos]) + ttype = num + tokens.append(Token(tval, ttype, (tok.lineno,tok.lexpos))) if printing: pprint_tokens(tokens) - return tokens, pos_data + return tokens diff --git a/src/main.py b/src/main.py index 7536aefce..620f11eb3 100644 --- a/src/main.py +++ b/src/main.py @@ -44,8 +44,7 @@ def pipeline(input_file: Path, output_file: Path = None): # define grammar grammar, idx, type_id, string, num = define_cool_grammar() - tokens, pos_data = tokenize_cool_text(grammar, idx, type_id, string, num, text, errors) - # print(tokens) + tokens = tokenize_cool_text(grammar, idx, type_id, string, num, text, errors) if len(errors) > 0: report_and_exit(errors) @@ -54,7 +53,7 @@ def pipeline(input_file: Path, output_file: Path = None): if len(errors) > 0: report_and_exit(errors) - parse, operations = parser([t.token_type for t in tokens], [t.lex for t in tokens], pos_data, text) + parse, operations = parser(tokens, text) # print("Parse") # print(parse) @@ -74,6 +73,9 @@ def pipeline(input_file: Path, output_file: Path = None): for visitor in visitors: ast = visitor.visit(ast) + type_checker = TypeChecker(errors) + scope = type_checker.visit(ast) + # formatter = FormatVisitor() # tree = formatter.visit(ast) # print(tree) diff --git a/src/shift_reduce_parsers.py b/src/shift_reduce_parsers.py index 25d16a9bc..25931808a 100644 --- a/src/shift_reduce_parsers.py +++ b/src/shift_reduce_parsers.py @@ -24,7 +24,7 @@ def __init__(self, G, errors, verbose=False): def _build_parsing_table(self): raise NotImplementedError() - def __call__(self, w, values, pos, text): + def __call__(self, w, text): stack = [0] cursor = 0 output = [] @@ -32,7 +32,7 @@ def __call__(self, w, values, pos, text): while True: state = stack[-1] - lookahead = w[cursor] + lookahead = w[cursor].token_type if self.verbose: print(stack, "<---||--->", w[cursor:]) @@ -41,11 +41,12 @@ def __call__(self, w, values, pos, text): action, tag = self.action[state, lookahead] except KeyError: + current_token = w[cursor] self.errors.append( SyntacticError( - pos[cursor][0], - find_column(text, pos[cursor][1]), - "ERROR at or near "+ str(values[cursor]) + current_token.location[0], + find_column(text, current_token.location[1]), + "ERROR at or near "+ str(current_token.lex) ) ) @@ -70,21 +71,23 @@ def __call__(self, w, values, pos, text): return output, operations # Invalid case else: + current_token = w[cursor] self.errors.append( SyntacticError( - pos[cursor][0], - find_column(text, pos[cursor][1]), - "ERROR at or near"+ str(values[cursor]) + current_token.location[0], + find_column(text, current_token.location[1]), + "ERROR at or near"+ str(current_token.lex) ) ) return output, operations # "Invalid case. Sentence given does not belong to the grammar", if cursor >= len(w): # or not stack + current_token = w[cursor] self.errors.append( SyntacticError( - pos[cursor][-1], - find_column(text, pos[cursor][-1]), + current_token.location[0], + find_column(text, current_token.location[1]), "Exceed word length while looking for a viable derivation. Sentence given does not belong to the grammar", ) ) From 41a0221dc821d55e6f3c1e141ad345e0a9f9bdab Mon Sep 17 00:00:00 2001 From: gabriela Date: Fri, 25 Feb 2022 18:24:38 -0500 Subject: [PATCH 066/162] Correct calls to ast's properties. --- src/ast_nodes.py | 16 ++++++++------ src/cmp/utils.py | 2 +- src/cool_grammar.py | 4 ++-- src/cool_visitor.py | 54 ++++++++++++++++++++++----------------------- src/main.py | 14 ++++++++---- src/type_builder.py | 19 +++++++++------- src/type_checker.py | 36 +++++++++++++++--------------- 7 files changed, 78 insertions(+), 67 deletions(-) diff --git a/src/ast_nodes.py b/src/ast_nodes.py index c2b3d7aa8..f38e67506 100644 --- a/src/ast_nodes.py +++ b/src/ast_nodes.py @@ -7,8 +7,8 @@ def __init__(self, token): class ProgramNode(Node): - def __init__( declarations, context=None): - super().__init__(self, Token("", "", (0,0))) # symbolic initial token + def __init__(self, declarations, context=None): + super().__init__(Token("", "", (0,0))) # symbolic initial token self.declarations = declarations self.context = context @@ -58,8 +58,8 @@ def __init__(self, identifiers, body, token): #No tiene uno asi class VarDeclarationNode: - def __init__(self, idx, typex, expr=None): - self.id = idx + def __init__(self, token, typex, expr=None): + self.id = token.lex self.type = typex self.expr = expr self.token = token @@ -111,8 +111,8 @@ def __init__(self, expression_list, token): class AtomicNode(ExpressionNode): - def __init__(self, lex, token): - self.lex = lex + def __init__(self, token): + self.lex = token.lex self.token = token @@ -155,7 +155,9 @@ class BooleanNode(AtomicNode): class InstantiateNode(AtomicNode): - pass + def __init__(self, lex, token): + self.lex = lex + self.token = token class NotNode(UnaryNode): diff --git a/src/cmp/utils.py b/src/cmp/utils.py index e7e5502b9..b0308a277 100644 --- a/src/cmp/utils.py +++ b/src/cmp/utils.py @@ -137,7 +137,7 @@ def __init__(self, lex, token_type, location): self.location = location def __str__(self): - return f"{self.token_type}: {self.lex}" + return f"{self.token_type}: {self.lex} at ({self.location[0]}, {self.location[1]})" def __repr__(self): return str(self) diff --git a/src/cool_grammar.py b/src/cool_grammar.py index af4ec858f..f866b60f8 100644 --- a/src/cool_grammar.py +++ b/src/cool_grammar.py @@ -71,11 +71,11 @@ def define_cool_grammar(print_grammar=False): def_class %= ( classx + type_id + ocur + feature_list + ccur + semi, - lambda h, s: ClassDeclarationNode(s[2], s[4], s[1]), + lambda h, s: ClassDeclarationNode(s[2].lex, s[4], s[1]), ) def_class %= ( classx + type_id + inherits + type_id + ocur + feature_list + ccur + semi, - lambda h, s: ClassDeclarationNode(s[2], s[6], s[1], s[4]), + lambda h, s: ClassDeclarationNode(s[2].lex, s[6], s[1], s[4]), # aqui hay que buscar otra alternativa a simplemente pasar el lexema pues a la hora de dar errores estaria bien decir que el tipo que se refencia noe sta definido ) feature_list %= def_attr + semi + feature_list, lambda h, s: [s[1]] + s[3] diff --git a/src/cool_visitor.py b/src/cool_visitor.py index ba83adc5d..6c4ccb580 100644 --- a/src/cool_visitor.py +++ b/src/cool_visitor.py @@ -372,7 +372,7 @@ def visit(self, node): features = [] for feat in node.features: features.append(self.visit(feat)) - return ClassDeclarationNode(node.id, features, node.parent) + return ClassDeclarationNode(node.id, features, node.token, node.parent) @visitor.when(AttrDeclarationNode) def visit(self, node): @@ -380,7 +380,7 @@ def visit(self, node): if not node.init_exp is None: init_exp = self.visit(node.init_exp) - return AttrDeclarationNode(node.id, node.type, init_exp) + return AttrDeclarationNode(node.id, node.type, init_exp, node.token) @visitor.when(VarDeclarationNode) def visit(self, node): @@ -388,18 +388,18 @@ def visit(self, node): if not node.expr is None: expr = self.visit(node.expr) - return VarDeclarationNode(node.id, node.type, expr) + return VarDeclarationNode(node.token, node.type, expr) @visitor.when(AssignNode) def visit(self, node): expr = self.visit(node.expr) - return AssignNode(node.id, expr) + return AssignNode(node.id, expr, node.token) @visitor.when(FuncDeclarationNode) def visit(self, node): params = [p for p in node.params] body = self.visit(node.body) - return FuncDeclarationNode(node.id, params, node.type, body) + return FuncDeclarationNode(node.id, params, node.type, body, node.token) @visitor.when(CallNode) def visit(self, node): @@ -411,27 +411,27 @@ def visit(self, node): for arg in node.args: args.append(self.visit(arg)) - return CallNode(node.id, args, obj, node.at_type) + return CallNode(node.id, args, obj, node.at_type, node.token) @visitor.when(BlockNode) def visit(self, node): expression_list = [] for child in node.expression_list: expression_list.append(self.visit(child)) - return BlockNode(expression_list) + return BlockNode(expression_list, node.token) @visitor.when(IfNode) def visit(self, node): if_expr = self.visit(node.if_expr) then_expr = self.visit(node.then_expr) else_expr = self.visit(node.else_expr) - return IfNode(if_expr, then_expr, else_expr) + return IfNode(if_expr, then_expr, else_expr, node.token) @visitor.when(WhileNode) def visit(self, node): condition = self.visit(node.condition) body = self.visit(node.body) - return WhileNode(condition, body) + return WhileNode(condition, body, node.token) @visitor.when(LetNode) def visit(self, node): @@ -439,7 +439,7 @@ def visit(self, node): for child in node.identifiers: identifiers.append(self.visit(child)) body = self.visit(node.body) - return LetNode(identifiers, body) + return LetNode(identifiers, body, node.token) @visitor.when(CaseNode) def visit(self, node): @@ -447,86 +447,86 @@ def visit(self, node): case_items = [] for child in node.case_items: case_items.append(self.visit(child)) - return CaseNode(expr, case_items) + return CaseNode(expr, case_items, node.token) @visitor.when(CaseItemNode) def visit(self, node): expr = self.visit(node.expr) - return CaseItemNode(node.id, node.type, expr) + return CaseItemNode(node.id, node.type, expr, node.token) @visitor.when(PlusNode) def visit(self, node): left = self.visit(node.left) right = self.visit(node.right) - return PlusNode(left, right) + return PlusNode(left, right, node.token) @visitor.when(MinusNode) def visit(self, node): left = self.visit(node.left) right = self.visit(node.right) - return MinusNode(left, right) + return MinusNode(left, right, node.token) @visitor.when(StarNode) def visit(self, node): left = self.visit(node.left) right = self.visit(node.right) - return StarNode(left, right) + return StarNode(left, right, node.token) @visitor.when(DivNode) def visit(self, node): left = self.visit(node.left) right = self.visit(node.right) - return DivNode(left, right) + return DivNode(left, right, node.token) @visitor.when(LessNode) def visit(self, node): left = self.visit(node.left) right = self.visit(node.right) - return LessNode(left, right) + return LessNode(left, right, node.token) @visitor.when(LessEqualNode) def visit(self, node): left = self.visit(node.left) right = self.visit(node.right) - return LessEqualNode(left, right) + return LessEqualNode(left, right, node.token) @visitor.when(EqualNode) def visit(self, node): left = self.visit(node.left) right = self.visit(node.right) - return EqualNode(left, right) + return EqualNode(left, right, node.token) @visitor.when(ConstantNumNode) def visit(self, node): - return ConstantNumNode(node.lex) + return ConstantNumNode(node.token) @visitor.when(VariableNode) def visit(self, node): - return VariableNode(node.lex) + return VariableNode(node.token) @visitor.when(StringNode) def visit(self, node): - return StringNode(node.lex) + return StringNode(node.token) @visitor.when(BooleanNode) def visit(self, node): - return BooleanNode(node.lex) + return BooleanNode(node.token) @visitor.when(InstantiateNode) def visit(self, node): - return InstantiateNode(node.lex) + return InstantiateNode(node.lex, node.token) @visitor.when(NotNode) def visit(self, node): expr = self.visit(node.expr) - return NotNode(expr) + return NotNode(exp, node.token) @visitor.when(IsvoidNode) def visit(self, node): expr = self.visit(node.expr) - return IsvoidNode(expr) + return IsvoidNode(expr, node.token) @visitor.when(NegNode) def visit(self, node): expr = self.visit(node.expr) - return NegNode(expr) + return NegNode(expr, node.token) diff --git a/src/main.py b/src/main.py index 620f11eb3..0e6aad278 100644 --- a/src/main.py +++ b/src/main.py @@ -63,11 +63,17 @@ def pipeline(input_file: Path, output_file: Path = None): #get parsing tree ast = evaluate_reverse_parse(parse, operations, tokens) - + print("AST") + # print(ast) #printing tree - # formatter = FormatVisitorST() - # tree = formatter.visit(ast) - # print(tree) + formatter = FormatVisitorST() + tree = formatter.visit(ast) + print(tree) + + # type_visitor = TypeCollector(errors) + # ast = type_visitor.visit(ast) + # print("Type visitor tree") + # print(ast.context) visitors = [TypeCollector(errors), TypeBuilder(errors)] for visitor in visitors: diff --git a/src/type_builder.py b/src/type_builder.py index 29a52848d..719ae50da 100644 --- a/src/type_builder.py +++ b/src/type_builder.py @@ -99,7 +99,10 @@ def visit(self, node): for class_declaration in node.declarations: not_visited.append(class_declaration) # ++ - parent_type = class_declaration.parent + if not (class_declaration.parent is None): + parent_type = class_declaration.parent.lex + else: + parent_type = None try: self.context.get_type(parent_type) try: @@ -169,7 +172,7 @@ def visit(self, node): if node.parent is not None: try: - parent_type = self.get_type(node.parent) + parent_type = self.get_type(node.parent.lex) self.current_type.set_parent(parent_type) except SemanticError as error: self.errors.append(error.text) @@ -185,13 +188,13 @@ def visit(self, node): @visitor.when(FuncDeclarationNode) def visit(self, node): - param_names = [fname for fname, ftype in node.params] + param_names = [fname.lex for fname, ftype in node.params] try: - param_types = [self.get_type(ftype) for fname, ftype in node.params] - return_type = self.get_type(node.type) + param_types = [self.get_type(ftype.lex) for fname, ftype in node.params] + return_type = self.get_type(node.type.lex) self.current_type.define_method( - node.id, param_names, param_types, return_type + node.id.lex, param_names, param_types, return_type ) except SemanticError as error: # print("--------aqui se esta reportando el error del metodo doble---------") @@ -200,8 +203,8 @@ def visit(self, node): @visitor.when(AttrDeclarationNode) def visit(self, node): try: - attr_type = self.get_type(node.type) - self.current_type.define_attribute(node.id, attr_type) + attr_type = self.get_type(node.type.lex) + self.current_type.define_attribute(node.id.lex, attr_type) except SemanticError as error: self.errors.append(error.text) diff --git a/src/type_checker.py b/src/type_checker.py index 7cd1b69e7..cacfe1ac7 100644 --- a/src/type_checker.py +++ b/src/type_checker.py @@ -88,7 +88,7 @@ def visit(self, node, scope): @visitor.when(AttrDeclarationNode) def visit(self, node, scope): try: - typex = self.context.get_type(node.type) + typex = self.context.get_type(node.type.lex) except SemanticError as e: self.errors.append(e) @@ -106,7 +106,7 @@ def visit(self, node, scope): @visitor.when(FuncDeclarationNode) def visit(self, node, scope): - self.current_method = self.current_type.get_method(node.id) + self.current_method = self.current_type.get_method(node.id.lex) method_return_type = self.current_method.return_type if method_return_type.name == "SELF_TYPE": method_return_type = self.current_type @@ -158,7 +158,7 @@ def visit(self, node, scope): pass try: - return_type = self.context.get_type(node.type) + return_type = self.context.get_type(node.type.lex) if return_type.name == "SELF_TYPE": return self.current_type @@ -170,14 +170,14 @@ def visit(self, node, scope): @visitor.when(VarDeclarationNode) def visit(self, node, scope): - if scope.is_local(node.id): + if scope.is_local(node.id.lex): self.errors.append( LOCAL_ALREADY_DEFINED % (node.id, self.current_method.name) ) - elif node.id == "self": + elif node.id.lex == "self": self.errors.append(SELF_IS_READONLY) try: - static_type = self.context.get_type(node.type) + static_type = self.context.get_type(node.type.lex) except SemanticError as error: self.errors.append(error.text) static_type = ErrorType() @@ -186,22 +186,22 @@ def visit(self, node, scope): if not expr_type.conforms_to(static_type): self.errors.append(INCOMPATIBLE_TYPES % (expr_type.name, static_type.name)) - scope.define_variable(node.id, static_type) + scope.define_variable(node.id.lex, static_type) return static_type @visitor.when(AssignNode) def visit(self, node, scope): - if node.id == "self": + if node.id.lex == "self": self.errors.append(SELF_IS_READONLY) var_type = None - if not scope.is_defined(node.id): + if not scope.is_defined(node.id.lex): self.errors.append( VARIABLE_NOT_DEFINED % (node.id, self.current_method.name) ) var_type = ErrorType() else: - var_type = scope.find_variable(node.id).type + var_type = scope.find_variable(node.id.lex).type expr_type = self.visit(node.expr, scope) if not expr_type.conforms_to(var_type): @@ -223,16 +223,16 @@ def visit(self, node, scope): method = None try: - if node.at_type is not None: - node_at_type = self.context.get_type(node.at_type) - method = node_at_type.get_method(node.id) + if not( node.at_type is None): + node_at_type = self.context.get_type(node.at_type.lex) + method = node_at_type.get_method(node.id.lex) if not typex.conforms_to(node_at_type): self.errors.append( f"The static type to the left of @ ({typex.name}) must conform to the type specified to the right of @ ({node_at_type.name}) " ) return ErrorType() else: - method = typex.get_method(node.id) + method = typex.get_method(node.id.lex) except SemanticError as error: self.errors.append(error.text) return ErrorType() @@ -304,7 +304,7 @@ def visit(self, node, scope): static_type = None try: - static_type = self.context.get_type(node.type) + static_type = self.context.get_type(node.type.lex) if static_type.name == "SELF_TYPE": static_type = self.current_type scope.define_variable(node.id, static_type) @@ -337,8 +337,8 @@ def visit(self, node, scope): @visitor.when(CaseItemNode) def visit(self, node, scope): try: - static_type = self.context.get_type(node.type) - scope.define_variable(node.id, static_type) + static_type = self.context.get_type(node.type.lex) + scope.define_variable(node.id.lex, static_type) except SemanticError as e: self.errors.append(e) return ErrorType() @@ -350,7 +350,7 @@ def visit(self, node, scope): @visitor.when(InstantiateNode) # NewNode def visit(self, node, scope): try: - typex = self.context.get_type(node.lex) + typex = self.context.get_type(node.lex.lex) if typex.name == "SELF_TYPE": return self.current_type From a47cd564c2d2d9ab742a20950e82deea7449900c Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Fri, 25 Feb 2022 19:03:49 -0500 Subject: [PATCH 067/162] feat: add default value to attrs. Visited nodes return vars. --- customized_tests/test_hello_world.cl | 21 +++- src/ast_nodes.py | 5 + src/code_gen/cil_builder.py | 140 ++++++++++++++++----------- src/main.py | 28 ++++-- 4 files changed, 124 insertions(+), 70 deletions(-) diff --git a/customized_tests/test_hello_world.cl b/customized_tests/test_hello_world.cl index 9de631736..0565e3093 100644 --- a/customized_tests/test_hello_world.cl +++ b/customized_tests/test_hello_world.cl @@ -1,7 +1,26 @@ -class Main inherits IO { +(* class Main inherits IO { msg : String <- "Hello World"; main() : IO{ out_string(msg) }; +}; + +*) + + class Main { + main (): Object { + 0 + }; +}; + +class Point { + x: Int; + y: Int; + + init(x0: AUTO_TYPE, y0: AUTO_TYPE): AUTO_TYPE { { + x <- x0; + y <- y0; + self; + } }; }; \ No newline at end of file diff --git a/src/ast_nodes.py b/src/ast_nodes.py index 869599488..59d06a2ef 100644 --- a/src/ast_nodes.py +++ b/src/ast_nodes.py @@ -177,3 +177,8 @@ class LessEqualNode(ComparisonOperation): class EqualNode(ComparisonOperation): pass + + +class DefaultValueNode(ExpressionNode): + def __init__(self, typex): + self.type = typex diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index a17e665af..419798d8e 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -44,6 +44,8 @@ STRNode, SetAttribNode, GetAttribNode, + DefaultValueNode, + IsVoidNode, ) from cool_visitor import FormatVisitor @@ -151,9 +153,9 @@ def build_constructor(self, node): ] expr_list = [] - # for attr in attributeNodes: # Assign default value first - # assign = cool.AssignNode(attr.id, cool.DefaultValueNode(attr.type)) - # expr_list.append(assign) + for attr in attributeNodes: # Assign default value first + assign = cool.AssignNode(attr.id, cool.DefaultValueNode(attr.type)) + expr_list.append(assign) for attr in attributeNodes: # Assign init_expr if not None if attr.init_exp: @@ -171,7 +173,9 @@ def add_builtin_functions(self): self.cil_predef_method("copy", "Object", self.object_copy), self.cil_predef_method("type_name", "Object", self.object_type_name), ] - object_type = TypeNode("Object", [], obj_functions) + object_type = TypeNode("Object") + object_type.attributes = [] + object_type.methods = obj_functions # "IO" functions = [ @@ -180,7 +184,9 @@ def add_builtin_functions(self): self.cil_predef_method("in_string", "IO", self.io_instring), self.cil_predef_method("in_int", "IO", self.io_inint), ] - io_type = TypeNode("IO", [], obj_functions + functions) + io_type = TypeNode("IO") + io_type.attributes = [] + io_type.methods = obj_functions + functions # String functions = [ @@ -188,25 +194,23 @@ def add_builtin_functions(self): self.cil_predef_method("concat", "String", self.string_concat), self.cil_predef_method("substr", "String", self.string_substr), ] - string_type = TypeNode( - "String", - [VariableInfo("length").name, VariableInfo("str_ref").name], - obj_functions + functions, - ) + string_type = TypeNode("String") + string_type.attributes = [ + VariableInfo("length").name, + VariableInfo("str_ref").name, + ] + string_type.methods = obj_functions + functions # Int - int_type = TypeNode( - "Int", - [VariableInfo("value", is_attr=True).name], - obj_functions, - ) + int_type = TypeNode("Int") + int_type.attributes = [VariableInfo("value", is_attr=True).name] + int_type.methods = obj_functions # Bool - bool_type = TypeNode( - "Bool", - [VariableInfo("value", is_attr=True).name], - obj_functions, - ) + bool_type = TypeNode("Bool") + bool_type.attributes = [VariableInfo("value", is_attr=True).name] + bool_type.methods = obj_functions + for typex in [object_type, io_type, string_type, int_type, bool_type]: self.types.append(typex) @@ -369,6 +373,7 @@ def visit(self, node): ] visited_func.extend(methods) type_node.attributes.extend(attributes[::-1]) + # print("-------EXTENDED:", type_node.attributes) type_node.methods.extend( [ (item, self.to_function_name(item, current_type.name)) @@ -384,11 +389,10 @@ def visit(self, node): for feature in node.features: self.visit(feature) - self.current_type = None - @visitor.when(cool.AttrDeclarationNode) def visit(self, node): - self.visit(node.init_exp) + # self.visit(node.init_exp) + pass @visitor.when(cool.FuncDeclarationNode) def visit(self, node): @@ -455,7 +459,7 @@ def visit(self, node): # IF condition GOTO label condition_value = self.visit(node.if_expr) then_label = "THEN_" + self.next_id() - self.register_instruction(GotoIfNode(condition_value, then_label)) + self.register_instruction(GotoIfNode(condition_value, LabelNode(then_label))) # Else self.visit(node.else_expr) @@ -500,6 +504,11 @@ def visit(self, node): # End while label self.register_instruction(LabelNode(end_while_label)) + solve = self.define_internal_local() + self.register_instruction(DefaultValueNode(solve, "Void")) + + return solve + @visitor.when(cool.BlockNode) def visit(self, node): value = None @@ -514,7 +523,7 @@ def visit(self, node): self.visit(var_dec.expr) self.current_function.localvars.append(LocalNode(var_dec.id)) - self.visit(node.body) + return self.visit(node.body) @visitor.when(cool.CaseNode) def visit(self, node): @@ -530,89 +539,99 @@ def visit(self, node): left = self.visit(node.left) right = self.visit(node.right) - local = self.generate_next_tvar_id() - self.register_instruction(LocalNode(local)) - self.register_instruction(PlusNode(local, left, right)) + solve = self.define_internal_local() + self.register_instruction(PlusNode(solve, left, right)) + + return solve @visitor.when(cool.MinusNode) def visit(self, node): left = self.visit(node.left) right = self.visit(node.right) - local = self.generate_next_tvar_id() - self.register_instruction(LocalNode(local)) - self.register_instruction(MinusNode(local, left, right)) + solve = self.define_internal_local() + self.register_instruction(MinusNode(solve, left, right)) + + return solve @visitor.when(cool.StarNode) def visit(self, node): left = self.visit(node.left) right = self.visit(node.right) - local = self.generate_next_tvar_id() - self.register_instruction(LocalNode(local)) - self.register_instruction(StarNode(local, left, right)) + solve = self.define_internal_local() + self.register_instruction(StarNode(solve, left, right)) + + return solve @visitor.when(cool.DivNode) def visit(self, node): left = self.visit(node.left) right = self.visit(node.right) - local = self.generate_next_tvar_id() - self.register_instruction(LocalNode(local)) - self.register_instruction(DivNode(local, left, right)) + solve = self.define_internal_local() + self.register_instruction(DivNode(solve, left, right)) + + return solve @visitor.when(cool.LessEqualNode) def visit(self, node): left = self.visit(node.left) right = self.visit(node.right) - local = self.generate_next_tvar_id() - self.register_instruction(LocalNode(local)) - self.register_instruction(LessEqualNode(local, left, right)) + solve = self.define_internal_local() + self.register_instruction(LessEqualNode(solve, left, right)) + + return solve @visitor.when(cool.LessNode) def visit(self, node): left = self.visit(node.left) right = self.visit(node.right) - local = self.generate_next_tvar_id() - self.register_instruction(LocalNode(local)) - self.register_instruction(LessNode(local, left, right)) + solve = self.define_internal_local() + self.register_instruction(LessNode(solve, left, right)) + + return solve @visitor.when(cool.EqualNode) def visit(self, node): left = self.visit(node.left) right = self.visit(node.right) - local = self.generate_next_tvar_id() - self.register_instruction(LocalNode(local)) - self.register_instruction(EqualNode(local, left, right)) + solve = self.define_internal_local() + self.register_instruction(EqualNode(solve, left, right)) + + return solve # Unary operators @visitor.when(cool.InstantiateNode) # NewNode def visit(self, node): - new_local = self.generate_next_tvar_id() - self.register_instruction(LocalNode(new_local)) + new_local = self.define_internal_local() self.register_instruction(AllocateNode(node.lex, new_local)) + return new_local + @visitor.when(cool.IsvoidNode) def visit(self, node): value = self.visit(node.expr) - return value + solve = self.define_internal_local() + self.register_instruction(IsVoidNode(solve, value)) + return solve @visitor.when(cool.NotNode) def visit(self, node): value = self.visit(node.expr) - local = self.generate_next_tvar_id() - self.register_instruction(LocalNode(local)) - self.register_instruction(NotNode(local, value)) + solve = self.define_internal_local() + self.register_instruction(NotNode(solve, value)) + return solve @visitor.when(cool.NegNode) def visit(self, node): value = self.visit(node.expr) - local = self.generate_next_tvar_id() - self.register_instruction(LocalNode(local)) - self.register_instruction(IntComplementNode(local, value)) + solve = self.define_internal_local() + self.register_instruction(IntComplementNode(solve, value)) + return solve @visitor.when(cool.ConstantNumNode) def visit(self, node): @@ -630,7 +649,10 @@ def visit(self, node): @visitor.when(cool.BooleanNode) def visit(self, node): - if node.lex == "true": - return 1 - else: - return 0 + 1 if node.lex == "true" else 0 + + @visitor.when(cool.DefaultValueNode) + def visit(self, node): + solve = self.define_internal_local() + self.register_instruction(DefaultValueNode(solve, node.type)) + return solve diff --git a/src/main.py b/src/main.py index 7536aefce..ef7398446 100644 --- a/src/main.py +++ b/src/main.py @@ -44,7 +44,9 @@ def pipeline(input_file: Path, output_file: Path = None): # define grammar grammar, idx, type_id, string, num = define_cool_grammar() - tokens, pos_data = tokenize_cool_text(grammar, idx, type_id, string, num, text, errors) + tokens, pos_data = tokenize_cool_text( + grammar, idx, type_id, string, num, text, errors + ) # print(tokens) if len(errors) > 0: @@ -54,18 +56,20 @@ def pipeline(input_file: Path, output_file: Path = None): if len(errors) > 0: report_and_exit(errors) - parse, operations = parser([t.token_type for t in tokens], [t.lex for t in tokens], pos_data, text) + parse, operations = parser( + [t.token_type for t in tokens], [t.lex for t in tokens], pos_data, text + ) # print("Parse") # print(parse) if len(errors) > 0: report_and_exit(errors) - - #get parsing tree + + # get parsing tree ast = evaluate_reverse_parse(parse, operations, tokens) - #printing tree + # printing tree # formatter = FormatVisitorST() # tree = formatter.visit(ast) # print(tree) @@ -81,16 +85,20 @@ def pipeline(input_file: Path, output_file: Path = None): if len(errors) > 0: report_and_exit(errors) - # cool_to_cil_visitor = CILBuilder(errors) - # cil_ast = cool_to_cil_visitor.visit(ast) + cool_to_cil_visitor = CILBuilder(errors) + cil_ast = cool_to_cil_visitor.visit(ast) - # formatter = PrintVisitor() - # tree = formatter.visit(cil_ast) - # print(tree) + formatter = PrintVisitor() + tree = formatter.visit(cil_ast) + print(tree) # if output_file is None: # output_file = input.with_suffix(".mips") if __name__ == "__main__": + # input_file = Path( + # "/home/amanda/Documents/Facultad/Compilacion/cool-compiler-2021/customized_tests/test_hello_world.cl" + # ) + # pipeline(input_file) typer.run(pipeline) From 8758b4f6a7bf3ef9bd41a63274614e0cf9e506fe Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Fri, 25 Feb 2022 19:05:33 -0500 Subject: [PATCH 068/162] fix: TypeNode constructor only receives name param --- src/cmp/cil.py | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/cmp/cil.py b/src/cmp/cil.py index f5cf63f15..9e31b9d51 100644 --- a/src/cmp/cil.py +++ b/src/cmp/cil.py @@ -13,10 +13,10 @@ def __init__(self, dottypes, dotdata, dotcode): class TypeNode(Node): - def __init__(self, name, attributes=[], methods=[]): + def __init__(self, name): self.name = name - self.attributes = attributes - self.methods = methods + self.attributes = [] + self.methods = [] class DataNode(Node): @@ -259,6 +259,18 @@ def __init__(self, dest, source): self.source = source +class DefaultValueNode(InstructionNode): + def __init__(self, dest, typex): + self.dest = dest + self.type = typex + + +class IsVoidNode(InstructionNode): + def __init__(self, dest, value): + self.dest = dest + self.value = value + + class PrintVisitor(object): @visitor.on("node") def visit(self, node): @@ -387,6 +399,14 @@ def visit(self, node): def visit(self, node): return f"{node.dest} = SUBSTRING {node.source} {node.id} {node.length}" + @visitor.when(DefaultValueNode) + def visit(self, node): + return f"{node.dest} = DEFAULT {node.type}" + + @visitor.when(IsVoidNode) + def visit(self, node): + return f"{node.dest} = ISVOID {node.value}" + # printer = PrintVisitor() # return lambda ast: printer.visit(ast) From 6321ec4c9d4adf96f832de1fe3e6a462321b54d0 Mon Sep 17 00:00:00 2001 From: gabriela Date: Fri, 25 Feb 2022 22:40:38 -0500 Subject: [PATCH 069/162] Pass token to parser with actual column. Calculate token pos in lexical analizar.py. --- src/errors.py | 2 +- src/lexical_analizer.py | 6 +++--- src/main.py | 6 +++--- src/shift_reduce_parsers.py | 9 ++++----- src/type_checker.py | 4 +++- 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/errors.py b/src/errors.py index 6411c8a1b..5c62b2733 100644 --- a/src/errors.py +++ b/src/errors.py @@ -126,7 +126,7 @@ def __init__(self, line: int, column: int, msg: str) -> None: class SemanticError(CoolCompilerError): """ - Any kind of semantic error + Any kind of semantic error (like class redefinition) """ def __init__(self, line, column, msg) -> None: diff --git a/src/lexical_analizer.py b/src/lexical_analizer.py index c31247f69..243d843be 100644 --- a/src/lexical_analizer.py +++ b/src/lexical_analizer.py @@ -1,7 +1,7 @@ import ply.lex as lex import tokens_rules as tokens_rules from cmp.utils import Token - +from utils import find_column def pprint_tokens(tokens): indent = 0 @@ -46,7 +46,7 @@ def tokenize_cool_text(grammar, idx, type_id, string, num, data, errors, printin else: # empty program last_lineno = 0 col = -1 - tokens.append(Token("$", grammar.EOF, (last_lineno, col))) + tokens.append(Token("$", grammar.EOF, (last_lineno, find_column(data, col)))) break # No more input else: try: @@ -64,7 +64,7 @@ def tokenize_cool_text(grammar, idx, type_id, string, num, data, errors, printin ttype = type_id else: ttype = num - tokens.append(Token(tval, ttype, (tok.lineno,tok.lexpos))) + tokens.append(Token(tval, ttype, (tok.lineno, find_column(data, tok.lexpos)))) if printing: pprint_tokens(tokens) diff --git a/src/main.py b/src/main.py index 0e6aad278..79fcd6766 100644 --- a/src/main.py +++ b/src/main.py @@ -53,7 +53,7 @@ def pipeline(input_file: Path, output_file: Path = None): if len(errors) > 0: report_and_exit(errors) - parse, operations = parser(tokens, text) + parse, operations = parser(tokens) # print("Parse") # print(parse) @@ -63,12 +63,12 @@ def pipeline(input_file: Path, output_file: Path = None): #get parsing tree ast = evaluate_reverse_parse(parse, operations, tokens) - print("AST") + # print("AST") # print(ast) #printing tree formatter = FormatVisitorST() tree = formatter.visit(ast) - print(tree) + # print(tree) # type_visitor = TypeCollector(errors) # ast = type_visitor.visit(ast) diff --git a/src/shift_reduce_parsers.py b/src/shift_reduce_parsers.py index 25931808a..7464ee7ad 100644 --- a/src/shift_reduce_parsers.py +++ b/src/shift_reduce_parsers.py @@ -6,7 +6,6 @@ from methods import compute_firsts, compute_local_first, compute_follows from cmp.automata import State from errors import shift_reduce_error, invalid_sentence_error, SyntacticError -from utils import find_column class ShiftReduceParser: SHIFT = "SHIFT" @@ -24,7 +23,7 @@ def __init__(self, G, errors, verbose=False): def _build_parsing_table(self): raise NotImplementedError() - def __call__(self, w, text): + def __call__(self, w): stack = [0] cursor = 0 output = [] @@ -45,7 +44,7 @@ def __call__(self, w, text): self.errors.append( SyntacticError( current_token.location[0], - find_column(text, current_token.location[1]), + current_token.location[1], "ERROR at or near "+ str(current_token.lex) ) ) @@ -75,7 +74,7 @@ def __call__(self, w, text): self.errors.append( SyntacticError( current_token.location[0], - find_column(text, current_token.location[1]), + current_token.location[1], "ERROR at or near"+ str(current_token.lex) ) ) @@ -87,7 +86,7 @@ def __call__(self, w, text): self.errors.append( SyntacticError( current_token.location[0], - find_column(text, current_token.location[1]), + current_token.location[1], "Exceed word length while looking for a viable derivation. Sentence given does not belong to the grammar", ) ) diff --git a/src/type_checker.py b/src/type_checker.py index cacfe1ac7..a07f5d601 100644 --- a/src/type_checker.py +++ b/src/type_checker.py @@ -41,6 +41,7 @@ from cmp.semantic import Scope from cmp.utils import find_least_type import copy +from errors import TypeError WRONG_SIGNATURE = 'Method "%s" already defined in "%s" with a different signature.' SELF_IS_READONLY = 'Variable "self" is read-only.' @@ -373,7 +374,8 @@ def visit(self, node, scope): if (left_type != int_type and left_type.name != "AUTO_TYPE") or ( right_type != int_type and right_type.name != "AUTO_TYPE" ): - self.errors.append(INVALID_OPERATION % (left_type.name, right_type.name)) + node_row, node_col = node.token.location + self.errors.append(TypeError( node_row, node_col, INVALID_OPERATION % (left_type.name, right_type.name))) return int_type From c387b60d7b79eaf2887c8cd35fd683a97f349de2 Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Fri, 25 Feb 2022 23:56:51 -0500 Subject: [PATCH 070/162] feat: add missing nodes to PrintVisitor --- src/cmp/cil.py | 61 ++++++++++++++++++++++++++----------- src/code_gen/cil_builder.py | 6 ++-- 2 files changed, 46 insertions(+), 21 deletions(-) diff --git a/src/cmp/cil.py b/src/cmp/cil.py index 9e31b9d51..aaf8ba857 100644 --- a/src/cmp/cil.py +++ b/src/cmp/cil.py @@ -32,12 +32,6 @@ def __init__(self, fname, params, localvars, instructions): self.localvars = localvars self.instructions = instructions - # def __str__(self): - # print("NAME:", self.name) - # # print("PARAMS:", self.params) - # # print("LOCALS:", self.localvars) - # print("INSTRUCTIONS", self.instructions) - class ParamNode(Node): def __init__(self, name): @@ -127,6 +121,10 @@ def __init__(self, typex, attr, value): self.attr = attr +class ArrayNode(InstructionNode): + pass + + class GetIndexNode(InstructionNode): pass @@ -141,10 +139,6 @@ def __init__(self, itype, dest): self.dest = dest -class ArrayNode(InstructionNode): - pass - - class TypeOfNode(InstructionNode): def __init__(self, obj, dest): self.obj = obj @@ -152,7 +146,8 @@ def __init__(self, obj, dest): class LabelNode(InstructionNode): - pass + def __init__(self, name): + self.name = name class GotoNode(InstructionNode): @@ -242,12 +237,6 @@ def __init__(self, dest, source): self.source = source -class STRNode(InstructionNode): - def __init__(self, dest, source): - self.dest = dest - self.source = source - - class PrintNode(InstructionNode): def __init__(self, str_addr): self.str_addr = str_addr @@ -313,7 +302,7 @@ def visit(self, node): @visitor.when(AssignNode) def visit(self, node): - return f"{node.dest} = {node.source}" + return f"{node.dest} <- {node.source}" @visitor.when(PlusNode) def visit(self, node): @@ -331,6 +320,38 @@ def visit(self, node): def visit(self, node): return f"{node.dest} = {node.left} / {node.right}" + @visitor.when(LessNode) + def visit(self, node): + return f"{node.dest} = {node.left} < {node.right}" + + @visitor.when(LessEqualNode) + def visit(self, node): + return f"{node.dest} = {node.left} <= {node.right}" + + @visitor.when(EqualNode) + def visit(self, node): + return f"{node.dest} = {node.left} == {node.right}" + + @visitor.when(NotNode) + def visit(self, node): + return f"{node.dest} = NOT {node.expr}" + + @visitor.when(IntComplementNode) + def visit(self, node): + return f"{node.dest} = ~ {node.expr}" + + @visitor.when(LabelNode) + def visit(self, node): + return f"LABEL {node.name}" + + @visitor.when(GotoNode) + def visit(self, node): + return f"GOTO {node.label}" + + @visitor.when(GotoIfNode) + def visit(self, node): + return f"IF {node.condition} GOTO {node.label}" + @visitor.when(AllocateNode) def visit(self, node): return f"{node.dest} = ALLOCATE {node.type}" @@ -391,6 +412,10 @@ def visit(self, node): def visit(self, node): return f"{node.dest} = LENGTH {node.source}" + @visitor.when(LoadNode) + def visit(self, node): + return f"{node.dest} = LOAD {node.msg}" + @visitor.when(ConcatNode) def visit(self, node): return f"{node.dest} = CONCAT {node.left} {node.right}" diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index 419798d8e..de6e657ce 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -41,7 +41,6 @@ RuntimeErrorNode, CopyNode, TypeNameNode, - STRNode, SetAttribNode, GetAttribNode, DefaultValueNode, @@ -373,7 +372,6 @@ def visit(self, node): ] visited_func.extend(methods) type_node.attributes.extend(attributes[::-1]) - # print("-------EXTENDED:", type_node.attributes) type_node.methods.extend( [ (item, self.to_function_name(item, current_type.name)) @@ -391,7 +389,6 @@ def visit(self, node): @visitor.when(cool.AttrDeclarationNode) def visit(self, node): - # self.visit(node.init_exp) pass @visitor.when(cool.FuncDeclarationNode) @@ -442,6 +439,9 @@ def visit(self, node): @visitor.when(cool.CallNode) def visit(self, node): + # TODO: Pending .id(,...,) + # TODO: Pending @.id(,...,) + for arg in node.args: temp = self.define_internal_local() value = self.visit(arg) From 2ddb02a259f30a0c48da8bcb2a520ca674dd4c1a Mon Sep 17 00:00:00 2001 From: smartos99 Date: Mon, 28 Feb 2022 20:23:55 -0500 Subject: [PATCH 071/162] add simple functions funcionalities --- src/code_gen/mips_builder.py | 239 +++++++++++++++++++++++++---------- 1 file changed, 172 insertions(+), 67 deletions(-) diff --git a/src/code_gen/mips_builder.py b/src/code_gen/mips_builder.py index 4b3536d43..67cb5157b 100644 --- a/src/code_gen/mips_builder.py +++ b/src/code_gen/mips_builder.py @@ -2,6 +2,8 @@ from email.quoprimime import body_length import enum from operator import le +from tkinter.tix import Select +from attr import attr from soupsieve import select import cmp.visitor as visitor @@ -15,11 +17,20 @@ #type_info offsets TYPENAME_OFFSET = 0 FUNCTION_OFFSET = 4 -RA_OFFSET = 4 +RA_OFFSET = 8 +OLD_FP_OFFSET = 4 FP_ARGS_DISTANCE = 3 # how far finishes $fp from arguments in method call FP_LOCALS_DISTANCE = 0 # how far finishes $fp from localvars in method call +ABORT_SIGNAL = "abort_signal"#CIL +CASE_MISSMATCH = "case_missmatch"#CIL +CASE_VOID = "case_on_void"#MIPS +DISPATCH_VOID = "dispatch_on_void"#MIPS +ZERO_DIVISION = "division_by_zero"#MIPS +SUBSTR_OUT_RANGE = "substr_out_of_range"#MIPS +HEAP_OVERFLOW = "heap_overflow" + #temporary registers t0 = "$t0" t1 = "$t1" @@ -53,6 +64,13 @@ s3 = "$s3" zero = "$zero" +SYSCALL_PRINT_INT = 1 +SYSCALL_PRINT_STR = 4 +SYSCALL_READ_INT = 5 +SYSCALL_READ_STR = 8 +SYSCALL_SBRK = 9 +SYSCALL_EXIT = 10 + class MemoryManager: def __init__(self): self.all_reg = [t0,t1,t2,t3,t4,t5,t6,t7,t8,t9] @@ -73,35 +91,28 @@ def save(self): self.stored = self.used_reg.copy() -SYSCALL_PRINT_INT = 1 -SYSCALL_PRINT_STR = 4 -SYSCALL_READ_INT = 5 -SYSCALL_READ_STR = 8 -SYSCALL_SBRK = 9 -SYSCALL_EXIT = 10 - class MIPSBuilder: - def __init__(self,errors,cil_ast): + def __init__(self,errors): self.mips_code = "" - self.cil_ast = cil_ast self.main_procedure = mips.ProcedureNode("main") self.current_procedure = self.main_procedure self.text = [self.main_procedure] self.data = [] self.params = [] self.locals = [] - self.types = {} + self.types = dict() + self.attr_offset = dict() self.memo = MemoryManager() - def get_dir_in_memo(self,x): + def get_offset(self,x): if x in self.locals: index = self.locals.index(x) return -4*index elif x in self.params: index = self.params.index(x) - return (4*index)+4 + return (-4 * (len(self.locals)+len(self.params)))-4 def register_instruction(self, instruction_type, *args): instruction = instruction_type(*args) @@ -120,6 +131,22 @@ def register_pop(self, reg): self.register_instruction(mips.LoadWordNode, reg, 4, sp) self.register_instruction(mips.AddiNode, sp, sp, 4) + def generate_exception_messages(self): + self.register_data(mips.DataTypeNode, ABORT_SIGNAL, '.asciiz', ['"Program execution aborted"']) + self.register_data(mips.DataTypeNode, CASE_MISSMATCH, '.asciiz', ['"Execution of a case statement without a matching branch"']) + self.register_data(mips.DataTypeNode, CASE_VOID, '.asciiz', ['"Case on void"']) + self.register_data(mips.DataTypeNode, DISPATCH_VOID, '.asciiz', ['"Dispatch on void"']) + self.register_data(mips.DataTypeNode, ZERO_DIVISION, '.asciiz', ['"Division by zero"']) + self.register_data(mips.DataTypeNode, SUBSTR_OUT_RANGE, '.asciiz', ['"Substring out of range"']) + self.register_data(mips.DataTypeNode, HEAP_OVERFLOW, '.asciiz', ['"Heap overflow"']) + + def generate_attr_offset(self,type): + attributes = self.types[type].attributes + + for i,attr in attributes: + self.attr_offset[attr] = 4(i+1) + + @visitor.on("node") def visit(self, node=None): @@ -129,7 +156,9 @@ def visit(self, node=None): def visit(self, node): for type in node.types: self.visit(type) - + + self.generate_attr_offset + self.generate_exception_messages() for str_data in node.data: self.visit(str_data) @@ -145,39 +174,32 @@ def visit(self, node): def visit(self, node): self.types[node.name] = node - #for func in node.methods: - values = [-1]*(len(node.methods)+1) + values = [] + for func in node.methods: + values.append(func[1]) + self.register_data(mips.DataTypeNode,'.word',node.name,values) self.register_data(mips.DataTypeNode, f'{node.name}_cname','.asciiz', [f'"{node.name}"']) #Filling type type info - self.register_instruction(mips.CommentNode(f"Filling {node.name} VT")) - self.register_instruction(mips.LoadAddress,t0,node.name) - self.register_instruction(mips.LoadAddress,t1,f'{node.name}_cname') + #self.register_instruction(mips.CommentNode(f"Filling {node.name} VT")) + #self.register_instruction(mips.LoadAddress,t0,node.name) + #self.register_instruction(mips.LoadAddress,t1,f'{node.name}_cname') - self.register_instruction(mips.StoreWordNode,t1,TYPENAME_OFFSET,t0) + #self.register_instruction(mips.StoreWordNode,t1,TYPENAME_OFFSET,t0) #Filling type VT - for i,func in enumerate(node.methods): - offset = FUNCTION_OFFSET*i - self.register_instruction(mips.LoadAddress,t1,func.name) - self.register_instruction(mips.StoreWordNode,t1,offset,t0) + #for i,func in enumerate(node.methods): + # offset = FUNCTION_OFFSET*i + # self.register_instruction(mips.LoadAddress,t1,func.name) + # self.register_instruction(mips.StoreWordNode,t1,offset,t0) @visitor.when(cil.DataNode) def visit(self, node): self.register_data(mips.DataTypeNode,'.ascii',node.vname,[node.value]) - @visitor.when(cil.LocalNode) - def visit(self,node): - self.memo.save() - reg = self.memo.get_unused_reg() - self.register_instruction(mips.LoadAddress,reg,node.name) - self.register_instruction(mips.StoreWordNode,reg,0,sp) - - self.register_instruction(mips.AddiNode,sp,sp,-4) - self.locals.append(node.name) - self.memo.clean() + @visitor.when(cil.ParamNode) def visit(self,node): @@ -196,18 +218,14 @@ def visit(self,node): self.memo.save() reg = self.memo.get_unused_reg() - dir = self.get_dir_in_memo(node.name) - self.register_instruction(mips.LoadWordNode,reg,dir,fp) - - self.register_instruction(mips.StoreWordNode,reg,0,sp) + offset = self.get_offset(node.name) + self.register_instruction(mips.LoadWordNode,reg,offset,fp) + self.register_push(reg) - self.register_instruction(mips.AddiNode,sp,sp,4) self.memo.clean() - - @visitor.when(cil.FunctionNode) def visit(self,node): @@ -217,6 +235,8 @@ def visit(self,node): self.register_push(ra) self.register_instruction(mips.CommentNode,"Saving $fp") + self.register_push(fp) + self.register_instruction(mips.CommentNode,"New $fp") self.register_instruction(mips.MoveNode, fp, sp) self.register_comment("Reserving space for locals") @@ -235,12 +255,13 @@ def visit(self,node): self.register_instruction(mips.LoadWordNode, fp, OLD_FP_OFFSET, fp)#stored (old)$fp AR = 4*(len(node.localvars) + len(node.arguments) + 2) + #AR = 4*(len(node.localvars) + 2) + self.register_instruction(mips.CommentNode("Cleaning stack after call")) self.register_instruction(mips.AddiNode, sp, sp, AR) self.register_instruction(mips.CommentNode("Return jump")) self.register_instruction(mips.JumpRegister, ra) - self.text.append(self.current_procedure) @@ -255,53 +276,53 @@ def visit(self,node): else: self.register_instruction(mips.LoadAddress,reg,node.msg) - - dir = self.get_dir_in_memo(node.dest) - self.register_instruction(mips.StoreWordNode,reg,dir,fp) + offset = self.get_offset(node.dest) + self.register_instruction(mips.StoreWordNode,reg,offset,fp) self.memo.clean() - + #All return value is saved in register a1 @visitor.when(cil.ReturnNode) - def visit(self): - pass + def visit(self,node): + offset = self.get_offset() + self.register_instruction(mips.LoadWordNode,a1,offset,fp) @visitor.when(cil.GotoNode) def visit(self,node): self.register_instruction(mips.UnconditionalJumpNode,node.label) - @visitor.when(cil.GotoIfNode) - def visit(self,node): - pass + @visitor.when(cil.AllocateNode) def visit(self,node): + self.memo.save() _size = (len(self.types[node.type].attributes)+1)*4 - self.register_instruction(mips.LoadInmediate,v0,9) + self.register_instruction(mips.LoadInmediate,v0,SYSCALL_SBRK) self.register_instruction(mips.LoadInmediate,a0,_size) self.register_instruction(mips.SyscallNode) - dir = self.get_dir_in_memo(node.dest) + dest_offset = self.get_offset(node.dest) + self.register_instruction(mips.StoreWordNode,v0,dest_offset,fp) + + reg = self.memo.get_unused_reg() + self.register_instruction(mips.LoadAddress,reg,node.type) + self.register_instruction(mips.StoreWordNode,reg,0,v0) - self.register_instruction(mips.StoreWordNode,v0,dir,fp) self.memo.clean() - - - @visitor.when(cil.AssignNode) def visit(self,node): self.save() reg = self.memo.get_unused_reg() - source_dir = self.get_dir_in_memo(node.source) - dest_dir = self.get_dir_in_memo(node.dest) + source_offset = self.get_offset(node.source) + dest_offset = self.get_offset(node.dest) - self.register_instruction(mips.LoadWordNode,reg,source_dir,fp) + self.register_instruction(mips.LoadWordNode,reg,source_offset,fp) - self.register_instruction(mips.StoreWordNode,reg,dest_dir,fp) + self.register_instruction(mips.StoreWordNode,reg,dest_offset,fp) self.memo.clean() @@ -321,8 +342,8 @@ def visit(self,node): self.register_instruction(mips.AddNode,reg3,reg1,reg2) - dir = self.get_dir_in_memo(node.dest) - self.register_instruction(mips.StoreWordNode,reg3,dir,fp) + offset = self.get_offset(node.dest) + self.register_instruction(mips.StoreWordNode,reg3,offset,fp) self.memo.clean() @@ -339,17 +360,101 @@ def visit(self,node): self.register_instruction(mips.SubNode,reg3,reg1,reg2) - dir = self.get_dir_in_memo(node.dest) - self.register_instruction(mips.StoreWordNode,reg3,dir,fp) + offset = self.get_offset(node.dest) + self.register_instruction(mips.StoreWordNode,reg3,offset,fp) + + self.memo.clean() + + @visitor.when(cil.RuntimeErrorNode) + def visit(self,node): + + self.register_instruction(mips.CommentNode,"Printing Abort Message") + self.register_instruction(mips.LoadAddress,a0,ABORT_SIGNAL) + self.register_instruction(mips.LoadInmediate,v0,SYSCALL_PRINT_STR) + self.register_instruction(mips.SyscallNode) + + self.register_instruction(mips.CommentNode,"Aborting execution") + self.register_instruction(mips.LoadInmediate,v0,SYSCALL_EXIT) + self.register_instruction(mips.SyscallNode) + + #PENDIENTEEEEEEEE + @visitor.when(cil.CopyNode) + def visit(self,node): + self.register_instruction(mips.CommentNode,"CopyNode") + + self.register_instruction(mips.CommentNode,"Printing Abort Message") + self.register_instruction(mips.LoadAddress,a0,ABORT_SIGNAL) + self.register_instruction(mips.LoadInmediate,v0,SYSCALL_PRINT_STR) + self.register_instruction(mips.SyscallNode) + + self.register_instruction(mips.CommentNode,"Aborting execution") + self.register_instruction(mips.LoadInmediate,v0,SYSCALL_EXIT) + self.register_instruction(mips.SyscallNode) + + @visitor.when(cil.StaticCallNode) + def visit(self,node): + + self.register_instruction(mips.JumpAndLink,node.function) + + dest_offset = self.get_offset() + self.register_instruction(mips.StoreWordNode,a1,dest_offset,fp) + + @visitor.when(cil.GetAttribNode) + def visit(self, node): + self.memo.save() + + reg1 = self.memo.get_unused_reg() + reg2 = self.memo.get_unused_reg() + + instance_offset = self.get_offset() + self.register_instruction(mips.LoadWordNode,reg1,instance_offset,fp) + + attr_offs = self.attr_offset[node.attr] + self.register_instruction(mips.LoadWordNode,reg2,attr_offs,reg1) + + dest_offs = self.get_offset() + self.register_instruction(mips.StoreWordNode,reg2,dest_offs,fp) + + @visitor.when(cil.SetAttribNode) + def visit(self, node): + self.memo.save() + reg1 = self.memo.get_unused_reg() + reg2 = self.memo.get_unused_reg() + + instance_offset = self.get_offset(node.type) + self.register_instruction(mips.LoadWordNode,reg1,instance_offset,fp) + + value_offset = self.get_offset(node.value) + self.register_instruction(mips.LoadWordNode,reg2,value_offset,fp) + + attr_os = self.attr_offset[node.attr] + self.register_instruction(mips.StoreWordNode,reg2,attr_os,reg1) + self.memo.clean() + + #Incompleto @visitor.when(cil.TypeOfNode) def visit(self,node): self.memo.save() - reg1 = self.get_dir_in_memo() - reg2 = self.get_dir_in_memo() + reg1 = self.get_offset() + reg2 = self.get_offset() + + @visitor.when(cil.TypeNameNode) + def visit(self,node): + pass + + @visitor.when(cil.GotoIfNode) + def visit(self,node): + pass + + @visitor.when(cil.LocalNode) #No hace falta + def visit(self,node): + pass + + From 9ddaf657e004d18fa8202dbadc1c0adf80d223ff Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Tue, 1 Mar 2022 18:06:56 -0500 Subject: [PATCH 072/162] feat: add return value to If, While and Boolean Nodes --- src/code_gen/cil_builder.py | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index de6e657ce..b515ea871 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -288,7 +288,9 @@ def io_outint(self): int_arg = VariableInfo("int") self.register_param(int_arg) result = self.define_internal_local() - self.register_instruction(ToStrNode(result, int_arg.name)) + self.register_instruction( + ToStrNode(result, int_arg.name) + ) # TODO: Define PrintIntNode self.register_instruction(ReturnNode(VariableInfo(result).name)) def io_instring(self): @@ -437,32 +439,44 @@ def visit(self, node): else: self.register_instruction(AssignNode(node.id, expr)) + return node.id + @visitor.when(cool.CallNode) def visit(self, node): # TODO: Pending .id(,...,) # TODO: Pending @.id(,...,) + # function_name = self.to_function_name(node.id, self.current_type.name) + for arg in node.args: temp = self.define_internal_local() value = self.visit(arg) self.register_instruction(AssignNode(temp, value)) self.register_instruction(ArgNode(temp)) + # if node.obj: + # obj_value = self.visit(node.obj) + # self.register_instruction() + method_name = self.to_function_name(node.id, self.current_type.name) - result = self.define_internal_local() - self.register_instruction(StaticCallNode(method_name, result)) + solve = self.define_internal_local() + self.register_instruction(StaticCallNode(method_name, solve)) - return result + return solve @visitor.when(cool.IfNode) def visit(self, node): + # Result Variable + solve = self.define_internal_local() + # IF condition GOTO label condition_value = self.visit(node.if_expr) then_label = "THEN_" + self.next_id() - self.register_instruction(GotoIfNode(condition_value, LabelNode(then_label))) + self.register_instruction(GotoIfNode(condition_value, then_label)) # Else - self.visit(node.else_expr) + else_value = self.visit(node.else_expr) + self.register_instruction(AssignNode(solve, else_value)) # GOTO end_label end_label = "END_IF_" + self.next_id() # Example: END_IF_120 @@ -470,12 +484,13 @@ def visit(self, node): # Then label self.register_instruction(LabelNode(then_label)) - self.visit(node.then_expr) + then_value = self.visit(node.then_expr) + self.register_instruction(AssignNode(solve, then_value)) # end_label self.register_instruction(LabelNode(end_label)) - # TODO: return something? + return solve @visitor.when(cool.WhileNode) def visit(self, node): @@ -484,7 +499,7 @@ def visit(self, node): self.register_instruction(LabelNode(while_label)) # Condition - c = self.visit(node.condition) # TODO: pop from stack + c = self.visit(node.condition) # If condition GOTO body_label body_label = "BODY_" + self.next_id() @@ -649,7 +664,9 @@ def visit(self, node): @visitor.when(cool.BooleanNode) def visit(self, node): - 1 if node.lex == "true" else 0 + solve = self.define_internal_local() + self.register_instruction(AssignNode(solve, 1 if node.lex == "true" else 0)) + return solve @visitor.when(cool.DefaultValueNode) def visit(self, node): From f75103995b47b969843e54ad4036bf9162e11d17 Mon Sep 17 00:00:00 2001 From: smartos99 Date: Tue, 1 Mar 2022 20:10:00 -0500 Subject: [PATCH 073/162] Merge dev into mips --- src/code_gen/mips_builder.py | 127 ++++++++++++++++++++++------------- src/code_gen/mips_nodes.py | 24 +++---- src/code_gen/mips_writer.py | 34 ++++++++-- src/main.py | 13 ++-- 4 files changed, 127 insertions(+), 71 deletions(-) diff --git a/src/code_gen/mips_builder.py b/src/code_gen/mips_builder.py index 67cb5157b..211d41e7e 100644 --- a/src/code_gen/mips_builder.py +++ b/src/code_gen/mips_builder.py @@ -1,16 +1,16 @@ -from atexit import register -from email.quoprimime import body_length +#from atexit import register +#from email.quoprimime import body_length import enum -from operator import le -from tkinter.tix import Select +#from operator import le +#from tkinter.tix import Select from attr import attr -from soupsieve import select +#from soupsieve import select import cmp.visitor as visitor import cmp.cil as cil import random -import mips_nodes as mips +from code_gen import mips_nodes as mips @@ -93,7 +93,7 @@ def save(self): class MIPSBuilder: - def __init__(self,errors): + def __init__(self): self.mips_code = "" self.main_procedure = mips.ProcedureNode("main") self.current_procedure = self.main_procedure @@ -101,8 +101,8 @@ def __init__(self,errors): self.data = [] self.params = [] self.locals = [] - self.types = dict() - self.attr_offset = dict() + self.types = {} + self.attr_offset = {} self.memo = MemoryManager() @@ -142,9 +142,9 @@ def generate_exception_messages(self): def generate_attr_offset(self,type): attributes = self.types[type].attributes - - for i,attr in attributes: - self.attr_offset[attr] = 4(i+1) + self.attr_offset[type]={} + for i,attr in enumerate(attributes): + self.attr_offset[type][attr] = 4*(i+1) @@ -154,16 +154,17 @@ def visit(self, node=None): @visitor.when(cil.ProgramNode) def visit(self, node): - for type in node.types: + for type in node.dottypes: self.visit(type) + self.generate_attr_offset(type.name) + - self.generate_attr_offset self.generate_exception_messages() - for str_data in node.data: + for str_data in node.dotdata: self.visit(str_data) - for instruction in node.code: + for instruction in node.dotcode: self.visit(instruction) @@ -197,7 +198,7 @@ def visit(self, node): @visitor.when(cil.DataNode) def visit(self, node): - self.register_data(mips.DataTypeNode,'.ascii',node.vname,[node.value]) + self.register_data(mips.DataTypeNode,'.ascii',node.name,[node.value]) @@ -222,7 +223,6 @@ def visit(self,node): self.register_instruction(mips.LoadWordNode,reg,offset,fp) self.register_push(reg) - self.memo.clean() @@ -239,28 +239,33 @@ def visit(self,node): self.register_instruction(mips.CommentNode,"New $fp") self.register_instruction(mips.MoveNode, fp, sp) - self.register_comment("Reserving space for locals") + self.register_instruction(mips.CommentNode,"Reserving space for locals") self.register_instruction(mips.AddiNode, sp, sp, -4*len(node.localvars)) - self.register_instruction(mips.CommentNode("Executing instructions")) + for local in node.localvars: + self.locals.append(local.name) + + self.register_instruction(mips.CommentNode,"Executing instructions") for inst in node.instructions: self.visit(inst) - self.register_instruction(mips.CommentNode("Restoring saved $ra")) + self.register_instruction(mips.CommentNode,"Restoring saved $ra") self.register_instruction(mips.LoadWordNode, ra, RA_OFFSET, fp)#stored $ra - self.register_comment("Restoring saved $fp") + self.register_instruction(mips.CommentNode,"Restoring saved $fp") self.register_instruction(mips.LoadWordNode, fp, OLD_FP_OFFSET, fp)#stored (old)$fp - - AR = 4*(len(node.localvars) + len(node.arguments) + 2) + + + #Cual de las dos???? + AR = 4*(len(node.localvars) + len(node.params) + 2) #AR = 4*(len(node.localvars) + 2) - self.register_instruction(mips.CommentNode("Cleaning stack after call")) + self.register_instruction(mips.CommentNode,"Cleaning stack after call") self.register_instruction(mips.AddiNode, sp, sp, AR) - self.register_instruction(mips.CommentNode("Return jump")) + self.register_instruction(mips.CommentNode,"Return jump") self.register_instruction(mips.JumpRegister, ra) self.text.append(self.current_procedure) @@ -284,7 +289,7 @@ def visit(self,node): #All return value is saved in register a1 @visitor.when(cil.ReturnNode) def visit(self,node): - offset = self.get_offset() + offset = self.get_offset(node.value) self.register_instruction(mips.LoadWordNode,a1,offset,fp) @visitor.when(cil.GotoNode) @@ -377,26 +382,13 @@ def visit(self,node): self.register_instruction(mips.LoadInmediate,v0,SYSCALL_EXIT) self.register_instruction(mips.SyscallNode) - #PENDIENTEEEEEEEE - @visitor.when(cil.CopyNode) - def visit(self,node): - self.register_instruction(mips.CommentNode,"CopyNode") - - self.register_instruction(mips.CommentNode,"Printing Abort Message") - self.register_instruction(mips.LoadAddress,a0,ABORT_SIGNAL) - self.register_instruction(mips.LoadInmediate,v0,SYSCALL_PRINT_STR) - self.register_instruction(mips.SyscallNode) - - self.register_instruction(mips.CommentNode,"Aborting execution") - self.register_instruction(mips.LoadInmediate,v0,SYSCALL_EXIT) - self.register_instruction(mips.SyscallNode) @visitor.when(cil.StaticCallNode) def visit(self,node): self.register_instruction(mips.JumpAndLink,node.function) - dest_offset = self.get_offset() + dest_offset = self.get_offset(node.dest) self.register_instruction(mips.StoreWordNode,a1,dest_offset,fp) @visitor.when(cil.GetAttribNode) @@ -406,13 +398,13 @@ def visit(self, node): reg1 = self.memo.get_unused_reg() reg2 = self.memo.get_unused_reg() - instance_offset = self.get_offset() + instance_offset = self.get_offset(node.type) self.register_instruction(mips.LoadWordNode,reg1,instance_offset,fp) - attr_offs = self.attr_offset[node.attr] + attr_offs = self.attr_offset[node.type][node.attr] self.register_instruction(mips.LoadWordNode,reg2,attr_offs,reg1) - dest_offs = self.get_offset() + dest_offs = self.get_offset(node.dest) self.register_instruction(mips.StoreWordNode,reg2,dest_offs,fp) @@ -428,21 +420,60 @@ def visit(self, node): value_offset = self.get_offset(node.value) self.register_instruction(mips.LoadWordNode,reg2,value_offset,fp) - attr_os = self.attr_offset[node.attr] + attr_os = self.attr_offset[node.type][node.attr] self.register_instruction(mips.StoreWordNode,reg2,attr_os,reg1) self.memo.clean() + + #PENDIENTEEEEEEEE + @visitor.when(cil.CopyNode) + def visit(self,node): + self.register_instruction(mips.CommentNode,"CopyNode") + + self.register_instruction(mips.CommentNode,"Printing Abort Message") + self.register_instruction(mips.LoadAddress,a0,ABORT_SIGNAL) + self.register_instruction(mips.LoadInmediate,v0,SYSCALL_PRINT_STR) + self.register_instruction(mips.SyscallNode) + + self.register_instruction(mips.CommentNode,"Aborting execution") + self.register_instruction(mips.LoadInmediate,v0,SYSCALL_EXIT) + self.register_instruction(mips.SyscallNode) #Incompleto @visitor.when(cil.TypeOfNode) def visit(self,node): - self.memo.save() + #self.memo.save() - reg1 = self.get_offset() - reg2 = self.get_offset() + #reg1 = self.get_offset() + #reg2 = self.get_offset() + pass + @visitor.when(cil.TypeNameNode) + def visit(self,node): + pass + @visitor.when(cil.PrintNode) + def visit(self,node): + pass + + @visitor.when(cil.ToStrNode) + def visit(self,node): + pass + @visitor.when(cil.ReadNode) + def visit(self,node): + pass + @visitor.when(cil.LengthNode) + def visit(self,node): + pass + @visitor.when(cil.ConcatNode) + def visit(self,node): + pass + @visitor.when(cil.SubstringNode) + def visit(self,node): + pass + + @visitor.when(cil.PrefixNode) def visit(self,node): pass diff --git a/src/code_gen/mips_nodes.py b/src/code_gen/mips_nodes.py index 75793f695..3d7dd0cfc 100644 --- a/src/code_gen/mips_nodes.py +++ b/src/code_gen/mips_nodes.py @@ -1,7 +1,7 @@ -from re import L -from soupsieve import select +#from re import L +#from soupsieve import select -from src.cmp.cil import InstructionNode +#from src.cmp.cil import InstructionNode class MIPS_Node: @@ -13,16 +13,16 @@ def __init__(self, data, code): self.data = data self.text = code -class MIPSDataNode(MIPS_Node): +class DataNode(MIPS_Node): pass -class MIPSInstructionNode(MIPS_Node): +class InstructionNode(MIPS_Node): pass -class DataTransferNode(MIPSInstructionNode): +class DataTransferNode(InstructionNode): pass -class ProcedureNode(MIPSInstructionNode): +class ProcedureNode(InstructionNode): def __init__(self, label): self.label = label self.instructions = [] @@ -46,7 +46,7 @@ def __str__(self): class LoadNode(DataTransferNode): def __init__(self,dest,value): self.destination = dest - self.value + self.value = value class LoadInmediate(LoadNode): def __str__(self): @@ -65,10 +65,10 @@ def __str__(self): return f"move {self.destination} {self.source}" -class DataTypeNode(MIPSDataNode): - def __init__(self, name, datatype,vt_values): - self.name = name +class DataTypeNode(DataNode): + def __init__(self,datatype,name,vt_values): self.datatype = datatype + self.name = name self.vt_values = vt_values def __str__(self): @@ -77,7 +77,7 @@ def __str__(self): values += f", {value}" return f"{self.name} : {self.datatype}{values}" -class ArithAnfLogicNode(MIPSInstructionNode): +class ArithAnfLogicNode(InstructionNode): def __init__(self, destination,left,right): self.destination = destination self.left = left diff --git a/src/code_gen/mips_writer.py b/src/code_gen/mips_writer.py index d945879e5..3ce0a79aa 100644 --- a/src/code_gen/mips_writer.py +++ b/src/code_gen/mips_writer.py @@ -1,10 +1,36 @@ +#from cool.utils.config import * +#import cool.structs.mips_ast_hierarchy as mips +import code_gen.mips_nodes as mips import cmp.visitor as visitor +class MIPSWriter(object): + def __init__(self): + self.tabs = 0 + self.output = [] + + def emit(self, msg): + self.output.append(self.tabs*" " + msg) + + def black(self): + self.output.append('') + + def visit(self, node:mips.ProgramNode): + self.emit(".data") + self.black() + for data in node.dotdata: + self.emit(str(data)) + + self.black() + self.emit(".text") + self.emit(".globl main") + self.black() + for proc in node.dottext: + self.emit(f'{proc.label}:') + self.tabs += 4 + for inst in proc.instructions: + self.emit(str(inst)) + self.tabs -= 4 -from mips_nodes import ( - MIPSProgramNode, - MIPSDataTypeNode -) diff --git a/src/main.py b/src/main.py index ef7398446..8670ca575 100644 --- a/src/main.py +++ b/src/main.py @@ -14,6 +14,8 @@ from errors import InvalidInputFileError from cool_visitor import FormatVisitor from code_gen.cil_builder import CILBuilder +from code_gen.mips_builder import MIPSBuilder +from code_gen.mips_writer import MIPSWriter from cmp.cil import PrintVisitor import typer @@ -29,7 +31,7 @@ def report_and_exit(errors): def pipeline(input_file: Path, output_file: Path = None): errors = [] - + if not input_file.is_file: errors.append(InvalidInputFileError(str(input_file))) @@ -92,13 +94,10 @@ def pipeline(input_file: Path, output_file: Path = None): tree = formatter.visit(cil_ast) print(tree) - # if output_file is None: - # output_file = input.with_suffix(".mips") + if __name__ == "__main__": - # input_file = Path( - # "/home/amanda/Documents/Facultad/Compilacion/cool-compiler-2021/customized_tests/test_hello_world.cl" - # ) - # pipeline(input_file) + #input_file = Path("/home/sandra/Desktop/FinalProjects/Compiler/cool-compiler-2021/customized_tests/test_hello_world.cl") + #pipeline(input_file) typer.run(pipeline) From 5637a37919d51e9d7f0623edbb776ccdeead0c23 Mon Sep 17 00:00:00 2001 From: gabriela Date: Tue, 1 Mar 2022 23:42:57 -0500 Subject: [PATCH 074/162] Fix "not" precedence. Edit grammar so "not" nodes remains with less precedence than binary ones and are still considered in the right part of this ones. --- src/cool_grammar.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/cool_grammar.py b/src/cool_grammar.py index f866b60f8..35cb804f5 100644 --- a/src/cool_grammar.py +++ b/src/cool_grammar.py @@ -42,8 +42,8 @@ def define_cool_grammar(print_grammar=False): " " ) param_list, param_list_rest, param = G.NonTerminals(" ") - expr, comp, arith, term, factor, element, atom = G.NonTerminals( - " " + expr, not_exp, comp, arith, term, factor, element, atom = G.NonTerminals( + " " ) identifiers_list, identifier_init = G.NonTerminals(" ") block, case_block, case_item = G.NonTerminals(" ") @@ -104,9 +104,9 @@ def define_cool_grammar(print_grammar=False): expr %= idx + larrow + expr, lambda h, s: AssignNode(s[1], s[3], s[2]) expr %= let + identifiers_list + inx + expr, lambda h, s: LetNode(s[2], s[4], s[1]) + expr %= notx + comp, lambda h, s: NotNode(s[2], s[1]) expr %= comp, lambda h, s: s[1] - # igual, deberia considerarse registrar estos tokens identifiers_list %= ( identifier_init + comma + identifiers_list, lambda h, s: [s[1]] + s[3], @@ -120,11 +120,13 @@ def define_cool_grammar(print_grammar=False): identifier_init %= idx + colon + type_id, lambda h, s: VarDeclarationNode(s[1], s[3]) comp %= comp + less + arith, lambda h, s: LessNode(s[1], s[3], s[2]) + comp %= comp + less + notx + arith, lambda h, s: LessNode(s[1], NotNode(s[4], s[3]) , s[2]) comp %= comp + equal + arith, lambda h, s: EqualNode(s[1], s[3], s[2]) + comp %= comp + equal + notx + arith, lambda h, s: EqualNode(s[1], NotNode(s[4], s[3]) , s[2]) comp %= comp + lesseq + arith, lambda h, s: LessEqualNode(s[1], s[3], s[2]) + comp %= comp + lesseq + notx + arith, lambda h, s: LessEqualNode(s[1], NotNode(s[4], s[3]) , s[2]) comp %= arith, lambda h, s: s[1] - arith %= notx + term, lambda h, s: NotNode(s[2], s[1]) arith %= arith + plus + term, lambda h, s: PlusNode(s[1], s[3], s[2]) arith %= arith + minus + term, lambda h, s: MinusNode(s[1], s[3], s[2]) arith %= term, lambda h, s: s[1] From 8e12a89a24c48ec39f242cad4577f786a4cec680 Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Wed, 2 Mar 2022 16:32:28 -0500 Subject: [PATCH 075/162] fix: remove entry function --- src/code_gen/cil_builder.py | 40 +++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index b515ea871..78eb238f7 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -316,22 +316,22 @@ def visit(self, node): self.add_builtin_functions() # Add entry function and call Main.main() - self.current_function = FunctionNode("entry", [], [], []) - self.code.append(self.current_function) + # self.current_function = FunctionNode("entry", [], [], []) + # self.code.append(self.current_function) - instance = "l_instance" - self.register_instruction(LocalNode(instance)) + # instance = "l_instance" + # self.register_instruction(LocalNode(instance)) - result = "l_result" - self.register_instruction(LocalNode(result)) + # result = "l_result" + # self.register_instruction(LocalNode(result)) - main_method_name = self.to_function_name("Main", "main") - self.register_instruction(AllocateNode("Main", instance)) - self.register_instruction(ArgNode(instance)) - self.register_instruction(StaticCallNode(main_method_name, result)) - self.register_instruction(ReturnNode(0)) + # main_method_name = self.to_function_name("Main", "main") + # self.register_instruction(AllocateNode("Main", instance)) + # self.register_instruction(ArgNode(instance)) + # self.register_instruction(StaticCallNode(main_method_name, result)) + # self.register_instruction(ReturnNode(0)) - self.current_function = None + # self.current_function = None for declaration in node.declarations: self.visit(declaration) @@ -446,7 +446,14 @@ def visit(self, node): # TODO: Pending .id(,...,) # TODO: Pending @.id(,...,) - # function_name = self.to_function_name(node.id, self.current_type.name) + function_name = ( + self.to_function_name(node.id, self.current_type.name) + if not node.at_type + else self.to_function_name(node.id, node.at_type) + ) + + if node.obj: + self.visit(node.obj) for arg in node.args: temp = self.define_internal_local() @@ -454,13 +461,8 @@ def visit(self, node): self.register_instruction(AssignNode(temp, value)) self.register_instruction(ArgNode(temp)) - # if node.obj: - # obj_value = self.visit(node.obj) - # self.register_instruction() - - method_name = self.to_function_name(node.id, self.current_type.name) solve = self.define_internal_local() - self.register_instruction(StaticCallNode(method_name, solve)) + self.register_instruction(StaticCallNode(function_name, solve)) return solve From 291b9a1820b19db881d32e26076f5d78bdd7c462 Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Thu, 3 Mar 2022 16:14:52 -0500 Subject: [PATCH 076/162] fix: change InitNode to call type constructor --- src/code_gen/cil_builder.py | 62 +++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index 78eb238f7..e2c3e778e 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -87,11 +87,14 @@ def next_id(self): return str(self._count) def to_function_name(self, method_name, type_name): - return f"function_{method_name}_at_{type_name}" + return f"{type_name}_{method_name}" def to_data_name(self, type_name, value): return f"{type_name}_{value}" + def to_attr_name(self, type_name, attr_name): + return f"{type_name}_{attr_name}" + @property def params(self): return self.current_function.params @@ -118,7 +121,7 @@ def register_function(self, function_name): return function_node def register_local(self, vinfo): - vinfo.name = f"local_{self.current_function.name[9:]}_{vinfo.name}_{len(self.current_function.localvars)}" + vinfo.name = f"local_{self.current_function.name}_{vinfo.name}_{len(self.current_function.localvars)}" local_node = LocalNode(vinfo.name) self.current_function.localvars.append(local_node) return vinfo.name @@ -130,7 +133,7 @@ def register_param(self, vinfo): return vinfo def build_internal_vname(self, vname): - vname = f"{self.internal_count}_{self.current_function.name[9:]}_{vname}" + vname = f"{self.internal_count}_{self.current_function.name}_{vname}" self.internal_count += 1 return vname @@ -146,21 +149,36 @@ def register_data(self, name, value): def is_attribute(self, vname): return vname not in [var.name for var in self.current_function.localvars] + # def builtin_constructor(self): + # built = ["Object", "IO", "Int", "Bool", "String"] + # for c in built: + + # self.code.append(LabelIL(c, "Constructor", True)) + # self.code.append(PushIL()) # No result, but needed in logic + # self.code.append(ReturnIL()) + def build_constructor(self, node): + # self_var = self.define_internal_local() + # self.register_instruction(AllocateNode(node.id, self_var)) + attributeNodes = [ feat for feat in node.features if isinstance(feat, cool.AttrDeclarationNode) ] expr_list = [] for attr in attributeNodes: # Assign default value first - assign = cool.AssignNode(attr.id, cool.DefaultValueNode(attr.type)) + assign = cool.AssignNode( + self.to_attr_name(self.current_type.name, attr.id), + cool.DefaultValueNode(attr.type), + ) expr_list.append(assign) for attr in attributeNodes: # Assign init_expr if not None if attr.init_exp: - assign = cool.AssignNode(attr.id, attr.init_exp) + assign = cool.AssignNode( + self.to_attr_name(self.current_type.name, attr.id), attr.init_exp + ) expr_list.append(assign) - body = cool.BlockNode(expr_list) self.current_type.define_method("constructor", [], [], "Object") return cool.FuncDeclarationNode("constructor", [], "Object", body) @@ -315,23 +333,25 @@ def visit(self, node): self.add_builtin_functions() - # Add entry function and call Main.main() - # self.current_function = FunctionNode("entry", [], [], []) - # self.code.append(self.current_function) + self.current_function = FunctionNode("main", [], [], []) + self.code.append(self.current_function) - # instance = "l_instance" - # self.register_instruction(LocalNode(instance)) + instance = self.define_internal_local() + result = self.define_internal_local() + + main_constructor = self.to_function_name("constructor", "Main") + main_method_name = self.to_function_name("Main", "main") + + # Get instance from constructor + self.register_instruction(StaticCallNode(main_constructor, instance)) - # result = "l_result" - # self.register_instruction(LocalNode(result)) + # Pass instance as parameter and call Main_main + self.register_instruction(ArgNode(instance)) + self.register_instruction(StaticCallNode(main_method_name, result)) - # main_method_name = self.to_function_name("Main", "main") - # self.register_instruction(AllocateNode("Main", instance)) - # self.register_instruction(ArgNode(instance)) - # self.register_instruction(StaticCallNode(main_method_name, result)) - # self.register_instruction(ReturnNode(0)) + self.register_instruction(ReturnNode(0)) - # self.current_function = None + self.current_function = None for declaration in node.declarations: self.visit(declaration) @@ -625,7 +645,9 @@ def visit(self, node): @visitor.when(cool.InstantiateNode) # NewNode def visit(self, node): new_local = self.define_internal_local() - self.register_instruction(AllocateNode(node.lex, new_local)) + self.register_instruction( + StaticCallNode(self.to_function_name("constructor", node.lex), new_local) + ) return new_local From 07178ebfcd2ee5dac8adeb844c7accb7e04990ff Mon Sep 17 00:00:00 2001 From: gabriela Date: Thu, 3 Mar 2022 20:07:28 -0500 Subject: [PATCH 077/162] Fix details in type checker. Visit class dec in order with type checker. so a parent class's scope is defined before it's child. Return right exp type in assign operation. Start to correct errors reported in semantic visitors. --- src/cool_grammar.py | 2 +- src/cool_visitor.py | 5 ++-- src/type_checker.py | 58 ++++++++++++++++++++++++++++++++++----------- 3 files changed, 48 insertions(+), 17 deletions(-) diff --git a/src/cool_grammar.py b/src/cool_grammar.py index 35cb804f5..375564507 100644 --- a/src/cool_grammar.py +++ b/src/cool_grammar.py @@ -147,7 +147,7 @@ def define_cool_grammar(print_grammar=False): element %= case + expr + of + case_block + esac, lambda h, s: CaseNode(s[2], s[4], s[1]) element %= new + type_id, lambda h, s: InstantiateNode(s[2], s[1]) element %= opar + expr + cpar, lambda h, s: s[2] - element %= ocur + block + ccur, lambda h, s: BlockNode(s[2]) + element %= ocur + block + ccur, lambda h, s: BlockNode(s[2], s[1]) element %= (element + dot + func_call, lambda h, s: CallNode(*s[3], obj=s[1], token = s[2]))#arreglar element %= ( element + at + type_id + dot + func_call, diff --git a/src/cool_visitor.py b/src/cool_visitor.py index 6c4ccb580..676e9290f 100644 --- a/src/cool_visitor.py +++ b/src/cool_visitor.py @@ -245,7 +245,8 @@ def visit(self, node, tabs=0): @visitor.when(FuncDeclarationNode) def visit(self, node, tabs=0): - params = ", ".join(":".join(param) for param in node.params) + # params = ", ".join(":".join(param) for param in node.params) + params = ", ".join(":".join(param_name.lex).join(param_type.lex) for param_name, param_type in node.params) ans = ( "\\__\\__" * tabs + f"\\__FuncDeclarationNode: {node.id}({params}) : {node.type} {{ }}" @@ -519,7 +520,7 @@ def visit(self, node): @visitor.when(NotNode) def visit(self, node): expr = self.visit(node.expr) - return NotNode(exp, node.token) + return NotNode(expr, node.token) @visitor.when(IsvoidNode) def visit(self, node): diff --git a/src/type_checker.py b/src/type_checker.py index a07f5d601..fb6a56f02 100644 --- a/src/type_checker.py +++ b/src/type_checker.py @@ -41,7 +41,7 @@ from cmp.semantic import Scope from cmp.utils import find_least_type import copy -from errors import TypeError +from errors import TypeError, NameError WRONG_SIGNATURE = 'Method "%s" already defined in "%s" with a different signature.' SELF_IS_READONLY = 'Variable "self" is read-only.' @@ -66,8 +66,26 @@ def visit(self, node, scope=None): def visit(self, node): scope = Scope() self.context = copy.copy(node.context) + + #visit class in order + parent_children_dict = {} + initial_nodes = [] + visited = {} for declaration in node.declarations: - self.visit(declaration, scope.create_child()) + try: + visited[declaration.id] # checking is visited + except: + visited[declaration.id] = True + if declaration.parent is None or declaration.parent.lex in ["IO", "Int", "String", "Bool"]: # is node has no parent, mark it to visit it first later + initial_nodes.append(declaration) + else: + try: + parent_children_dict[declaration.parent.lex].append(declaration) + except: + parent_children_dict[declaration.parent.lex] = [declaration] + + for declaration in initial_nodes: + self.visit(declaration, scope.create_child(), parent_children_dict) self.context = None self.current_type = None @@ -76,7 +94,7 @@ def visit(self, node): return scope @visitor.when(ClassDeclarationNode) - def visit(self, node, scope): + def visit(self, node, scope, parent_children_dict): self.current_type = self.context.get_type(node.id) scope.define_variable("self", self.current_type) @@ -85,6 +103,13 @@ def visit(self, node, scope): for feature in node.features: self.visit(feature, scope) + + try: + children = parent_children_dict[node.id] + for child in children: + self.visit(child, scope.create_child(), parent_children_dict) + except: + return @visitor.when(AttrDeclarationNode) def visit(self, node, scope): @@ -98,10 +123,13 @@ def visit(self, node, scope): if typex.name == "SELF_TYPE": typex = self.current_type + if node.init_exp != None: init_expr_type = self.visit(node.init_exp, scope) + if not init_expr_type.conforms_to(typex): - self.errors.append(INCOMPATIBLE_TYPES % (init_expr_type, typex)) + line, col = node.token.location + self.errors.append(TypeError(line, col,INCOMPATIBLE_TYPES % (init_expr_type.name, typex.name))) return typex @@ -137,10 +165,9 @@ def visit(self, node, scope): body_type = self.visit(node.body, child_scope) - if not body_type.conforms_to(method_return_type): - self.errors.append( - INCOMPATIBLE_TYPES % (body_type.name, method_return_type.name) - ) + if not body_type.conforms_to(method_return_type):#aqui se debe poner + node_row, node_col = node.body.token.location + self.errors.append(TypeError( node_row, node_col, INCOMPATIBLE_TYPES % (body_type.name, method_return_type.name))) if self.current_type.parent is not None: try: @@ -194,7 +221,6 @@ def visit(self, node, scope): def visit(self, node, scope): if node.id.lex == "self": self.errors.append(SELF_IS_READONLY) - var_type = None if not scope.is_defined(node.id.lex): self.errors.append( @@ -208,7 +234,7 @@ def visit(self, node, scope): if not expr_type.conforms_to(var_type): self.errors.append(INCOMPATIBLE_TYPES % (expr_type.name, var_type.name)) - return var_type + return expr_type @visitor.when(CallNode) def visit(self, node, scope): @@ -388,7 +414,8 @@ def visit(self, node, scope): if (left_type != int_type and left_type.name != "AUTO_TYPE") or ( right_type != int_type and right_type.name != "AUTO_TYPE" ): - self.errors.append(INVALID_OPERATION % (left_type.name, right_type.name)) + node_row, node_col = node.token.location + self.errors.append(TypeError( node_row, node_col, INVALID_OPERATION % (left_type.name, right_type.name))) return self.context.get_type("Bool") @@ -420,8 +447,9 @@ def visit(self, node, scope): typex = self.visit(node.expr, scope) if typex != bool_type and not typex.name == "AUTO_TYPE": + line, col = node.token.location self.errors.append( - f"Expression after 'not' must be Bool, current is {typex.name}" + TypeError(line, col, f"Expression after 'not' must be Bool, current is {typex.name}") ) return ErrorType() @@ -433,8 +461,9 @@ def visit(self, node, scope): typex = self.visit(node.expr, scope) if typex != int_type and not typex.name == "AUTO_TYPE": + node_row, node_col = node.token.location self.errors.append( - f"Expression after '~' must be Int, current is {typex.name}" + TypeError( node_row, node_col,f"Expression after '~' must be Int, current is {typex.name}") ) return ErrorType() @@ -448,8 +477,9 @@ def visit(self, node, scope): def visit(self, node, scope): var = scope.find_variable(node.lex) if var is None: + node_row, node_col = node.token.location self.errors.append( - VARIABLE_NOT_DEFINED % (node.lex, self.current_method.name) + NameError( node_row, node_col,VARIABLE_NOT_DEFINED % (node.lex, self.current_method.name)) ) return ErrorType() return var.type From fa34d1391e9b1fd6f13f446112088c256e903c5f Mon Sep 17 00:00:00 2001 From: gabriela Date: Fri, 4 Mar 2022 01:01:03 -0500 Subject: [PATCH 078/162] Continue with type checker testing. Detect and report redefinition of classes. Detect idem branches in case expression. --- src/ast_nodes.py | 7 +++-- src/cmp/semantic.py | 14 +++++++++- src/cool_grammar.py | 2 +- src/type_builder.py | 21 ++++++++------- src/type_checker.py | 63 +++++++++++++++++++++++++++---------------- src/type_collector.py | 9 ++++--- 6 files changed, 75 insertions(+), 41 deletions(-) diff --git a/src/ast_nodes.py b/src/ast_nodes.py index f38e67506..3f093c6bb 100644 --- a/src/ast_nodes.py +++ b/src/ast_nodes.py @@ -96,12 +96,15 @@ def __init__(self, idx, typex, exp, token): class CallNode(ExpressionNode): - def __init__(self, idx, args, obj=None, at_type=None, token = Token("", "", (0,0))): + def __init__(self, idx, args, obj=None, at_type=None, token = Token("", "", (-1,-1))): self.obj = obj self.id = idx self.args = args self.at_type = at_type - self.token = token + if token.location[0] == -1: + self.token = idx + else: + self.token = token class BlockNode(ExpressionNode): diff --git a/src/cmp/semantic.py b/src/cmp/semantic.py index b4f6424c0..4eccf31ef 100644 --- a/src/cmp/semantic.py +++ b/src/cmp/semantic.py @@ -235,7 +235,7 @@ def __init__(self): def create_type(self, name: str): if name in self.types: - raise SemanticError(f"Type with the same name ({name}) already in context.") + raise SemanticError(f"Type with the same name {name} already in context.") typex = self.types[name] = Type(name) return typex @@ -267,6 +267,9 @@ def __init__(self, name, vtype): self.name = name self.type = vtype + def __str__(self): + return f"{self.name}: {self.type}" + class Scope: def __init__(self, parent=None): @@ -302,3 +305,12 @@ def is_defined(self, vname): def is_local(self, vname): return any(True for x in self.locals if x.name == vname) + + def __str__(self): + output = "LOCALS: \n" + output += "\n".join(str(x) for x in self.locals) + output += "\n" + output += "PARENT:" + output += str(self.parent) + output += "\n" + return output \ No newline at end of file diff --git a/src/cool_grammar.py b/src/cool_grammar.py index 375564507..b2b767476 100644 --- a/src/cool_grammar.py +++ b/src/cool_grammar.py @@ -160,7 +160,7 @@ def define_cool_grammar(print_grammar=False): case_block %= case_item, lambda h, s: [s[1]] case_item %= ( idx + colon + type_id + rarrow + expr + semi, - lambda h, s: CaseItemNode(s[1], s[3], s[5]), + lambda h, s: CaseItemNode(s[1], s[3], s[5], s[4]), ) atom %= num, lambda h, s: ConstantNumNode(s[1]) diff --git a/src/type_builder.py b/src/type_builder.py index 719ae50da..525e25716 100644 --- a/src/type_builder.py +++ b/src/type_builder.py @@ -1,5 +1,5 @@ import copy -from cmp.semantic import SemanticError +from cmp.semantic import SemanticError as SError from cmp.semantic import Attribute, Method, Type from cmp.semantic import VoidType, IntType, ErrorType, StringType, BoolType from cmp.semantic import Context @@ -13,7 +13,7 @@ from tset import Tset from collections import deque from cool_visitor import CopyVisitor - +from errors import SemanticError class TypeBuilder: def __init__(self, errors=[]): @@ -109,7 +109,7 @@ def visit(self, node): parent_child_dict[parent_type].append(class_declaration) except: # KeyError parent_child_dict[parent_type] = [class_declaration] - except SemanticError: # parent is None or not definition provided + except SError: # parent is None or not definition provided queue.append(class_declaration) main_round = 0 @@ -147,7 +147,7 @@ def visit(self, node): '"main" method in class Main does not receive any parameters' ) # modify in semantic get_method in order to get some ancestor where the method is already defined - except SemanticError: + except SError: self.errors.append("A class Main with a method main most be provided") # ---------------------------------------------------- @@ -174,13 +174,14 @@ def visit(self, node): try: parent_type = self.get_type(node.parent.lex) self.current_type.set_parent(parent_type) - except SemanticError as error: - self.errors.append(error.text) + except SError as error: + node_row, node_col = node.parent.location + self.errors.append(SemanticError(node_row, node_col, error.text)) else: object_type = self.context.get_type("Object") try: self.current_type.set_parent(object_type) - except SemanticError as error: + except SError as error: self.errors.append(error.text) for feature in node.features: @@ -196,7 +197,7 @@ def visit(self, node): self.current_type.define_method( node.id.lex, param_names, param_types, return_type ) - except SemanticError as error: + except SError as error: # print("--------aqui se esta reportando el error del metodo doble---------") self.errors.append(error.text) @@ -205,12 +206,12 @@ def visit(self, node): try: attr_type = self.get_type(node.type.lex) self.current_type.define_attribute(node.id.lex, attr_type) - except SemanticError as error: + except SError as error: self.errors.append(error.text) def get_type(self, tname): try: return self.context.get_type(tname) - except SemanticError as error: + except SError as error: self.errors.append(error.text) return ErrorType() diff --git a/src/type_checker.py b/src/type_checker.py index fb6a56f02..bf58c9d7c 100644 --- a/src/type_checker.py +++ b/src/type_checker.py @@ -1,3 +1,4 @@ +from email import message import cmp.nbpackage import cmp.visitor as visitor @@ -33,7 +34,7 @@ ) from cool_visitor import FormatVisitor -from cmp.semantic import SemanticError +from cmp.semantic import SemanticError as SError from cmp.semantic import Attribute, Method, Type from cmp.semantic import VoidType, ErrorType, IntType from cmp.semantic import Context @@ -41,7 +42,7 @@ from cmp.semantic import Scope from cmp.utils import find_least_type import copy -from errors import TypeError, NameError +from errors import TypeError, NameError, SemanticError, AttributeError WRONG_SIGNATURE = 'Method "%s" already defined in "%s" with a different signature.' SELF_IS_READONLY = 'Variable "self" is read-only.' @@ -116,7 +117,7 @@ def visit(self, node, scope): try: typex = self.context.get_type(node.type.lex) - except SemanticError as e: + except SError as e: self.errors.append(e) return ErrorType() @@ -182,7 +183,7 @@ def visit(self, node, scope): f"an ancestor of {self.current_type.name}", ) ) - except SemanticError: + except SError: pass try: @@ -192,7 +193,7 @@ def visit(self, node, scope): return return_type - except SemanticError as e: + except SError as e: self.errors.append(e) return ErrorType() @@ -206,7 +207,7 @@ def visit(self, node, scope): self.errors.append(SELF_IS_READONLY) try: static_type = self.context.get_type(node.type.lex) - except SemanticError as error: + except SError as error: self.errors.append(error.text) static_type = ErrorType() @@ -254,25 +255,29 @@ def visit(self, node, scope): node_at_type = self.context.get_type(node.at_type.lex) method = node_at_type.get_method(node.id.lex) if not typex.conforms_to(node_at_type): + node_row, node_col = node.token.location self.errors.append( - f"The static type to the left of @ ({typex.name}) must conform to the type specified to the right of @ ({node_at_type.name}) " + TypeError(node_row, node_col, f"Expression type {typex.name} does not conform to declared static dispatch type {node_at_type.name}.") ) return ErrorType() else: method = typex.get_method(node.id.lex) - except SemanticError as error: - self.errors.append(error.text) + except SError as error: + node_col, node_row = node.token.location + self.errors.append(AttributeError(node_col, node_row ,error.text)) return ErrorType() if len(method.param_names) != len(node.args): + node_row, node_col = node.id.location self.errors.append( - f"There is no definition of {method.name} that takes {len(node.args)} arguments " + SemanticError(node_row, node_col, f"There is no definition of {method.name} that takes {len(node.args)} arguments ") ) for arg, ptype in zip(node.args, method.param_types): arg_type = self.visit(arg, scope) if not arg_type.conforms_to(ptype): - self.errors.append(INCOMPATIBLE_TYPES % (arg_type.name, ptype.name)) + node_row, node_col = arg.token.location # verificar si esto siempre da ok + self.errors.append(TypeError(node_row, node_col,f"In call of method {node.id.lex} parameter of type {arg_type.name} does not conforms to declared type {ptype.name}")) if method.return_type == self.context.get_type("SELF_TYPE"): return typex @@ -284,8 +289,9 @@ def visit(self, node, scope): predicate_type = self.visit(node.if_expr, scope) if predicate_type.name != "Bool" and predicate_type.name != "AUTO_TYPE": + node_row, node_col = node.token.location self.errors.append( - f"Expression after 'if' must be bool, current is {predicate_type.name}" + TypeError(node_row, node_col, f"Expression after 'if' must be Bool, current type is {predicate_type.name}") ) return ErrorType() @@ -336,7 +342,7 @@ def visit(self, node, scope): static_type = self.current_type scope.define_variable(node.id, static_type) - except SemanticError as e: + except SError as e: self.errors.append(e) return ErrorType() @@ -352,12 +358,19 @@ def visit(self, node, scope): self.visit(node.expr, scope) current_case_type = None + case_types_found = [] for item in node.case_items: - child_scope = scope.create_child() - case_item_type = self.visit(item, child_scope) - current_case_type = find_least_type( - current_case_type, case_item_type, self.context - ) + if not ( item.type.lex in case_types_found): + case_types_found.append(item.type.lex) + child_scope = scope.create_child() + case_item_type = self.visit(item, child_scope) + current_case_type = find_least_type( + current_case_type, case_item_type, self.context + ) + else: + line, col = item.type.location + self.errors.append(SemanticError(line, col, f"Duplicate branch {item.type.lex} in case statement")) + return current_case_type @@ -365,10 +378,14 @@ def visit(self, node, scope): def visit(self, node, scope): try: static_type = self.context.get_type(node.type.lex) - scope.define_variable(node.id.lex, static_type) - except SemanticError as e: - self.errors.append(e) - return ErrorType() + try: + scope.define_variable(node.id.lex, static_type) + except SError as e: + self.errors.append(e) + return ErrorType() + except SError as e: + node_row, node_col = node.type.location + self.errors.append(TypeError(node_row, node_col, f"Class {node.type.lex} of case branch is undefined.")) typex = self.visit(node.expr, scope) @@ -382,7 +399,7 @@ def visit(self, node, scope): return self.current_type return typex - except SemanticError as error: + except SError as error: self.errors.append(error.text) return ErrorType() diff --git a/src/type_collector.py b/src/type_collector.py index 2f5dfc503..c5837c1c3 100644 --- a/src/type_collector.py +++ b/src/type_collector.py @@ -1,4 +1,4 @@ -from cmp.semantic import SemanticError +from cmp.semantic import SemanticError as SError from cmp.semantic import Attribute, Method, Type from cmp.semantic import ( VoidType, @@ -15,7 +15,7 @@ from ast_nodes import ProgramNode, ClassDeclarationNode import cmp.visitor as visitor from cool_visitor import CopyVisitor - +from errors import SemanticError class TypeCollector(object): def __init__(self, errors=[]): @@ -61,5 +61,6 @@ def visit(self, node): def visit(self, node): try: self.context.create_type(node.id) - except SemanticError as error: - self.errors.append(error.text) + except SError as error: + node_row, node_col = node.token.location + self.errors.append(SemanticError(node_row, node_col, error.text)) From ed7e678277c1d58ec95f8a497775ec8b932446e6 Mon Sep 17 00:00:00 2001 From: smartos99 Date: Fri, 4 Mar 2022 17:13:31 -0500 Subject: [PATCH 079/162] Accept changes from dev --- customized_tests/test_hello_world.cl | 9 +- src/code_gen/mips_builder.py | 202 +++++++++++++++++++++++++-- src/code_gen/mips_nodes.py | 30 ++++ src/main.py | 18 ++- 4 files changed, 238 insertions(+), 21 deletions(-) diff --git a/customized_tests/test_hello_world.cl b/customized_tests/test_hello_world.cl index 0565e3093..84701ff26 100644 --- a/customized_tests/test_hello_world.cl +++ b/customized_tests/test_hello_world.cl @@ -1,4 +1,4 @@ -(* class Main inherits IO { +class Main inherits IO { msg : String <- "Hello World"; main() : IO{ @@ -6,9 +6,9 @@ }; }; -*) - class Main { + +(* class Main { main (): Object { 0 }; @@ -23,4 +23,5 @@ class Point { y <- y0; self; } }; -}; \ No newline at end of file +}; +*) \ No newline at end of file diff --git a/src/code_gen/mips_builder.py b/src/code_gen/mips_builder.py index 211d41e7e..72d16d6be 100644 --- a/src/code_gen/mips_builder.py +++ b/src/code_gen/mips_builder.py @@ -1,6 +1,8 @@ #from atexit import register #from email.quoprimime import body_length import enum +from ssl import ALERT_DESCRIPTION_BAD_CERTIFICATE_HASH_VALUE +from turtle import left #from operator import le #from tkinter.tix import Select from attr import attr @@ -20,6 +22,10 @@ RA_OFFSET = 8 OLD_FP_OFFSET = 4 +#str attributes offsets +LENGTH_ATTR_OFFSET = 4 +CHARS_ATTR_OFFSET = 8 + FP_ARGS_DISTANCE = 3 # how far finishes $fp from arguments in method call FP_LOCALS_DISTANCE = 0 # how far finishes $fp from localvars in method call @@ -30,6 +36,10 @@ ZERO_DIVISION = "division_by_zero"#MIPS SUBSTR_OUT_RANGE = "substr_out_of_range"#MIPS HEAP_OVERFLOW = "heap_overflow" +STRING_SIZE = 12 +VOID = "void" +STR_CMP = "string_comparer" +EMPTY_STRING = "empty_string" #temporary registers t0 = "$t0" @@ -71,6 +81,13 @@ SYSCALL_SBRK = 9 SYSCALL_EXIT = 10 +SELF_TYPE = "SELF_TYPE" +INT = "Int" +BOOL = "Bool" +STRING = "String" +OBJECT = "Object" +IO = "IO" + class MemoryManager: def __init__(self): self.all_reg = [t0,t1,t2,t3,t4,t5,t6,t7,t8,t9] @@ -97,6 +114,7 @@ def __init__(self): self.mips_code = "" self.main_procedure = mips.ProcedureNode("main") self.current_procedure = self.main_procedure + self.main_size = 0 self.text = [self.main_procedure] self.data = [] self.params = [] @@ -112,7 +130,7 @@ def get_offset(self,x): return -4*index elif x in self.params: index = self.params.index(x) - return (-4 * (len(self.locals)+len(self.params)))-4 + return (-4 * (len(self.locals)+len(self.params)))+4 def register_instruction(self, instruction_type, *args): instruction = instruction_type(*args) @@ -140,12 +158,28 @@ def generate_exception_messages(self): self.register_data(mips.DataTypeNode, SUBSTR_OUT_RANGE, '.asciiz', ['"Substring out of range"']) self.register_data(mips.DataTypeNode, HEAP_OVERFLOW, '.asciiz', ['"Heap overflow"']) + def generate_attr_offset(self,type): attributes = self.types[type].attributes self.attr_offset[type]={} for i,attr in enumerate(attributes): self.attr_offset[type][attr] = 4*(i+1) + #def register_main_allocation(self): + # self.register_instruction(mips.CommentNode,"Allocating Main instance") + # self.register_instruction(mips.MoveNode,fp,sp) + # self.register_instruction(mips.AddiNode,sp,sp,-4) + # + # self.register_instruction(mips.CommentNode,"Allocating Main instance") + # #Allocate + # self.register_instruction(mips.LoadInmediate,v0,SYSCALL_SBRK) + # self.register_instruction(mips.LoadInmediate,a0,self.main_size) + # self.register_instruction(mips.SyscallNode) + # self.register_instruction(mips.StoreWordNode,v0,0,fp) + # + # self.register_instruction(mips.CommentNode,"Calling Main Constructor") + # self.register_push(fp) + # self.register_instruction(mips.JumpAndLink,"Main_constructor") @visitor.on("node") @@ -173,8 +207,9 @@ def visit(self, node): @visitor.when(cil.TypeNode) def visit(self, node): - self.types[node.name] = node + if node.name == "Main": + self.main_size = (len(node.attributes)+1)*4 values = [] for func in node.methods: values.append(func[1]) @@ -214,6 +249,7 @@ def visit(self,node): self.memo.clean() + @visitor.when(cil.ArgNode) def visit(self,node): self.memo.save() @@ -229,6 +265,10 @@ def visit(self,node): @visitor.when(cil.FunctionNode) def visit(self,node): + + locals_save = self.locals + params_save = self.params + self.locals, self.params = [], [] self.current_procedure = mips.ProcedureNode(node.name) self.register_instruction(mips.CommentNode,"Pushing $ra") @@ -244,6 +284,9 @@ def visit(self,node): for local in node.localvars: self.locals.append(local.name) + + for param in node.params: + self.params.append(param.name) self.register_instruction(mips.CommentNode,"Executing instructions") for inst in node.instructions: @@ -257,8 +300,6 @@ def visit(self,node): self.register_instruction(mips.CommentNode,"Restoring saved $fp") self.register_instruction(mips.LoadWordNode, fp, OLD_FP_OFFSET, fp)#stored (old)$fp - - #Cual de las dos???? AR = 4*(len(node.localvars) + len(node.params) + 2) #AR = 4*(len(node.localvars) + 2) @@ -268,7 +309,9 @@ def visit(self,node): self.register_instruction(mips.CommentNode,"Return jump") self.register_instruction(mips.JumpRegister, ra) - self.text.append(self.current_procedure) + self.text.append(self.current_procedure) + self.locals = locals_save + self.params = params_save @visitor.when(cil.LoadNode) @@ -288,9 +331,12 @@ def visit(self,node): #All return value is saved in register a1 @visitor.when(cil.ReturnNode) - def visit(self,node): - offset = self.get_offset(node.value) - self.register_instruction(mips.LoadWordNode,a1,offset,fp) + def visit(self,node): + if isinstance(node.value,int): + self.register_instruction(mips.LoadInmediate,a1,node.value) + else: + offset = self.get_offset(node.value) + self.register_instruction(mips.LoadWordNode,a1,offset,fp) @visitor.when(cil.GotoNode) def visit(self,node): @@ -312,8 +358,6 @@ def visit(self,node): reg = self.memo.get_unused_reg() self.register_instruction(mips.LoadAddress,reg,node.type) self.register_instruction(mips.StoreWordNode,reg,0,v0) - - self.memo.clean() @visitor.when(cil.AssignNode) @@ -331,8 +375,6 @@ def visit(self,node): self.memo.clean() - - @visitor.when(cil.PlusNode) def visit(self,node): @@ -391,6 +433,36 @@ def visit(self,node): dest_offset = self.get_offset(node.dest) self.register_instruction(mips.StoreWordNode,a1,dest_offset,fp) + + @visitor.when(cil.DynamicCallNode) + def visit(self,node): + self.memo.save() + + reg1 = self.memo.get_unused_reg() + reg2 = self.memo.get_unused_reg() + + instance_offset = self.get_offset(node.instance) + self.register_instruction(mips.CommentNode,"Getting type of instance") + self.register_instruction(mips.LoadWordNode,reg1,instance_offset,fp) + + #getting method offset + _methods = self.types[node.type].methods + meth_offset = _methods.index(node.method) + self.register_instruction(mips.LoadWordNode,reg2,meth_offset*4,reg1) + + self.register_instruction(mips.JumpAndLink,reg2) + + #putting the return vslue in destination + dest_offset = self.get_offset(node.dest) + self.register_instruction(mips.StoreWordNode,a1,dest_offset,fp) + + self.memo.clean() + + + + + + @visitor.when(cil.GetAttribNode) def visit(self, node): self.memo.save() @@ -398,7 +470,7 @@ def visit(self, node): reg1 = self.memo.get_unused_reg() reg2 = self.memo.get_unused_reg() - instance_offset = self.get_offset(node.type) + instance_offset = self.get_offset(node.instance) self.register_instruction(mips.LoadWordNode,reg1,instance_offset,fp) attr_offs = self.attr_offset[node.type][node.attr] @@ -414,7 +486,7 @@ def visit(self, node): reg1 = self.memo.get_unused_reg() reg2 = self.memo.get_unused_reg() - instance_offset = self.get_offset(node.type) + instance_offset = self.get_offset(node.instance) self.register_instruction(mips.LoadWordNode,reg1,instance_offset,fp) value_offset = self.get_offset(node.value) @@ -424,6 +496,108 @@ def visit(self, node): self.register_instruction(mips.StoreWordNode,reg2,attr_os,reg1) self.memo.clean() + + @visitor.when(cil.DefaultValueNode) + def visit(self,node): + self.memo.save() + reg = self.memo.get_unused_reg() + dest_offset = self.get_offset(node.dest) + if node.type in [INT,BOOL]: + self.register_instruction(mips.LoadInmediate,reg,0) + self.register_instruction(mips.StoreWordNode,reg,dest_offset,fp) + elif node.type == STRING: + self.register_instruction(mips.LoadInmediate,reg,0) + self.register_instruction(mips.StoreWordNode, reg, LENGTH_ATTR_OFFSET, v0) #pq en vo esta el allocate + self.register_instruction(mips.LoadAddress, reg, EMPTY_STRING) + self.register_instruction(mips.StoreWordNode, reg, CHARS_ATTR_OFFSET, v0) + else: + self.register_instruction(mips.LoadAddress, reg, VOID) + self.register_instruction(mips.StoreWordNode, reg, dest_offset, fp) + + self.memo.clean() + + + @visitor.when(cil.PlusNode) + def visit(self,node): + self.memo.save() + reg_l = self.memo.get_unused_reg() + reg_r = self.memo.get_unused_reg() + reg_dest = self.memo.get_unused_reg() + + left_offset = self.get_offset(node.left) + right_offset = self.get_offset(node.right) + + self.register_instruction(mips.LoadWordNode,reg_l,left_offset,fp) + self.register_instruction(mips.LoadWordNode,reg_r,right_offset,fp) + + self.register_instruction(mips.AddNode,reg_dest,reg_l,reg_r) + + offset = self.get_offset(node.dest) + self.register_instruction(mips.StoreWordNode,reg_dest,offset,fp) + + self.memo.clean() + + @visitor.when(cil.MinusNode) + def visit(self,node): + self.memo.save() + reg_l = self.memo.get_unused_reg() + reg_r = self.memo.get_unused_reg() + reg_dest = self.memo.get_unused_reg() + + left_offset = self.get_offset(node.left) + right_offset = self.get_offset(node.right) + + self.register_instruction(mips.LoadWordNode,reg_l,left_offset,fp) + self.register_instruction(mips.LoadWordNode,reg_r,right_offset,fp) + + self.register_instruction(mips.SubNode,reg_dest,reg_l,reg_r) + + offset = self.get_offset(node.dest) + self.register_instruction(mips.StoreWordNode,reg_dest,offset,fp) + + self.memo.clean() + + @visitor.when(cil.StarNode) + def visit(self,node): + self.memo.save() + reg1 = self.memo.get_unused_reg() + reg2 = self.memo.get_unused_reg() + + + left_offset = self.get_offset(node.left) + right_offset = self.get_offset(node.right) + + self.register_instruction(mips.LoadWordNode,reg1,left_offset,fp) + self.register_instruction(mips.LoadWordNode,reg2,right_offset,fp) + + self.register_instruction(mips.MultNode,reg1,reg2) + + dest_offset = self.get_offset(node.dest) + self.register_instruction(mips.MoveFromHi,reg1) + self.register_instruction(mips.StoreWordNode,reg1,dest_offset,fp) + + self.memo.clean() + + @visitor.when(cil.DivNode) + def visit(self,node): + self.memo.save() + reg1 = self.memo.get_unused_reg() + reg2 = self.memo.get_unused_reg() + + + left_offset = self.get_offset(node.left) + right_offset = self.get_offset(node.right) + + self.register_instruction(mips.LoadWordNode,reg1,left_offset,fp) + self.register_instruction(mips.LoadWordNode,reg2,right_offset,fp) + + self.register_instruction(mips.DivideNode,reg1,reg2) + + dest_offset = self.get_offset(node.dest) + self.register_instruction(mips.MoveFromLo,reg1) + self.register_instruction(mips.StoreWordNode,reg1,dest_offset,fp) + + self.memo.clean() #PENDIENTEEEEEEEE diff --git a/src/code_gen/mips_nodes.py b/src/code_gen/mips_nodes.py index 3d7dd0cfc..9a9195d76 100644 --- a/src/code_gen/mips_nodes.py +++ b/src/code_gen/mips_nodes.py @@ -4,6 +4,9 @@ #from src.cmp.cil import InstructionNode +from matplotlib.pyplot import cla + + class MIPS_Node: pass @@ -94,7 +97,34 @@ def __str__(self): class SubNode(ArithAnfLogicNode): def __str__(self): return f"sub {self.destination}, {self.left}, {self.right}" + +class HiLoOperationNode(InstructionNode): + def __init__(self,left,right): + self.left = left + self.right = right +class MultNode(HiLoOperationNode): + def __str__(self): + return f'mult {self.left}, {self.right}' + +class DivideNode(HiLoOperationNode): + def __str__(self): + return f'div {self.left}, {self.right}' + +class MoveFromHi(InstructionNode): + def __init__(self,register): + self.register = register + + def __str__(self): + return f'mfhi {self.register}' + +class MoveFromLo(InstructionNode): + def __init__(self,register): + self.register = register + + def __str__(self): + return f'mflo {self.register}' + class ConditionalBranch(InstructionNode): def __init__(self,c1,c2,jump): self.c1 = c1 diff --git a/src/main.py b/src/main.py index 8670ca575..b89a04e81 100644 --- a/src/main.py +++ b/src/main.py @@ -93,11 +93,23 @@ def pipeline(input_file: Path, output_file: Path = None): formatter = PrintVisitor() tree = formatter.visit(cil_ast) print(tree) + + cil_to_mips_visitor = MIPSBuilder() + mips_ast = cil_to_mips_visitor.visit(cil_ast) + + mips_writer = MIPSWriter() + output = mips_writer(mips_ast) + + output = '\n'.join(mips_writer.output) + if output_file is None: + output_file = input.with_suffix(".mips") + output_file.write_text(output) + if __name__ == "__main__": - #input_file = Path("/home/sandra/Desktop/FinalProjects/Compiler/cool-compiler-2021/customized_tests/test_hello_world.cl") - #pipeline(input_file) - typer.run(pipeline) + input_file = Path("/home/sandra/Desktop/FinalProjects/Compiler/cool-compiler-2021/customized_tests/test_hello_world.cl") + pipeline(input_file) + #typer.run(pipeline) From 54d88b67977007576b9d1118cc3dd6f816abac2c Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Fri, 4 Mar 2022 22:59:27 -0500 Subject: [PATCH 080/162] feat: allocate returns self --- src/code_gen/cil_builder.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index e2c3e778e..c15c33ec2 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -158,9 +158,6 @@ def is_attribute(self, vname): # self.code.append(ReturnIL()) def build_constructor(self, node): - # self_var = self.define_internal_local() - # self.register_instruction(AllocateNode(node.id, self_var)) - attributeNodes = [ feat for feat in node.features if isinstance(feat, cool.AttrDeclarationNode) ] @@ -179,6 +176,7 @@ def build_constructor(self, node): self.to_attr_name(self.current_type.name, attr.id), attr.init_exp ) expr_list.append(assign) + body = cool.BlockNode(expr_list) self.current_type.define_method("constructor", [], [], "Object") return cool.FuncDeclarationNode("constructor", [], "Object", body) @@ -342,8 +340,11 @@ def visit(self, node): main_constructor = self.to_function_name("constructor", "Main") main_method_name = self.to_function_name("Main", "main") - # Get instance from constructor - self.register_instruction(StaticCallNode(main_constructor, instance)) + # Get instance from allocate + self.register_instruction(AllocateNode("Main", instance)) + self.register_instruction( + StaticCallNode(main_constructor, self.define_internal_local()) + ) # Pass instance as parameter and call Main_main self.register_instruction(ArgNode(instance)) @@ -644,12 +645,14 @@ def visit(self, node): # Unary operators @visitor.when(cool.InstantiateNode) # NewNode def visit(self, node): - new_local = self.define_internal_local() + instance = self.define_internal_local() + solve = self.define_internal_local() + self.register_instruction(AllocateNode(node.lex, instance)) self.register_instruction( - StaticCallNode(self.to_function_name("constructor", node.lex), new_local) + StaticCallNode(self.to_function_name("constructor", node.lex), solve) ) - return new_local + return solve @visitor.when(cool.IsvoidNode) def visit(self, node): From dba699abbe4c5cbd3d3ba58ff91ae62b0bb276e7 Mon Sep 17 00:00:00 2001 From: gabriela Date: Sat, 5 Mar 2022 12:42:43 -0500 Subject: [PATCH 081/162] Fix tokenizer error of taking strings as keywords. --- src/lexical_analizer.py | 31 ++++++++++++--------- src/tokens_rules.py | 62 ++++++++++++++++++++--------------------- src/type_checker.py | 3 +- 3 files changed, 50 insertions(+), 46 deletions(-) diff --git a/src/lexical_analizer.py b/src/lexical_analizer.py index 243d843be..0ce8d40c1 100644 --- a/src/lexical_analizer.py +++ b/src/lexical_analizer.py @@ -28,12 +28,20 @@ def tokenize_cool_text(grammar, idx, type_id, string, num, data, errors, printin # Give the lexer some input lexer.input(data) + lessequal = grammar.__getitem__("<=") + rarrow = grammar.__getitem__("=>") + larrow = grammar.__getitem__("<-") + fixed_tokens_names = { t.Name: (t.Name, t) for t in grammar.terminals - if t not in {idx, type_id, string, num} + if t not in {idx, type_id, string, num, lessequal, rarrow, larrow} } + fixed_tokens_names["larrow"] = ("<-", larrow) + fixed_tokens_names["rarrow"] = ("=>", rarrow) + fixed_tokens_names["lessequal"] = ("<=", lessequal) + tokens = [] pos_data = [] # Tokenize @@ -52,18 +60,15 @@ def tokenize_cool_text(grammar, idx, type_id, string, num, data, errors, printin try: tval, ttype = fixed_tokens_names[tok.type] except: - try: # for <=, ->, <- #this may be unnecessary - tval, ttype = fixed_tokens_names[tok.value] - except: - tval = tok.value - if tok.type == "string": - ttype = string - elif tok.type == "id": - ttype = idx - elif tok.type == "type_id": - ttype = type_id - else: - ttype = num + tval = tok.value + if tok.type == "string": + ttype = string + elif tok.type == "id": + ttype = idx + elif tok.type == "type_id": + ttype = type_id + else: + ttype = num tokens.append(Token(tval, ttype, (tok.lineno, find_column(data, tok.lexpos)))) if printing: diff --git a/src/tokens_rules.py b/src/tokens_rules.py index e4f4bf6fa..2824fb1db 100644 --- a/src/tokens_rules.py +++ b/src/tokens_rules.py @@ -119,37 +119,6 @@ def t_comments_eof(t): # Rules for initial state (default state) - -#Object identifiers -def t_id(t): - r"[a-z][a-zA-Z_0-9]*" - t.type = reserved.get( - t.value.lower(), "id" - ) # Check for reserved words. If it isn't a reserved word is categorized as identifier - return t - -#Type identifiers -def t_type_id(t): - r"[A-Z][a-zA-Z_0-9]*" - value_in_lowercase = t.value.lower() - if value_in_lowercase != "false" and value_in_lowercase != "true": - t.type = reserved.get( - value_in_lowercase, "type_id" - ) # Check for reserved words. If it isn't a reserved word is categorized as identifier - else: - t.type = "type_id"#this may be extra as t.type is already setted as type_id - # t.lexpos = t.lexpos - t.lexer.last_new_line_pos + 1 - return t - -# matching int numbers -def t_int(t): - r"\d+" - t.value = int(t.value) - # r'\d+(\.\d*)?' float numbers - # t.value = float(t.value) - return t - - def t_comment1(t): r"\--.*" pass @@ -157,7 +126,7 @@ def t_comment1(t): def t_string(t):# se va a develve el string vacio cada vez que no se puede matchear el string completo - r"\" "#xq habria que seguir analizando el string cuando se ha encontrado un caracter null y se ha de parar en otros casos? + r'\"'#xq habria que seguir analizando el string cuando se ha encontrado un caracter null y se ha de parar en otros casos? string_list = [] text = t.lexer.lexdata initial = t.lexer.lexpos @@ -222,6 +191,35 @@ def t_string(t):# se va a develve el string vacio cada vez que no se puede match return t +#Object identifiers +def t_id(t): + r'[a-z][a-zA-Z_0-9]*' + t.type = reserved.get( + t.value.lower(), "id" + ) # Check for reserved words. If it isn't a reserved word is categorized as identifier + return t + +#Type identifiers +def t_type_id(t): + r'[A-Z][a-zA-Z_0-9]*' + value_in_lowercase = t.value.lower() + if value_in_lowercase != "false" and value_in_lowercase != "true": + t.type = reserved.get( + value_in_lowercase, "type_id" + ) # Check for reserved words. If it isn't a reserved word is categorized as identifier + else: + t.type = "type_id"#this may be extra as t.type is already setted as type_id + # t.lexpos = t.lexpos - t.lexer.last_new_line_pos + 1 + return t + +# matching int numbers +def t_int(t): + r"\d+" + t.value = int(t.value) + # r'\d+(\.\d*)?' float numbers + # t.value = float(t.value) + return t + # Define a rule so we can track line numbers def t_newline(t): r'\n' diff --git a/src/type_checker.py b/src/type_checker.py index bf58c9d7c..4f2dceea9 100644 --- a/src/type_checker.py +++ b/src/type_checker.py @@ -452,8 +452,9 @@ def visit(self, node, scope): and left_type.name != "AUTO_TYPE" and right_type.name != "AUTO_TYPE" ): + node_row, node_col = node.token.location self.errors.append( - f"One of the expressions of '=' operator is of type Int, String or Bool, the other must have the same static type. Left type: {left_type.name}.Right type: {right_type.name}" + TypeError(node_row, node_col, f"One of the expressions of '=' operator is of type Int, String or Bool, the other must have the same static type. Left type: {left_type.name}. Right type: {right_type.name}") ) return self.context.get_type("Bool") From dce19854129af8c04df7a342157a25db59321935 Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Sat, 5 Mar 2022 13:10:57 -0500 Subject: [PATCH 082/162] feat: use cil nodes in build_constructor --- src/code_gen/cil_builder.py | 46 +++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index c15c33ec2..d454453fd 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -69,6 +69,7 @@ def __init__(self, errors=[]): self._count = 0 self.internal_count = 0 self.context = None + self.self_var = "self" def generate_next_method_id(self): self.method_count += 1 @@ -158,28 +159,42 @@ def is_attribute(self, vname): # self.code.append(ReturnIL()) def build_constructor(self, node): + self.current_function = self.register_function( + self.to_function_name("constructor", node.id) + ) + self.current_type.define_method("constructor", [], [], "Object") + + self_var = self.define_internal_local() + + self.register_instruction(AllocateNode(node.id, self_var)) + attributeNodes = [ feat for feat in node.features if isinstance(feat, cool.AttrDeclarationNode) ] - expr_list = [] for attr in attributeNodes: # Assign default value first - assign = cool.AssignNode( - self.to_attr_name(self.current_type.name, attr.id), - cool.DefaultValueNode(attr.type), + default_var = self.define_internal_local() + self.register_instruction(DefaultValueNode(default_var, attr.type)) + self.register_instruction( + SetAttribNode( + node.id, + self.to_attr_name(self.current_type.name, attr.id), + default_var, + ) ) - expr_list.append(assign) for attr in attributeNodes: # Assign init_expr if not None if attr.init_exp: - assign = cool.AssignNode( - self.to_attr_name(self.current_type.name, attr.id), attr.init_exp + init_expr_value = self.visit(attr.init_exp) + self.register_instruction( + SetAttribNode( + node.type, + self.to_attr_name(self.current_type.name, attr.id), + init_expr_value, + ) ) - expr_list.append(assign) - body = cool.BlockNode(expr_list) - self.current_type.define_method("constructor", [], [], "Object") - return cool.FuncDeclarationNode("constructor", [], "Object", body) + self.register_instruction(ReturnNode(self_var)) def add_builtin_functions(self): # Object @@ -380,7 +395,7 @@ def visit(self, node): type_node = self.register_type(self.current_type.name) - constructor = self.build_constructor(node) + self.build_constructor(node) visited_func = [] current_type = self.current_type @@ -406,7 +421,6 @@ def visit(self, node): type_node.attributes.reverse() type_node.methods.reverse() - self.visit(constructor) for feature in node.features: self.visit(feature) @@ -646,13 +660,11 @@ def visit(self, node): @visitor.when(cool.InstantiateNode) # NewNode def visit(self, node): instance = self.define_internal_local() - solve = self.define_internal_local() - self.register_instruction(AllocateNode(node.lex, instance)) self.register_instruction( - StaticCallNode(self.to_function_name("constructor", node.lex), solve) + StaticCallNode(self.to_function_name("constructor", node.lex), instance) ) - return solve + return instance @visitor.when(cool.IsvoidNode) def visit(self, node): From 33c4ca5dec39e42019c981523dac4abcccdf173b Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Sat, 5 Mar 2022 13:28:36 -0500 Subject: [PATCH 083/162] feat: add instance prop to nodes that use self --- src/cmp/cil.py | 15 +++++++++------ src/code_gen/cil_builder.py | 12 +++++++++--- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/cmp/cil.py b/src/cmp/cil.py index aaf8ba857..e120d4a2b 100644 --- a/src/cmp/cil.py +++ b/src/cmp/cil.py @@ -108,17 +108,19 @@ class IntComplementNode(UnaryNode): class GetAttribNode(InstructionNode): - def __init__(self, dest, typex, attr): + def __init__(self, dest, instance, attr, typex): self.dest = dest - self.type = typex + self.instance = instance self.attr = attr + self.type = typex class SetAttribNode(InstructionNode): - def __init__(self, typex, attr, value): - self.type = typex + def __init__(self, instance, attr, value, typex): + self.instance = instance self.value = value self.attr = attr + self.type = typex class ArrayNode(InstructionNode): @@ -168,10 +170,11 @@ def __init__(self, function, dest): class DynamicCallNode(InstructionNode): - def __init__(self, xtype, method, dest): - self.type = xtype + def __init__(self, instance, method, dest, typex): + self.instance = instance self.method = method self.dest = dest + self.type = typex class ArgNode(InstructionNode): diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index d454453fd..c67fb43fe 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -180,6 +180,7 @@ def build_constructor(self, node): node.id, self.to_attr_name(self.current_type.name, attr.id), default_var, + node.id, ) ) @@ -188,9 +189,10 @@ def build_constructor(self, node): init_expr_value = self.visit(attr.init_exp) self.register_instruction( SetAttribNode( - node.type, + node.id, self.to_attr_name(self.current_type.name, attr.id), init_expr_value, + node.id, ) ) @@ -470,7 +472,9 @@ def visit(self, node): expr = self.visit(node.expr) if self.is_attribute(node.id): - self.register_instruction(SetAttribNode("self", node.id, expr)) + self.register_instruction( + SetAttribNode("self", node.id, expr, self.current_type.name) + ) else: self.register_instruction(AssignNode(node.id, expr)) @@ -699,7 +703,9 @@ def visit(self, node): def visit(self, node): idx = self.generate_next_string_id() self.data.append(DataNode(idx, node.lex)) - return idx + solve = self.define_internal_local() + self.register_instruction(LoadNode(solve,idx)) + return solve @visitor.when(cool.BooleanNode) def visit(self, node): From 86d5b224313b05ee54674f4c81d900330835205b Mon Sep 17 00:00:00 2001 From: gabriela Date: Sat, 5 Mar 2022 15:26:31 -0500 Subject: [PATCH 084/162] Identify attributes inherited from other classes. --- src/cmp/semantic.py | 14 +++++++++----- src/type_builder.py | 19 +++++++++++++------ 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/cmp/semantic.py b/src/cmp/semantic.py index 4eccf31ef..73cde0e4a 100644 --- a/src/cmp/semantic.py +++ b/src/cmp/semantic.py @@ -56,11 +56,11 @@ def set_parent(self, parent): raise SemanticError(f"Is not possible to inherit from {parent.name}") self.parent = parent - def get_attribute(self, name: str, visited=None): + def get_attribute(self, name: str, index: int, visited=None): if visited is None: visited = [] try: - return next(attr for attr in self.attributes if attr.name == name) + return next((attr, index) for attr in self.attributes if attr.name == name) except StopIteration: visited.append(self.name) if self.parent is None: @@ -72,7 +72,7 @@ def get_attribute(self, name: str, visited=None): raise SemanticError( f'Attribute "{name}" is not defined in {self.name}.' ) - return self.parent.get_attribute(name, visited=visited) + return self.parent.get_attribute(name, index + 1, visited=visited) except SemanticError: raise SemanticError( f'Attribute "{name}" is not defined in {self.name}.' @@ -80,14 +80,18 @@ def get_attribute(self, name: str, visited=None): def define_attribute(self, name: str, typex): try: - self.get_attribute(name) + attr, index = self.get_attribute(name, 0) except SemanticError: attribute = Attribute(name, typex) self.attributes.append(attribute) return attribute else: + if index > 0: + mssg = "an inherited class" + else: + mssg = self.name raise SemanticError( - f'Attribute "{name}" is already defined in {self.name}.' + f'Attribute "{name}" is already defined in {mssg}.' ) def get_method(self, name: str, non_rec=False, visited=None): diff --git a/src/type_builder.py b/src/type_builder.py index 525e25716..18b6b6954 100644 --- a/src/type_builder.py +++ b/src/type_builder.py @@ -13,7 +13,7 @@ from tset import Tset from collections import deque from cool_visitor import CopyVisitor -from errors import SemanticError +from errors import SemanticError, TypeError class TypeBuilder: def __init__(self, errors=[]): @@ -198,20 +198,27 @@ def visit(self, node): node.id.lex, param_names, param_types, return_type ) except SError as error: + node_row, node_col = node.id.location # print("--------aqui se esta reportando el error del metodo doble---------") - self.errors.append(error.text) + self.errors.append(SemanticError(node_row, node_col,error.text)) @visitor.when(AttrDeclarationNode) def visit(self, node): try: - attr_type = self.get_type(node.type.lex) + try: + attr_type = self.context.get_type(node.type.lex) + except SError as error: + attr_type = ErrorType() + node_row, node_col = node.type.location + self.errors.append(TypeError(node_row, node_col,error.text)) self.current_type.define_attribute(node.id.lex, attr_type) except SError as error: - self.errors.append(error.text) + node_row, node_col = node.id.location + self.errors.append(SemanticError(node_row, node_col,error.text)) - def get_type(self, tname): + def get_type(self, ntype): try: - return self.context.get_type(tname) + return self.context.get_type(ntype) except SError as error: self.errors.append(error.text) return ErrorType() From d6d03208d9d3a45e1183baabddff8b057e28c5d1 Mon Sep 17 00:00:00 2001 From: gabriela Date: Sat, 5 Mar 2022 15:39:34 -0500 Subject: [PATCH 085/162] Correct get_type method in type_builder. Access to token.lex and token.locations properties from method. --- src/type_builder.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/type_builder.py b/src/type_builder.py index 18b6b6954..2ffbef8a2 100644 --- a/src/type_builder.py +++ b/src/type_builder.py @@ -172,7 +172,7 @@ def visit(self, node): if node.parent is not None: try: - parent_type = self.get_type(node.parent.lex) + parent_type = self.get_type(node.parent) self.current_type.set_parent(parent_type) except SError as error: node_row, node_col = node.parent.location @@ -192,8 +192,8 @@ def visit(self, node): param_names = [fname.lex for fname, ftype in node.params] try: - param_types = [self.get_type(ftype.lex) for fname, ftype in node.params] - return_type = self.get_type(node.type.lex) + param_types = [self.get_type(ftype) for fname, ftype in node.params] + return_type = self.get_type(node.type) self.current_type.define_method( node.id.lex, param_names, param_types, return_type ) @@ -205,12 +205,7 @@ def visit(self, node): @visitor.when(AttrDeclarationNode) def visit(self, node): try: - try: - attr_type = self.context.get_type(node.type.lex) - except SError as error: - attr_type = ErrorType() - node_row, node_col = node.type.location - self.errors.append(TypeError(node_row, node_col,error.text)) + attr_type = self.get_type(node.type) self.current_type.define_attribute(node.id.lex, attr_type) except SError as error: node_row, node_col = node.id.location @@ -218,7 +213,8 @@ def visit(self, node): def get_type(self, ntype): try: - return self.context.get_type(ntype) + return self.context.get_type(ntype.lex) except SError as error: - self.errors.append(error.text) + node_row, node_col = ntype.location + self.errors.append(TypeError(node_row, node_col,error.text)) return ErrorType() From 982d67ead6ae721769fe8e2cb798cef9d767500a Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Sat, 5 Mar 2022 15:51:55 -0500 Subject: [PATCH 086/162] feat: add get attr to variable node --- src/code_gen/cil_builder.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index c67fb43fe..250ddc97e 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -693,18 +693,30 @@ def visit(self, node): @visitor.when(cool.ConstantNumNode) def visit(self, node): - return node.lex + solve = self.define_internal_local() + self.register_instruction(AssignNode(solve, int(node.lex))) + return solve @visitor.when(cool.VariableNode) def visit(self, node): - return node.lex + solve = self.define_internal_local() + + if self.is_attribute(node.lex): + self.register_instruction( + GetAttribNode( + solve, self.current_type.name, node.lex, self.current_type.name + ) + ) + else: + self.register_instruction(AssignNode(solve, node.lex)) + return solve @visitor.when(cool.StringNode) def visit(self, node): idx = self.generate_next_string_id() self.data.append(DataNode(idx, node.lex)) solve = self.define_internal_local() - self.register_instruction(LoadNode(solve,idx)) + self.register_instruction(LoadNode(solve, idx)) return solve @visitor.when(cool.BooleanNode) From 753bc42d38edf484ea6944d8c2ae9bd75a787037 Mon Sep 17 00:00:00 2001 From: smartos99 Date: Sat, 5 Mar 2022 16:02:59 -0500 Subject: [PATCH 087/162] Add PrintNodes --- src/cmp/cil.py | 5 +- src/code_gen/cil_builder.py | 8 +- src/code_gen/mips_builder.py | 194 ++++++++++++++++++++++++++++++++--- src/code_gen/mips_nodes.py | 8 ++ 4 files changed, 194 insertions(+), 21 deletions(-) diff --git a/src/cmp/cil.py b/src/cmp/cil.py index aaf8ba857..29b7fa1c3 100644 --- a/src/cmp/cil.py +++ b/src/cmp/cil.py @@ -237,10 +237,13 @@ def __init__(self, dest, source): self.source = source -class PrintNode(InstructionNode): +class PrintStrNode(InstructionNode): def __init__(self, str_addr): self.str_addr = str_addr +class PrintIntNode(InstructionNode): + def __init__(self, str_addr): + self.int_addr = str_addr class TypeNameNode(InstructionNode): def __init__(self, dest, source): diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index e2c3e778e..793d9e808 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -28,7 +28,8 @@ SubstringNode, ToStrNode, ReadNode, - PrintNode, + PrintStrNode, + PrintIntNode, PlusNode, MinusNode, StarNode, @@ -298,7 +299,7 @@ def io_outstring(self): self.params.append(ParamNode("self")) str_arg = VariableInfo("str") self.register_param(str_arg) - self.register_instruction(PrintNode(str_arg.name)) + self.register_instruction(PrintStrNode(str_arg.name)) self.register_instruction(ReturnNode("self")) def io_outint(self): @@ -308,7 +309,8 @@ def io_outint(self): result = self.define_internal_local() self.register_instruction( ToStrNode(result, int_arg.name) - ) # TODO: Define PrintIntNode + ) + self.register_instruction(PrintIntNode(result)) self.register_instruction(ReturnNode(VariableInfo(result).name)) def io_instring(self): diff --git a/src/code_gen/mips_builder.py b/src/code_gen/mips_builder.py index 72d16d6be..44d36636f 100644 --- a/src/code_gen/mips_builder.py +++ b/src/code_gen/mips_builder.py @@ -6,6 +6,8 @@ #from operator import le #from tkinter.tix import Select from attr import attr +from matplotlib.pyplot import get +from soupsieve import select #from soupsieve import select import cmp.visitor as visitor @@ -40,6 +42,10 @@ VOID = "void" STR_CMP = "string_comparer" EMPTY_STRING = "empty_string" +LENGTH = "length" +COPY = "copy" +INPUT_STR_BUFFER = "input_str_buffer" +BUFFER_SIZE = 1024 #temporary registers t0 = "$t0" @@ -122,6 +128,7 @@ def __init__(self): self.types = {} self.attr_offset = {} self.memo = MemoryManager() + self.pushed_args = 0 def get_offset(self,x): @@ -165,6 +172,30 @@ def generate_attr_offset(self,type): for i,attr in enumerate(attributes): self.attr_offset[type][attr] = 4*(i+1) + def generate_str_length(self): + #calculates the length of the null-terminated char array referenced by $a0 and stores it in $a0 + self.memo.save() + reg1 = self.memo.get_unused_reg() + reg2 = self.memo.get_unused_reg() + + self.current_procedure = mips.ProcedureNode(LENGTH) + + self.register_instruction(mips.LoadInmediate, reg1, 0) + + self.register_instruction(mips.Label, "length_loop") + self.register_instruction(mips.LoadByteNode, reg2, 0, a0) + self.register_instruction(mips.BranchOnEqualNode, zero, reg2, "length_end") + + self.register_instruction(mips.AddNode, reg1, reg1, 1) + self.register_instruction(mips.AddNode, a0, a0, 1) + self.register_instruction(mips.Jump, "length_loop") + + self.register_instruction(mips.Label, "length_end") + self.register_instruction(mips.MoveNode, a0, reg1) + self.register_instruction(mips.Jump, ra) + + self.text.append(self.current_procedure) + #def register_main_allocation(self): # self.register_instruction(mips.CommentNode,"Allocating Main instance") # self.register_instruction(mips.MoveNode,fp,sp) @@ -258,6 +289,7 @@ def visit(self,node): offset = self.get_offset(node.name) self.register_instruction(mips.LoadWordNode,reg,offset,fp) self.register_push(reg) + self.pushed_args += 1 self.memo.clean() @@ -314,21 +346,55 @@ def visit(self,node): self.params = params_save + #@visitor.when(cil.LoadNode) + #def visit(self,node): + # self.memo.save() + # reg = self.memo.used_reg() + # + # if isinstance(node.msg,int): + # self.register_instruction(mips.LoadInmediate,reg,node.msg) + # else: + # self.register_instruction(mips.LoadAddress,reg,node.msg) + # + # offset = self.get_offset(node.dest) + # self.register_instruction(mips.StoreWordNode,reg,offset,fp) + # self.memo.clean() + @visitor.when(cil.LoadNode) - def visit(self,node): + def visit(self, node: cil.LoadNode): self.memo.save() - reg = self.memo.used_reg() - - if isinstance(node.msg,int): - self.register_instruction(mips.LoadInmediate,reg,node.msg) - else: - self.register_instruction(mips.LoadAddress,reg,node.msg) + _size = STRING_SIZE + self.register_instruction(mips.LoadInmediate,v0,SYSCALL_SBRK) + self.register_instruction(mips.LoadInmediate,a0,_size) + self.register_instruction(mips.SyscallNode) - offset = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode,reg,offset,fp) + dest_offset = self.get_offset(node.dest) + self.register_instruction(mips.StoreWordNode,v0,dest_offset,fp) + + reg = self.memo.get_unused_reg() + self.register_instruction(mips.LoadAddress,reg,STRING) + self.register_instruction(mips.StoreWordNode,reg,0,v0) + + #storing string length + self.register_instruction(mips.LoadInmediate, reg, len(node.msg)) + self.register_instruction(mips.StoreWordNode, reg, LENGTH_ATTR_OFFSET, v0) + + #storing string chars ref + self.register_instruction(mips.LoadAddress, reg, node.msg) + self.register_instruction(mips.StoreWordNode, reg, CHARS_ATTR_OFFSET, v0) self.memo.clean() - + @visitor.when(cil.LengthNode) + def visit(self, node): + self.memo.save() + reg = self.memo.get_unused_reg() + source_offset = self.get_offset(node.source) + self.register_instruction(mips.LoadNode, reg,source_offset, fp) + self.register_instruction(mips.LoadWordNode, reg, LENGTH_ATTR_OFFSET, reg) + dest_offset = self.get_offset(node.dest) + self.register_instruction(mips.StoreWordNode, reg,dest_offset, fp) + + #All return value is saved in register a1 @visitor.when(cil.ReturnNode) def visit(self,node): @@ -432,6 +498,8 @@ def visit(self,node): dest_offset = self.get_offset(node.dest) self.register_instruction(mips.StoreWordNode,a1,dest_offset,fp) + self.register_instruction(mips.AddiNode,sp,sp,self.pushed_args * 4) + self.pushed_args = 0 @visitor.when(cil.DynamicCallNode) @@ -506,6 +574,16 @@ def visit(self,node): self.register_instruction(mips.LoadInmediate,reg,0) self.register_instruction(mips.StoreWordNode,reg,dest_offset,fp) elif node.type == STRING: + _size = STRING_SIZE + self.register_instruction(mips.LoadInmediate,v0,SYSCALL_SBRK) + self.register_instruction(mips.LoadInmediate,a0,_size) + self.register_instruction(mips.SyscallNode) + + self.register_instruction(mips.StoreWordNode,v0,dest_offset,fp) + reg = self.memo.get_unused_reg() + self.register_instruction(mips.LoadAddress,reg,STRING) + self.register_instruction(mips.StoreWordNode,reg,0,v0) + self.register_instruction(mips.LoadInmediate,reg,0) self.register_instruction(mips.StoreWordNode, reg, LENGTH_ATTR_OFFSET, v0) #pq en vo esta el allocate self.register_instruction(mips.LoadAddress, reg, EMPTY_STRING) @@ -613,7 +691,93 @@ def visit(self,node): self.register_instruction(mips.CommentNode,"Aborting execution") self.register_instruction(mips.LoadInmediate,v0,SYSCALL_EXIT) self.register_instruction(mips.SyscallNode) - + + #READSTRING + @visitor.when(cil.ReadNode) + def visit(self,node): + self.memo.save() + self.register_instruction(mips.CommentNode,"ReadStrNode") + self.register_instruction(mips.CommentNode,"Reading String to buffer") + self.register_instruction(mips.LoadAddress, a0, INPUT_STR_BUFFER) + self.register_instruction(mips.LoadInmediate, a1, BUFFER_SIZE) + self.register_instruction(mips.LoadInmediate, v0, SYSCALL_READ_STR) + self.register_instruction(mips.SyscallNode) + + self.register_instruction(mips.CommentNode,"Saving reference to read string") + reg1 = self.memo.get_unused_reg() + if reg1 != t1: + if t1 in self.memo.used_reg: + self.register_instruction(mips.MoveNode,reg1,t1) + else: + self.memo.clean() + self.register_instruction(mips.MoveNode, t1, a0) + + self.register_instruction(mips.CommentNode,"Calculating str length") + self.register_instruction(mips.JumpAndLink, LENGTH) + + + self.register_instruction(mips.CommentNode,"Allocating char array for new string") + self.register_instruction(mips.LoadInmediate, v0, SYSCALL_SBRK) + self.register_instruction(mips.SyscallNode) + if t0 in self.memo.used_reg: + reg2 = self.memo.get_unused_reg() + self.register_instruction(mips.MoveNode,reg2,t0) + self.register_instruction(mips.MoveNode, t0, v0) + + reg3 = self.memo.get_unused_reg() + self.register_instruction(mips.MoveNode, reg3, v0)#saving pointer to char array + + reg4 = self.memo.get_unused_reg() + self.register_instruction(mips.AddNode, a0, a0, -1) + self.register_instruction(mips.MoveNode, reg4, a0)#saving length + + self.register_instruction(mips.CommentNode,"Copying bytes from one char array to another") + self.register_instruction(mips.JumpAndLink, COPY) + + self.register_instruction(mips.CommentNode,"Null-terminating the string") + self.register_instruction(mips.StoreByteNode, zero, 0, t0) + + self.register_instruction(mips.CommentNode,"Allocating new String instance") + _size = STRING_SIZE + self.register_instruction(mips.LoadInmediate,v0,SYSCALL_SBRK) + self.register_instruction(mips.LoadInmediate,a0,_size) + self.register_instruction(mips.SyscallNode) + + dest_offset = self.get_offset(node.dest) + self.register_instruction(mips.StoreWordNode,v0,dest_offset,fp) + + reg = self.memo.get_unused_reg() + self.register_instruction(mips.LoadAddress,reg,STRING) + self.register_instruction(mips.StoreWordNode,reg,0,v0) + + #storing string length + self.register_instruction(mips.CommentNode,"Storing length and reference to char array") + self.register_instruction(mips.StoreWordNode, reg4, LENGTH_ATTR_OFFSET, v0) + + #storing string chars ref + self.register_instruction(mips.StoreWordNode, reg3, CHARS_ATTR_OFFSET, v0) + self.memo.clean() + + @visitor.when(cil.PrintStrNode) + def visit(self,node): + self.register_instruction(mips.CommentNode,"PrintStringNode") + straddr_offset = self.get_offset(node.str_addr) + self.register_instruction(mips.LoadWordNode, a0, straddr_offset, fp) + self.register_instruction(mips.LoadWordNode, a0, CHARS_ATTR_OFFSET, a0) + self.register_instruction(mips.LoadInmediate, v0, SYSCALL_PRINT_STR) + self.register_instruction(mips.SyscallNode) + + @visitor.when(cil.PrintIntNode) + def visit(self,node): + self.register_instruction(mips.CommentNode,"PrintIntNode") + if isinstance(node.int_addr,int): + self.register_instruction(mips.LoadInmediate,a0,node.int_addr) + else: + int_offset = self.get_offset(node.int_addr) + self.register_instruction(mips.LoadWordNode, a0, int_offset, fp) + self.register_instruction(mips.LoadInmediate, v0, SYSCALL_PRINT_INT) + self.register_instruction(mips.SyscallNode) + #Incompleto @visitor.when(cil.TypeOfNode) def visit(self,node): @@ -625,18 +789,14 @@ def visit(self,node): @visitor.when(cil.TypeNameNode) - def visit(self,node): - pass - @visitor.when(cil.PrintNode) def visit(self,node): pass + @visitor.when(cil.ToStrNode) def visit(self,node): pass - @visitor.when(cil.ReadNode) - def visit(self,node): - pass + @visitor.when(cil.LengthNode) def visit(self,node): pass diff --git a/src/code_gen/mips_nodes.py b/src/code_gen/mips_nodes.py index 9a9195d76..7192c622c 100644 --- a/src/code_gen/mips_nodes.py +++ b/src/code_gen/mips_nodes.py @@ -41,11 +41,19 @@ def __init__(self,source,offset,dest): class LoadWordNode(DataTransferWithOffset): def __str__(self): return f'lw {self.source}, {str(self.offset)}({self.destination})' + +class LoadByteNode(DataTransferWithOffset): + def __str__(self): + return f'lb {self.source}, {str(self.offset)}({self.destination})' class StoreWordNode(DataTransferWithOffset): def __str__(self): return f'sw {self.source}, {str(self.offset)}({self.destination})' +class StoreByteNode(DataTransferWithOffset): + def __str__(self): + return f'sb {self.source}, {str(self.offset)}({self.destination})' + class LoadNode(DataTransferNode): def __init__(self,dest,value): self.destination = dest From 4fecd4eb8de5427b724f31e55e217fea18f482d3 Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Sat, 5 Mar 2022 16:06:17 -0500 Subject: [PATCH 088/162] fix: check param names in is_attribute function --- src/code_gen/cil_builder.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index 250ddc97e..215661171 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -148,7 +148,9 @@ def register_data(self, name, value): return data_node def is_attribute(self, vname): - return vname not in [var.name for var in self.current_function.localvars] + return vname not in [var.name for var in self.current_function.localvars] and ( + vname not in [param.name for param in self.current_function.params] + ) # def builtin_constructor(self): # built = ["Object", "IO", "Int", "Bool", "String"] From 97db5a3c1dd7fadd09bf80fd109546705a9185cd Mon Sep 17 00:00:00 2001 From: smartos99 Date: Sat, 5 Mar 2022 16:12:52 -0500 Subject: [PATCH 089/162] Stage to push --- src/cmp/cil.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/cmp/cil.py b/src/cmp/cil.py index 9212041fd..a18c2ca85 100644 --- a/src/cmp/cil.py +++ b/src/cmp/cil.py @@ -410,9 +410,13 @@ def visit(self, node): def visit(self, node): return f"{node.dest} = READ" - @visitor.when(PrintNode) + @visitor.when(PrintStrNode) def visit(self, node): - return f"PRINT {node.str_addr}" + return f"PRINT STR{node.str_addr}" + + @visitor.when(PrintIntNode) + def visit(self, node): + return f"PRINT INT{node.str_addr}" @visitor.when(LengthNode) def visit(self, node): From f18517386e1924ac965a2a005e527f62d35d2d82 Mon Sep 17 00:00:00 2001 From: smartos99 Date: Sat, 5 Mar 2022 16:15:42 -0500 Subject: [PATCH 090/162] Add PrintStr and PrintInt to PrintVisitor --- src/cmp/cil.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/cmp/cil.py b/src/cmp/cil.py index 9212041fd..52f0ea337 100644 --- a/src/cmp/cil.py +++ b/src/cmp/cil.py @@ -410,10 +410,14 @@ def visit(self, node): def visit(self, node): return f"{node.dest} = READ" - @visitor.when(PrintNode) + @visitor.when(PrintStrNode) def visit(self, node): - return f"PRINT {node.str_addr}" + return f"PRINT STR {node.str_addr}" + @visitor.when(PrintIntNode) + def visit(self, node): + return f"PRINT INT {node.str_addr}" + @visitor.when(LengthNode) def visit(self, node): return f"{node.dest} = LENGTH {node.source}" From 6088e45c25e3c09a534fe82e797fa724d8f151ba Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Sat, 5 Mar 2022 16:24:09 -0500 Subject: [PATCH 091/162] fix: get instance from constructor --- src/code_gen/cil_builder.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index 2677983e5..37822ae84 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -324,9 +324,7 @@ def io_outint(self): int_arg = VariableInfo("int") self.register_param(int_arg) result = self.define_internal_local() - self.register_instruction( - ToStrNode(result, int_arg.name) - ) + self.register_instruction(ToStrNode(result, int_arg.name)) self.register_instruction(PrintIntNode(result)) self.register_instruction(ReturnNode(VariableInfo(result).name)) @@ -361,11 +359,8 @@ def visit(self, node): main_constructor = self.to_function_name("constructor", "Main") main_method_name = self.to_function_name("Main", "main") - # Get instance from allocate - self.register_instruction(AllocateNode("Main", instance)) - self.register_instruction( - StaticCallNode(main_constructor, self.define_internal_local()) - ) + # Get instance from constructor + self.register_instruction(StaticCallNode(main_constructor, instance)) # Pass instance as parameter and call Main_main self.register_instruction(ArgNode(instance)) From 29f7781af5818cc6ed55aa276943ff067284a49a Mon Sep 17 00:00:00 2001 From: smartos99 Date: Sat, 5 Mar 2022 16:25:59 -0500 Subject: [PATCH 092/162] Fix PrintIntNode --- src/cmp/cil.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cmp/cil.py b/src/cmp/cil.py index a18c2ca85..0d81ed571 100644 --- a/src/cmp/cil.py +++ b/src/cmp/cil.py @@ -245,8 +245,8 @@ def __init__(self, str_addr): self.str_addr = str_addr class PrintIntNode(InstructionNode): - def __init__(self, str_addr): - self.int_addr = str_addr + def __init__(self, int_addr): + self.int_addr = int_addr class TypeNameNode(InstructionNode): def __init__(self, dest, source): @@ -416,7 +416,7 @@ def visit(self, node): @visitor.when(PrintIntNode) def visit(self, node): - return f"PRINT INT{node.str_addr}" + return f"PRINT INT{node.int_addr}" @visitor.when(LengthNode) def visit(self, node): From 8a8c6104d820663e782116016f5cc2d9ff09cf34 Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Sat, 5 Mar 2022 17:18:47 -0500 Subject: [PATCH 093/162] feat: add builtin constructors --- src/cmp/cil.py | 6 +- src/code_gen/cil_builder.py | 22 +- src/code_gen/mips_builder.py | 805 +++++++++++++++++------------------ src/code_gen/mips_nodes.py | 158 ++++--- 4 files changed, 507 insertions(+), 484 deletions(-) diff --git a/src/cmp/cil.py b/src/cmp/cil.py index 52f0ea337..43cb7ee9a 100644 --- a/src/cmp/cil.py +++ b/src/cmp/cil.py @@ -244,10 +244,12 @@ class PrintStrNode(InstructionNode): def __init__(self, str_addr): self.str_addr = str_addr + class PrintIntNode(InstructionNode): def __init__(self, str_addr): self.int_addr = str_addr + class TypeNameNode(InstructionNode): def __init__(self, dest, source): self.dest = dest @@ -416,8 +418,8 @@ def visit(self, node): @visitor.when(PrintIntNode) def visit(self, node): - return f"PRINT INT {node.str_addr}" - + return f"PRINT INT {node.int_addr}" + @visitor.when(LengthNode) def visit(self, node): return f"{node.dest} = LENGTH {node.source}" diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index 37822ae84..58a7cf194 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -153,13 +153,18 @@ def is_attribute(self, vname): vname not in [param.name for param in self.current_function.params] ) - # def builtin_constructor(self): - # built = ["Object", "IO", "Int", "Bool", "String"] - # for c in built: + def add_builtin_constructors(self): + builtin_types = ["Object", "IO", "Int", "Bool", "String"] + for typex in builtin_types: + self.current_function = FunctionNode( + self.to_function_name("constructor", typex), [], [], [] + ) + instance = self.define_internal_local() + self.register_instruction(AllocateNode(typex, instance)) + self.register_instruction(ReturnNode(instance)) + self.code.append(self.current_function) - # self.code.append(LabelIL(c, "Constructor", True)) - # self.code.append(PushIL()) # No result, but needed in logic - # self.code.append(ReturnIL()) + self.current_function = None def build_constructor(self, node): self.current_function = self.register_function( @@ -183,7 +188,7 @@ def build_constructor(self, node): node.id, self.to_attr_name(self.current_type.name, attr.id), default_var, - node.id, + self_var, ) ) @@ -195,7 +200,7 @@ def build_constructor(self, node): node.id, self.to_attr_name(self.current_type.name, attr.id), init_expr_value, - node.id, + self_var, ) ) @@ -349,6 +354,7 @@ def visit(self, node): self.context = node.context self.add_builtin_functions() + self.add_builtin_constructors() self.current_function = FunctionNode("main", [], [], []) self.code.append(self.current_function) diff --git a/src/code_gen/mips_builder.py b/src/code_gen/mips_builder.py index 44d36636f..012c22baf 100644 --- a/src/code_gen/mips_builder.py +++ b/src/code_gen/mips_builder.py @@ -1,42 +1,29 @@ -#from atexit import register -#from email.quoprimime import body_length -import enum -from ssl import ALERT_DESCRIPTION_BAD_CERTIFICATE_HASH_VALUE -from turtle import left -#from operator import le -#from tkinter.tix import Select -from attr import attr -from matplotlib.pyplot import get -from soupsieve import select - -#from soupsieve import select +# from soupsieve import select import cmp.visitor as visitor import cmp.cil as cil import random from code_gen import mips_nodes as mips - - -#type_info offsets +# type_info offsets TYPENAME_OFFSET = 0 FUNCTION_OFFSET = 4 RA_OFFSET = 8 OLD_FP_OFFSET = 4 -#str attributes offsets +# str attributes offsets LENGTH_ATTR_OFFSET = 4 CHARS_ATTR_OFFSET = 8 -FP_ARGS_DISTANCE = 3 # how far finishes $fp from arguments in method call -FP_LOCALS_DISTANCE = 0 # how far finishes $fp from localvars in method call +FP_ARGS_DISTANCE = 3 # how far finishes $fp from arguments in method call +FP_LOCALS_DISTANCE = 0 # how far finishes $fp from localvars in method call -ABORT_SIGNAL = "abort_signal"#CIL -CASE_MISSMATCH = "case_missmatch"#CIL -CASE_VOID = "case_on_void"#MIPS -DISPATCH_VOID = "dispatch_on_void"#MIPS -ZERO_DIVISION = "division_by_zero"#MIPS -SUBSTR_OUT_RANGE = "substr_out_of_range"#MIPS +ABORT_SIGNAL = "abort_signal" # CIL +CASE_MISSMATCH = "case_missmatch" # CIL +CASE_VOID = "case_on_void" # MIPS +DISPATCH_VOID = "dispatch_on_void" # MIPS +ZERO_DIVISION = "division_by_zero" # MIPS +SUBSTR_OUT_RANGE = "substr_out_of_range" # MIPS HEAP_OVERFLOW = "heap_overflow" STRING_SIZE = 12 VOID = "void" @@ -47,27 +34,27 @@ INPUT_STR_BUFFER = "input_str_buffer" BUFFER_SIZE = 1024 -#temporary registers +# temporary registers t0 = "$t0" t1 = "$t1" t2 = "$t2" t3 = "$t3" t4 = "$t4" t5 = "$t5" -t6 = "$t6" # convenios -t7 = "$t7" # convenios -t8 = "$t8" -t9 = "$t9" +t6 = "$t6" # convenios +t7 = "$t7" # convenios +t8 = "$t8" +t9 = "$t9" -#Arguments Registers +# Arguments Registers a0 = "$a0" a1 = "$a1" a2 = "$a2" a3 = "$a3" -#frame pointer +# frame pointer fp = "$fp" -#stack pointer +# stack pointer sp = "$sp" ra = "$ra" @@ -94,25 +81,27 @@ OBJECT = "Object" IO = "IO" + class MemoryManager: def __init__(self): - self.all_reg = [t0,t1,t2,t3,t4,t5,t6,t7,t8,t9] + self.all_reg = [t0, t1, t2, t3, t4, t5, t6, t7, t8, t9] self.used_reg = [] self.stored = [] - + def get_unused_reg(self): - unused = list(set(self.all_reg) - set(self.used_reg)) + list(set(self.used_reg) - set(self.all_reg)) - reg = random.choice(unused) + unused = list(set(self.all_reg) - set(self.used_reg)) + list( + set(self.used_reg) - set(self.all_reg) + ) + reg = random.choice(unused) self.used_reg.append(reg) return reg - + def clean(self): self.used_reg = self.stored self.stored = [] - + def save(self): self.stored = self.used_reg.copy() - class MIPSBuilder: @@ -129,55 +118,67 @@ def __init__(self): self.attr_offset = {} self.memo = MemoryManager() self.pushed_args = 0 - - - def get_offset(self,x): + + def get_offset(self, x): if x in self.locals: index = self.locals.index(x) - return -4*index + return -4 * index elif x in self.params: index = self.params.index(x) - return (-4 * (len(self.locals)+len(self.params)))+4 - + return (-4 * (len(self.locals) + len(self.params))) + 4 + def register_instruction(self, instruction_type, *args): instruction = instruction_type(*args) - self.current_procedure.instructions.append(instruction) - - def register_data(self,data_type,*args): + self.current_procedure.instructions.append(instruction) + + def register_data(self, data_type, *args): data = data_type(*args) self.data.append(data) - - + def register_push(self, reg): self.register_instruction(mips.StoreWordNode, reg, 0, sp) self.register_instruction(mips.AddiNode, sp, sp, -4) def register_pop(self, reg): self.register_instruction(mips.LoadWordNode, reg, 4, sp) - self.register_instruction(mips.AddiNode, sp, sp, 4) - + self.register_instruction(mips.AddiNode, sp, sp, 4) + def generate_exception_messages(self): - self.register_data(mips.DataTypeNode, ABORT_SIGNAL, '.asciiz', ['"Program execution aborted"']) - self.register_data(mips.DataTypeNode, CASE_MISSMATCH, '.asciiz', ['"Execution of a case statement without a matching branch"']) - self.register_data(mips.DataTypeNode, CASE_VOID, '.asciiz', ['"Case on void"']) - self.register_data(mips.DataTypeNode, DISPATCH_VOID, '.asciiz', ['"Dispatch on void"']) - self.register_data(mips.DataTypeNode, ZERO_DIVISION, '.asciiz', ['"Division by zero"']) - self.register_data(mips.DataTypeNode, SUBSTR_OUT_RANGE, '.asciiz', ['"Substring out of range"']) - self.register_data(mips.DataTypeNode, HEAP_OVERFLOW, '.asciiz', ['"Heap overflow"']) - - - def generate_attr_offset(self,type): + self.register_data( + mips.DataTypeNode, ABORT_SIGNAL, ".asciiz", ['"Program execution aborted"'] + ) + self.register_data( + mips.DataTypeNode, + CASE_MISSMATCH, + ".asciiz", + ['"Execution of a case statement without a matching branch"'], + ) + self.register_data(mips.DataTypeNode, CASE_VOID, ".asciiz", ['"Case on void"']) + self.register_data( + mips.DataTypeNode, DISPATCH_VOID, ".asciiz", ['"Dispatch on void"'] + ) + self.register_data( + mips.DataTypeNode, ZERO_DIVISION, ".asciiz", ['"Division by zero"'] + ) + self.register_data( + mips.DataTypeNode, SUBSTR_OUT_RANGE, ".asciiz", ['"Substring out of range"'] + ) + self.register_data( + mips.DataTypeNode, HEAP_OVERFLOW, ".asciiz", ['"Heap overflow"'] + ) + + def generate_attr_offset(self, type): attributes = self.types[type].attributes - self.attr_offset[type]={} - for i,attr in enumerate(attributes): - self.attr_offset[type][attr] = 4*(i+1) - + self.attr_offset[type] = {} + for i, attr in enumerate(attributes): + self.attr_offset[type][attr] = 4 * (i + 1) + def generate_str_length(self): - #calculates the length of the null-terminated char array referenced by $a0 and stores it in $a0 + # calculates the length of the null-terminated char array referenced by $a0 and stores it in $a0 self.memo.save() reg1 = self.memo.get_unused_reg() reg2 = self.memo.get_unused_reg() - + self.current_procedure = mips.ProcedureNode(LENGTH) self.register_instruction(mips.LoadInmediate, reg1, 0) @@ -195,632 +196,610 @@ def generate_str_length(self): self.register_instruction(mips.Jump, ra) self.text.append(self.current_procedure) - - #def register_main_allocation(self): + + # def register_main_allocation(self): # self.register_instruction(mips.CommentNode,"Allocating Main instance") # self.register_instruction(mips.MoveNode,fp,sp) # self.register_instruction(mips.AddiNode,sp,sp,-4) - # + # # self.register_instruction(mips.CommentNode,"Allocating Main instance") # #Allocate # self.register_instruction(mips.LoadInmediate,v0,SYSCALL_SBRK) # self.register_instruction(mips.LoadInmediate,a0,self.main_size) # self.register_instruction(mips.SyscallNode) # self.register_instruction(mips.StoreWordNode,v0,0,fp) - # + # # self.register_instruction(mips.CommentNode,"Calling Main Constructor") # self.register_push(fp) # self.register_instruction(mips.JumpAndLink,"Main_constructor") - - + @visitor.on("node") def visit(self, node=None): pass - + @visitor.when(cil.ProgramNode) def visit(self, node): for type in node.dottypes: self.visit(type) self.generate_attr_offset(type.name) - - + self.generate_exception_messages() - + for str_data in node.dotdata: self.visit(str_data) - + for instruction in node.dotcode: self.visit(instruction) - - - return mips.ProgramNode(self.data,self.text) - + + return mips.ProgramNode(self.data, self.text) @visitor.when(cil.TypeNode) def visit(self, node): self.types[node.name] = node if node.name == "Main": - self.main_size = (len(node.attributes)+1)*4 + self.main_size = (len(node.attributes) + 1) * 4 values = [] for func in node.methods: values.append(func[1]) - - self.register_data(mips.DataTypeNode,'.word',node.name,values) - self.register_data(mips.DataTypeNode, f'{node.name}_cname','.asciiz', [f'"{node.name}"']) - - - #Filling type type info - #self.register_instruction(mips.CommentNode(f"Filling {node.name} VT")) - #self.register_instruction(mips.LoadAddress,t0,node.name) - #self.register_instruction(mips.LoadAddress,t1,f'{node.name}_cname') - - #self.register_instruction(mips.StoreWordNode,t1,TYPENAME_OFFSET,t0) - - #Filling type VT - #for i,func in enumerate(node.methods): + + self.register_data(mips.DataTypeNode, ".word", node.name, values) + self.register_data( + mips.DataTypeNode, f"{node.name}_cname", ".asciiz", [f'"{node.name}"'] + ) + + # Filling type type info + # self.register_instruction(mips.CommentNode(f"Filling {node.name} VT")) + # self.register_instruction(mips.LoadAddress,t0,node.name) + # self.register_instruction(mips.LoadAddress,t1,f'{node.name}_cname') + + # self.register_instruction(mips.StoreWordNode,t1,TYPENAME_OFFSET,t0) + + # Filling type VT + # for i,func in enumerate(node.methods): # offset = FUNCTION_OFFSET*i # self.register_instruction(mips.LoadAddress,t1,func.name) # self.register_instruction(mips.StoreWordNode,t1,offset,t0) - + @visitor.when(cil.DataNode) def visit(self, node): - self.register_data(mips.DataTypeNode,'.ascii',node.name,[node.value]) + self.register_data(mips.DataTypeNode, ".ascii", node.name, [node.value]) - - @visitor.when(cil.ParamNode) - def visit(self,node): + def visit(self, node): self.memo.save() reg = self.memo.get_unused_reg() - + self.params.append(node.name) - - self.register_instruction(mips.LoadInmediate,reg,node.name) - self.register_instruction(mips.StoreWordNode,reg,len(self.params)*4,fp) - + + self.register_instruction(mips.LoadInmediate, reg, node.name) + self.register_instruction(mips.StoreWordNode, reg, len(self.params) * 4, fp) + self.memo.clean() - - - @visitor.when(cil.ArgNode) - def visit(self,node): + + @visitor.when(cil.ArgNode) + def visit(self, node): self.memo.save() reg = self.memo.get_unused_reg() - + offset = self.get_offset(node.name) - self.register_instruction(mips.LoadWordNode,reg,offset,fp) + self.register_instruction(mips.LoadWordNode, reg, offset, fp) self.register_push(reg) self.pushed_args += 1 - + self.memo.clean() - - - + @visitor.when(cil.FunctionNode) - def visit(self,node): - + def visit(self, node): + locals_save = self.locals params_save = self.params self.locals, self.params = [], [] self.current_procedure = mips.ProcedureNode(node.name) - self.register_instruction(mips.CommentNode,"Pushing $ra") + self.register_instruction(mips.CommentNode, "Pushing $ra") self.register_push(ra) - self.register_instruction(mips.CommentNode,"Saving $fp") + self.register_instruction(mips.CommentNode, "Saving $fp") self.register_push(fp) - self.register_instruction(mips.CommentNode,"New $fp") + self.register_instruction(mips.CommentNode, "New $fp") self.register_instruction(mips.MoveNode, fp, sp) - - self.register_instruction(mips.CommentNode,"Reserving space for locals") - self.register_instruction(mips.AddiNode, sp, sp, -4*len(node.localvars)) + + self.register_instruction(mips.CommentNode, "Reserving space for locals") + self.register_instruction(mips.AddiNode, sp, sp, -4 * len(node.localvars)) for local in node.localvars: self.locals.append(local.name) - + for param in node.params: self.params.append(param.name) - self.register_instruction(mips.CommentNode,"Executing instructions") + self.register_instruction(mips.CommentNode, "Executing instructions") for inst in node.instructions: self.visit(inst) - - - self.register_instruction(mips.CommentNode,"Restoring saved $ra") - self.register_instruction(mips.LoadWordNode, ra, RA_OFFSET, fp)#stored $ra - - - self.register_instruction(mips.CommentNode,"Restoring saved $fp") - self.register_instruction(mips.LoadWordNode, fp, OLD_FP_OFFSET, fp)#stored (old)$fp - - AR = 4*(len(node.localvars) + len(node.params) + 2) - #AR = 4*(len(node.localvars) + 2) - - self.register_instruction(mips.CommentNode,"Cleaning stack after call") + + self.register_instruction(mips.CommentNode, "Restoring saved $ra") + self.register_instruction(mips.LoadWordNode, ra, RA_OFFSET, fp) # stored $ra + + self.register_instruction(mips.CommentNode, "Restoring saved $fp") + self.register_instruction( + mips.LoadWordNode, fp, OLD_FP_OFFSET, fp + ) # stored (old)$fp + + AR = 4 * (len(node.localvars) + len(node.params) + 2) + # AR = 4*(len(node.localvars) + 2) + + self.register_instruction(mips.CommentNode, "Cleaning stack after call") self.register_instruction(mips.AddiNode, sp, sp, AR) - - self.register_instruction(mips.CommentNode,"Return jump") + + self.register_instruction(mips.CommentNode, "Return jump") self.register_instruction(mips.JumpRegister, ra) self.text.append(self.current_procedure) self.locals = locals_save - self.params = params_save - - - #@visitor.when(cil.LoadNode) - #def visit(self,node): + self.params = params_save + + # @visitor.when(cil.LoadNode) + # def visit(self,node): # self.memo.save() # reg = self.memo.used_reg() - # + # # if isinstance(node.msg,int): # self.register_instruction(mips.LoadInmediate,reg,node.msg) # else: # self.register_instruction(mips.LoadAddress,reg,node.msg) - # + # # offset = self.get_offset(node.dest) # self.register_instruction(mips.StoreWordNode,reg,offset,fp) # self.memo.clean() - + @visitor.when(cil.LoadNode) def visit(self, node: cil.LoadNode): self.memo.save() _size = STRING_SIZE - self.register_instruction(mips.LoadInmediate,v0,SYSCALL_SBRK) - self.register_instruction(mips.LoadInmediate,a0,_size) + self.register_instruction(mips.LoadInmediate, v0, SYSCALL_SBRK) + self.register_instruction(mips.LoadInmediate, a0, _size) self.register_instruction(mips.SyscallNode) - + dest_offset = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode,v0,dest_offset,fp) + self.register_instruction(mips.StoreWordNode, v0, dest_offset, fp) reg = self.memo.get_unused_reg() - self.register_instruction(mips.LoadAddress,reg,STRING) - self.register_instruction(mips.StoreWordNode,reg,0,v0) + self.register_instruction(mips.LoadAddress, reg, STRING) + self.register_instruction(mips.StoreWordNode, reg, 0, v0) - #storing string length + # storing string length self.register_instruction(mips.LoadInmediate, reg, len(node.msg)) self.register_instruction(mips.StoreWordNode, reg, LENGTH_ATTR_OFFSET, v0) - #storing string chars ref + # storing string chars ref self.register_instruction(mips.LoadAddress, reg, node.msg) self.register_instruction(mips.StoreWordNode, reg, CHARS_ATTR_OFFSET, v0) self.memo.clean() - + @visitor.when(cil.LengthNode) def visit(self, node): self.memo.save() reg = self.memo.get_unused_reg() source_offset = self.get_offset(node.source) - self.register_instruction(mips.LoadNode, reg,source_offset, fp) + self.register_instruction(mips.LoadNode, reg, source_offset, fp) self.register_instruction(mips.LoadWordNode, reg, LENGTH_ATTR_OFFSET, reg) dest_offset = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode, reg,dest_offset, fp) - - - #All return value is saved in register a1 + self.register_instruction(mips.StoreWordNode, reg, dest_offset, fp) + + # All return value is saved in register a1 @visitor.when(cil.ReturnNode) - def visit(self,node): - if isinstance(node.value,int): - self.register_instruction(mips.LoadInmediate,a1,node.value) - else: + def visit(self, node): + if isinstance(node.value, int): + self.register_instruction(mips.LoadInmediate, a1, node.value) + else: offset = self.get_offset(node.value) - self.register_instruction(mips.LoadWordNode,a1,offset,fp) - + self.register_instruction(mips.LoadWordNode, a1, offset, fp) + @visitor.when(cil.GotoNode) - def visit(self,node): - self.register_instruction(mips.UnconditionalJumpNode,node.label) - - - + def visit(self, node): + self.register_instruction(mips.UnconditionalJumpNode, node.label) + @visitor.when(cil.AllocateNode) - def visit(self,node): + def visit(self, node): self.memo.save() - _size = (len(self.types[node.type].attributes)+1)*4 - self.register_instruction(mips.LoadInmediate,v0,SYSCALL_SBRK) - self.register_instruction(mips.LoadInmediate,a0,_size) + _size = (len(self.types[node.type].attributes) + 1) * 4 + self.register_instruction(mips.LoadInmediate, v0, SYSCALL_SBRK) + self.register_instruction(mips.LoadInmediate, a0, _size) self.register_instruction(mips.SyscallNode) - + dest_offset = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode,v0,dest_offset,fp) - + self.register_instruction(mips.StoreWordNode, v0, dest_offset, fp) + reg = self.memo.get_unused_reg() - self.register_instruction(mips.LoadAddress,reg,node.type) - self.register_instruction(mips.StoreWordNode,reg,0,v0) + self.register_instruction(mips.LoadAddress, reg, node.type) + self.register_instruction(mips.StoreWordNode, reg, 0, v0) self.memo.clean() - + @visitor.when(cil.AssignNode) - def visit(self,node): + def visit(self, node): self.save() - + reg = self.memo.get_unused_reg() - + source_offset = self.get_offset(node.source) dest_offset = self.get_offset(node.dest) - - self.register_instruction(mips.LoadWordNode,reg,source_offset,fp) - - self.register_instruction(mips.StoreWordNode,reg,dest_offset,fp) - - self.memo.clean() - - + + self.register_instruction(mips.LoadWordNode, reg, source_offset, fp) + + self.register_instruction(mips.StoreWordNode, reg, dest_offset, fp) + + self.memo.clean() + @visitor.when(cil.PlusNode) - def visit(self,node): + def visit(self, node): self.save() - + reg1 = self.memo.get_unused_reg() reg2 = self.memo.get_unused_reg() reg3 = self.memo.get_unused_reg() - - self.register_instruction(mips.LoadInmediate,reg1,node.left) - self.register_instruction(mips.LoadInmediate,reg2,node.right) - - self.register_instruction(mips.AddNode,reg3,reg1,reg2) - + + self.register_instruction(mips.LoadInmediate, reg1, node.left) + self.register_instruction(mips.LoadInmediate, reg2, node.right) + + self.register_instruction(mips.AddNode, reg3, reg1, reg2) + offset = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode,reg3,offset,fp) - + self.register_instruction(mips.StoreWordNode, reg3, offset, fp) + self.memo.clean() - + @visitor.when(cil.MinusNode) - def visit(self,node): + def visit(self, node): self.save() - + reg1 = self.memo.get_unused_reg() reg2 = self.memo.get_unused_reg() reg3 = self.memo.get_unused_reg() - - self.register_instruction(mips.LoadInmediate,reg1,node.left) - self.register_instruction(mips.LoadInmediate,reg2,node.right) - - self.register_instruction(mips.SubNode,reg3,reg1,reg2) - + + self.register_instruction(mips.LoadInmediate, reg1, node.left) + self.register_instruction(mips.LoadInmediate, reg2, node.right) + + self.register_instruction(mips.SubNode, reg3, reg1, reg2) + offset = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode,reg3,offset,fp) - + self.register_instruction(mips.StoreWordNode, reg3, offset, fp) + self.memo.clean() - + @visitor.when(cil.RuntimeErrorNode) - def visit(self,node): - - self.register_instruction(mips.CommentNode,"Printing Abort Message") - self.register_instruction(mips.LoadAddress,a0,ABORT_SIGNAL) - self.register_instruction(mips.LoadInmediate,v0,SYSCALL_PRINT_STR) + def visit(self, node): + + self.register_instruction(mips.CommentNode, "Printing Abort Message") + self.register_instruction(mips.LoadAddress, a0, ABORT_SIGNAL) + self.register_instruction(mips.LoadInmediate, v0, SYSCALL_PRINT_STR) self.register_instruction(mips.SyscallNode) - - self.register_instruction(mips.CommentNode,"Aborting execution") - self.register_instruction(mips.LoadInmediate,v0,SYSCALL_EXIT) + + self.register_instruction(mips.CommentNode, "Aborting execution") + self.register_instruction(mips.LoadInmediate, v0, SYSCALL_EXIT) self.register_instruction(mips.SyscallNode) - - + @visitor.when(cil.StaticCallNode) - def visit(self,node): - - self.register_instruction(mips.JumpAndLink,node.function) - + def visit(self, node): + + self.register_instruction(mips.JumpAndLink, node.function) + dest_offset = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode,a1,dest_offset,fp) - self.register_instruction(mips.AddiNode,sp,sp,self.pushed_args * 4) + self.register_instruction(mips.StoreWordNode, a1, dest_offset, fp) + self.register_instruction(mips.AddiNode, sp, sp, self.pushed_args * 4) self.pushed_args = 0 - - + @visitor.when(cil.DynamicCallNode) - def visit(self,node): + def visit(self, node): self.memo.save() - + reg1 = self.memo.get_unused_reg() reg2 = self.memo.get_unused_reg() - + instance_offset = self.get_offset(node.instance) - self.register_instruction(mips.CommentNode,"Getting type of instance") - self.register_instruction(mips.LoadWordNode,reg1,instance_offset,fp) - - #getting method offset + self.register_instruction(mips.CommentNode, "Getting type of instance") + self.register_instruction(mips.LoadWordNode, reg1, instance_offset, fp) + + # getting method offset _methods = self.types[node.type].methods meth_offset = _methods.index(node.method) - self.register_instruction(mips.LoadWordNode,reg2,meth_offset*4,reg1) - - self.register_instruction(mips.JumpAndLink,reg2) - - #putting the return vslue in destination + self.register_instruction(mips.LoadWordNode, reg2, meth_offset * 4, reg1) + + self.register_instruction(mips.JumpAndLink, reg2) + + # putting the return vslue in destination dest_offset = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode,a1,dest_offset,fp) - + self.register_instruction(mips.StoreWordNode, a1, dest_offset, fp) + self.memo.clean() - - - - - - + @visitor.when(cil.GetAttribNode) def visit(self, node): self.memo.save() - + reg1 = self.memo.get_unused_reg() reg2 = self.memo.get_unused_reg() - + instance_offset = self.get_offset(node.instance) - self.register_instruction(mips.LoadWordNode,reg1,instance_offset,fp) - + self.register_instruction(mips.LoadWordNode, reg1, instance_offset, fp) + attr_offs = self.attr_offset[node.type][node.attr] - self.register_instruction(mips.LoadWordNode,reg2,attr_offs,reg1) - + self.register_instruction(mips.LoadWordNode, reg2, attr_offs, reg1) + dest_offs = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode,reg2,dest_offs,fp) - - + self.register_instruction(mips.StoreWordNode, reg2, dest_offs, fp) + @visitor.when(cil.SetAttribNode) def visit(self, node): self.memo.save() reg1 = self.memo.get_unused_reg() reg2 = self.memo.get_unused_reg() - + instance_offset = self.get_offset(node.instance) - self.register_instruction(mips.LoadWordNode,reg1,instance_offset,fp) - + self.register_instruction(mips.LoadWordNode, reg1, instance_offset, fp) + value_offset = self.get_offset(node.value) - self.register_instruction(mips.LoadWordNode,reg2,value_offset,fp) - + self.register_instruction(mips.LoadWordNode, reg2, value_offset, fp) + attr_os = self.attr_offset[node.type][node.attr] - self.register_instruction(mips.StoreWordNode,reg2,attr_os,reg1) + self.register_instruction(mips.StoreWordNode, reg2, attr_os, reg1) self.memo.clean() - + @visitor.when(cil.DefaultValueNode) - def visit(self,node): + def visit(self, node): self.memo.save() reg = self.memo.get_unused_reg() dest_offset = self.get_offset(node.dest) - if node.type in [INT,BOOL]: - self.register_instruction(mips.LoadInmediate,reg,0) - self.register_instruction(mips.StoreWordNode,reg,dest_offset,fp) + if node.type in [INT, BOOL]: + self.register_instruction(mips.LoadInmediate, reg, 0) + self.register_instruction(mips.StoreWordNode, reg, dest_offset, fp) elif node.type == STRING: _size = STRING_SIZE - self.register_instruction(mips.LoadInmediate,v0,SYSCALL_SBRK) - self.register_instruction(mips.LoadInmediate,a0,_size) + self.register_instruction(mips.LoadInmediate, v0, SYSCALL_SBRK) + self.register_instruction(mips.LoadInmediate, a0, _size) self.register_instruction(mips.SyscallNode) - self.register_instruction(mips.StoreWordNode,v0,dest_offset,fp) + self.register_instruction(mips.StoreWordNode, v0, dest_offset, fp) reg = self.memo.get_unused_reg() - self.register_instruction(mips.LoadAddress,reg,STRING) - self.register_instruction(mips.StoreWordNode,reg,0,v0) - - self.register_instruction(mips.LoadInmediate,reg,0) - self.register_instruction(mips.StoreWordNode, reg, LENGTH_ATTR_OFFSET, v0) #pq en vo esta el allocate + self.register_instruction(mips.LoadAddress, reg, STRING) + self.register_instruction(mips.StoreWordNode, reg, 0, v0) + + self.register_instruction(mips.LoadInmediate, reg, 0) + self.register_instruction( + mips.StoreWordNode, reg, LENGTH_ATTR_OFFSET, v0 + ) # pq en vo esta el allocate self.register_instruction(mips.LoadAddress, reg, EMPTY_STRING) self.register_instruction(mips.StoreWordNode, reg, CHARS_ATTR_OFFSET, v0) else: self.register_instruction(mips.LoadAddress, reg, VOID) self.register_instruction(mips.StoreWordNode, reg, dest_offset, fp) - + self.memo.clean() - - + @visitor.when(cil.PlusNode) - def visit(self,node): + def visit(self, node): self.memo.save() reg_l = self.memo.get_unused_reg() reg_r = self.memo.get_unused_reg() reg_dest = self.memo.get_unused_reg() - + left_offset = self.get_offset(node.left) right_offset = self.get_offset(node.right) - - self.register_instruction(mips.LoadWordNode,reg_l,left_offset,fp) - self.register_instruction(mips.LoadWordNode,reg_r,right_offset,fp) - - self.register_instruction(mips.AddNode,reg_dest,reg_l,reg_r) - + + self.register_instruction(mips.LoadWordNode, reg_l, left_offset, fp) + self.register_instruction(mips.LoadWordNode, reg_r, right_offset, fp) + + self.register_instruction(mips.AddNode, reg_dest, reg_l, reg_r) + offset = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode,reg_dest,offset,fp) - + self.register_instruction(mips.StoreWordNode, reg_dest, offset, fp) + self.memo.clean() - + @visitor.when(cil.MinusNode) - def visit(self,node): + def visit(self, node): self.memo.save() reg_l = self.memo.get_unused_reg() reg_r = self.memo.get_unused_reg() reg_dest = self.memo.get_unused_reg() - + left_offset = self.get_offset(node.left) right_offset = self.get_offset(node.right) - - self.register_instruction(mips.LoadWordNode,reg_l,left_offset,fp) - self.register_instruction(mips.LoadWordNode,reg_r,right_offset,fp) - - self.register_instruction(mips.SubNode,reg_dest,reg_l,reg_r) - + + self.register_instruction(mips.LoadWordNode, reg_l, left_offset, fp) + self.register_instruction(mips.LoadWordNode, reg_r, right_offset, fp) + + self.register_instruction(mips.SubNode, reg_dest, reg_l, reg_r) + offset = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode,reg_dest,offset,fp) - + self.register_instruction(mips.StoreWordNode, reg_dest, offset, fp) + self.memo.clean() - + @visitor.when(cil.StarNode) - def visit(self,node): + def visit(self, node): self.memo.save() reg1 = self.memo.get_unused_reg() reg2 = self.memo.get_unused_reg() - - + left_offset = self.get_offset(node.left) right_offset = self.get_offset(node.right) - - self.register_instruction(mips.LoadWordNode,reg1,left_offset,fp) - self.register_instruction(mips.LoadWordNode,reg2,right_offset,fp) - - self.register_instruction(mips.MultNode,reg1,reg2) - + + self.register_instruction(mips.LoadWordNode, reg1, left_offset, fp) + self.register_instruction(mips.LoadWordNode, reg2, right_offset, fp) + + self.register_instruction(mips.MultNode, reg1, reg2) + dest_offset = self.get_offset(node.dest) - self.register_instruction(mips.MoveFromHi,reg1) - self.register_instruction(mips.StoreWordNode,reg1,dest_offset,fp) - + self.register_instruction(mips.MoveFromHi, reg1) + self.register_instruction(mips.StoreWordNode, reg1, dest_offset, fp) + self.memo.clean() - + @visitor.when(cil.DivNode) - def visit(self,node): + def visit(self, node): self.memo.save() reg1 = self.memo.get_unused_reg() reg2 = self.memo.get_unused_reg() - - + left_offset = self.get_offset(node.left) right_offset = self.get_offset(node.right) - - self.register_instruction(mips.LoadWordNode,reg1,left_offset,fp) - self.register_instruction(mips.LoadWordNode,reg2,right_offset,fp) - - self.register_instruction(mips.DivideNode,reg1,reg2) - + + self.register_instruction(mips.LoadWordNode, reg1, left_offset, fp) + self.register_instruction(mips.LoadWordNode, reg2, right_offset, fp) + + self.register_instruction(mips.DivideNode, reg1, reg2) + dest_offset = self.get_offset(node.dest) - self.register_instruction(mips.MoveFromLo,reg1) - self.register_instruction(mips.StoreWordNode,reg1,dest_offset,fp) - + self.register_instruction(mips.MoveFromLo, reg1) + self.register_instruction(mips.StoreWordNode, reg1, dest_offset, fp) + self.memo.clean() - - - #PENDIENTEEEEEEEE + + # PENDIENTEEEEEEEE @visitor.when(cil.CopyNode) - def visit(self,node): - self.register_instruction(mips.CommentNode,"CopyNode") - - self.register_instruction(mips.CommentNode,"Printing Abort Message") - self.register_instruction(mips.LoadAddress,a0,ABORT_SIGNAL) - self.register_instruction(mips.LoadInmediate,v0,SYSCALL_PRINT_STR) + def visit(self, node): + self.register_instruction(mips.CommentNode, "CopyNode") + + self.register_instruction(mips.CommentNode, "Printing Abort Message") + self.register_instruction(mips.LoadAddress, a0, ABORT_SIGNAL) + self.register_instruction(mips.LoadInmediate, v0, SYSCALL_PRINT_STR) + self.register_instruction(mips.SyscallNode) + + self.register_instruction(mips.CommentNode, "Aborting execution") + self.register_instruction(mips.LoadInmediate, v0, SYSCALL_EXIT) self.register_instruction(mips.SyscallNode) - - self.register_instruction(mips.CommentNode,"Aborting execution") - self.register_instruction(mips.LoadInmediate,v0,SYSCALL_EXIT) - self.register_instruction(mips.SyscallNode) - - #READSTRING + + # READSTRING @visitor.when(cil.ReadNode) - def visit(self,node): + def visit(self, node): self.memo.save() - self.register_instruction(mips.CommentNode,"ReadStrNode") - self.register_instruction(mips.CommentNode,"Reading String to buffer") + self.register_instruction(mips.CommentNode, "ReadStrNode") + self.register_instruction(mips.CommentNode, "Reading String to buffer") self.register_instruction(mips.LoadAddress, a0, INPUT_STR_BUFFER) self.register_instruction(mips.LoadInmediate, a1, BUFFER_SIZE) self.register_instruction(mips.LoadInmediate, v0, SYSCALL_READ_STR) self.register_instruction(mips.SyscallNode) - self.register_instruction(mips.CommentNode,"Saving reference to read string") + self.register_instruction(mips.CommentNode, "Saving reference to read string") reg1 = self.memo.get_unused_reg() if reg1 != t1: if t1 in self.memo.used_reg: - self.register_instruction(mips.MoveNode,reg1,t1) + self.register_instruction(mips.MoveNode, reg1, t1) else: self.memo.clean() self.register_instruction(mips.MoveNode, t1, a0) - self.register_instruction(mips.CommentNode,"Calculating str length") + self.register_instruction(mips.CommentNode, "Calculating str length") self.register_instruction(mips.JumpAndLink, LENGTH) - - self.register_instruction(mips.CommentNode,"Allocating char array for new string") + self.register_instruction( + mips.CommentNode, "Allocating char array for new string" + ) self.register_instruction(mips.LoadInmediate, v0, SYSCALL_SBRK) self.register_instruction(mips.SyscallNode) if t0 in self.memo.used_reg: reg2 = self.memo.get_unused_reg() - self.register_instruction(mips.MoveNode,reg2,t0) + self.register_instruction(mips.MoveNode, reg2, t0) self.register_instruction(mips.MoveNode, t0, v0) - + reg3 = self.memo.get_unused_reg() - self.register_instruction(mips.MoveNode, reg3, v0)#saving pointer to char array + self.register_instruction( + mips.MoveNode, reg3, v0 + ) # saving pointer to char array reg4 = self.memo.get_unused_reg() self.register_instruction(mips.AddNode, a0, a0, -1) - self.register_instruction(mips.MoveNode, reg4, a0)#saving length + self.register_instruction(mips.MoveNode, reg4, a0) # saving length - self.register_instruction(mips.CommentNode,"Copying bytes from one char array to another") + self.register_instruction( + mips.CommentNode, "Copying bytes from one char array to another" + ) self.register_instruction(mips.JumpAndLink, COPY) - self.register_instruction(mips.CommentNode,"Null-terminating the string") + self.register_instruction(mips.CommentNode, "Null-terminating the string") self.register_instruction(mips.StoreByteNode, zero, 0, t0) - self.register_instruction(mips.CommentNode,"Allocating new String instance") + self.register_instruction(mips.CommentNode, "Allocating new String instance") _size = STRING_SIZE - self.register_instruction(mips.LoadInmediate,v0,SYSCALL_SBRK) - self.register_instruction(mips.LoadInmediate,a0,_size) + self.register_instruction(mips.LoadInmediate, v0, SYSCALL_SBRK) + self.register_instruction(mips.LoadInmediate, a0, _size) self.register_instruction(mips.SyscallNode) - + dest_offset = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode,v0,dest_offset,fp) + self.register_instruction(mips.StoreWordNode, v0, dest_offset, fp) reg = self.memo.get_unused_reg() - self.register_instruction(mips.LoadAddress,reg,STRING) - self.register_instruction(mips.StoreWordNode,reg,0,v0) + self.register_instruction(mips.LoadAddress, reg, STRING) + self.register_instruction(mips.StoreWordNode, reg, 0, v0) - #storing string length - self.register_instruction(mips.CommentNode,"Storing length and reference to char array") + # storing string length + self.register_instruction( + mips.CommentNode, "Storing length and reference to char array" + ) self.register_instruction(mips.StoreWordNode, reg4, LENGTH_ATTR_OFFSET, v0) - #storing string chars ref + # storing string chars ref self.register_instruction(mips.StoreWordNode, reg3, CHARS_ATTR_OFFSET, v0) self.memo.clean() - + @visitor.when(cil.PrintStrNode) - def visit(self,node): - self.register_instruction(mips.CommentNode,"PrintStringNode") + def visit(self, node): + self.register_instruction(mips.CommentNode, "PrintStringNode") straddr_offset = self.get_offset(node.str_addr) self.register_instruction(mips.LoadWordNode, a0, straddr_offset, fp) self.register_instruction(mips.LoadWordNode, a0, CHARS_ATTR_OFFSET, a0) self.register_instruction(mips.LoadInmediate, v0, SYSCALL_PRINT_STR) self.register_instruction(mips.SyscallNode) - + @visitor.when(cil.PrintIntNode) - def visit(self,node): - self.register_instruction(mips.CommentNode,"PrintIntNode") - if isinstance(node.int_addr,int): - self.register_instruction(mips.LoadInmediate,a0,node.int_addr) + def visit(self, node): + self.register_instruction(mips.CommentNode, "PrintIntNode") + if isinstance(node.int_addr, int): + self.register_instruction(mips.LoadInmediate, a0, node.int_addr) else: int_offset = self.get_offset(node.int_addr) self.register_instruction(mips.LoadWordNode, a0, int_offset, fp) self.register_instruction(mips.LoadInmediate, v0, SYSCALL_PRINT_INT) self.register_instruction(mips.SyscallNode) - - #Incompleto + + # Incompleto @visitor.when(cil.TypeOfNode) - def visit(self,node): - #self.memo.save() - - #reg1 = self.get_offset() - #reg2 = self.get_offset() + def visit(self, node): + # self.memo.save() + + # reg1 = self.get_offset() + # reg2 = self.get_offset() pass - - + @visitor.when(cil.TypeNameNode) - def visit(self,node): + def visit(self, node): pass - - + @visitor.when(cil.ToStrNode) - def visit(self,node): + def visit(self, node): pass - + @visitor.when(cil.LengthNode) - def visit(self,node): + def visit(self, node): pass + @visitor.when(cil.ConcatNode) - def visit(self,node): + def visit(self, node): pass + @visitor.when(cil.SubstringNode) - def visit(self,node): - pass - + def visit(self, node): + pass + @visitor.when(cil.PrefixNode) - def visit(self,node): + def visit(self, node): pass - + @visitor.when(cil.GotoIfNode) - def visit(self,node): + def visit(self, node): pass - - @visitor.when(cil.LocalNode) #No hace falta - def visit(self,node): + + @visitor.when(cil.LocalNode) # No hace falta + def visit(self, node): pass - - - - - - \ No newline at end of file diff --git a/src/code_gen/mips_nodes.py b/src/code_gen/mips_nodes.py index 7192c622c..3bc3925e1 100644 --- a/src/code_gen/mips_nodes.py +++ b/src/code_gen/mips_nodes.py @@ -1,10 +1,10 @@ -#from re import L -#from soupsieve import select +# from re import L +# from soupsieve import select -#from src.cmp.cil import InstructionNode +# from src.cmp.cil import InstructionNode -from matplotlib.pyplot import cla +# from matplotlib.pyplot import cla class MIPS_Node: @@ -16,56 +16,67 @@ def __init__(self, data, code): self.data = data self.text = code + class DataNode(MIPS_Node): - pass - + pass + + class InstructionNode(MIPS_Node): - pass - + pass + + class DataTransferNode(InstructionNode): pass + class ProcedureNode(InstructionNode): def __init__(self, label): self.label = label self.instructions = [] - class DataTransferWithOffset(DataTransferNode): - def __init__(self,source,offset,dest): + def __init__(self, source, offset, dest): self.source = source self.offset = offset self.destination = dest - + + class LoadWordNode(DataTransferWithOffset): def __str__(self): - return f'lw {self.source}, {str(self.offset)}({self.destination})' - + return f"lw {self.source}, {str(self.offset)}({self.destination})" + + class LoadByteNode(DataTransferWithOffset): def __str__(self): - return f'lb {self.source}, {str(self.offset)}({self.destination})' - + return f"lb {self.source}, {str(self.offset)}({self.destination})" + + class StoreWordNode(DataTransferWithOffset): def __str__(self): - return f'sw {self.source}, {str(self.offset)}({self.destination})' - + return f"sw {self.source}, {str(self.offset)}({self.destination})" + + class StoreByteNode(DataTransferWithOffset): def __str__(self): - return f'sb {self.source}, {str(self.offset)}({self.destination})' - + return f"sb {self.source}, {str(self.offset)}({self.destination})" + + class LoadNode(DataTransferNode): - def __init__(self,dest,value): + def __init__(self, dest, value): self.destination = dest self.value = value + class LoadInmediate(LoadNode): def __str__(self): - return f'li {self.destination}, {self.value}' + return f"li {self.destination}, {self.value}" + class LoadAddress(LoadNode): def __str__(self): - return f'la {self.destination}, {self.value}' + return f"la {self.destination}, {self.value}" + class MoveNode(DataTransferNode): def __init__(self, destination, source): @@ -77,7 +88,7 @@ def __str__(self): class DataTypeNode(DataNode): - def __init__(self,datatype,name,vt_values): + def __init__(self, datatype, name, vt_values): self.datatype = datatype self.name = name self.vt_values = vt_values @@ -87,127 +98,152 @@ def __str__(self): for value in self.vt_values: values += f", {value}" return f"{self.name} : {self.datatype}{values}" - + + class ArithAnfLogicNode(InstructionNode): - def __init__(self, destination,left,right): + def __init__(self, destination, left, right): self.destination = destination self.left = left self.right = right - + + class AddNode(ArithAnfLogicNode): def __str__(self): - return f"add {self.destination}, {self.left}, {self.right}" + return f"add {self.destination}, {self.left}, {self.right}" + class AddiNode(ArithAnfLogicNode): def __str__(self): return f"addi {self.destination}, {self.left}, {self.right}" + class SubNode(ArithAnfLogicNode): def __str__(self): return f"sub {self.destination}, {self.left}, {self.right}" + class HiLoOperationNode(InstructionNode): - def __init__(self,left,right): + def __init__(self, left, right): self.left = left self.right = right - + + class MultNode(HiLoOperationNode): - def __str__(self): - return f'mult {self.left}, {self.right}' + def __str__(self): + return f"mult {self.left}, {self.right}" + class DivideNode(HiLoOperationNode): - def __str__(self): - return f'div {self.left}, {self.right}' + def __str__(self): + return f"div {self.left}, {self.right}" + class MoveFromHi(InstructionNode): - def __init__(self,register): + def __init__(self, register): self.register = register - + def __str__(self): - return f'mfhi {self.register}' - + return f"mfhi {self.register}" + + class MoveFromLo(InstructionNode): - def __init__(self,register): + def __init__(self, register): self.register = register - + def __str__(self): - return f'mflo {self.register}' - + return f"mflo {self.register}" + + class ConditionalBranch(InstructionNode): - def __init__(self,c1,c2,jump): + def __init__(self, c1, c2, jump): self.c1 = c1 self.c2 = c2 self.jump = jump - + + class BranchOnEqualNode(ConditionalBranch): def __str__(self): return f"beq {self.c1}, {self.c2}, {self.jump}" - + + class BranchOnNotEqualNode(ConditionalBranch): def __str__(self): return f"bne {self.c1}, {self.c2}, {self.jump}" + class BranchOnGreaterThanNode(ConditionalBranch): def __str__(self): return f"bgt {self.c1}, {self.c2}, {self.jump}" + class BranchOnGreaterOrEqNode(ConditionalBranch): def __str__(self): return f"bge {self.c1}, {self.c2}, {self.jump}" + class BranchOnLessThanNode(ConditionalBranch): def __str__(self): return f"blt {self.c1}, {self.c2}, {self.jump}" - + + class BranchOnLessOrEqNode(ConditionalBranch): def __str__(self): return f"ble {self.c1}, {self.c2}, {self.jump}" + class ComparisonNode(InstructionNode): - def __init__(self,m1,m2,dest): + def __init__(self, m1, m2, dest): self.m1 = m1 self.m2 = m2 self.destination = dest - + + class SetOnLessThan(ComparisonNode): def __str__(self): return f"slt {self.dest}, {self.m1}, {self.m2}" - + + class SetOnLessThanInmediate(ComparisonNode): def __str__(self): return f"slt {self.dest}, {self.m1}, {self.m2}" - + + class UnconditionalJumpNode(InstructionNode): - def __init__(self,jump): + def __init__(self, jump): self.jump = jump - + + class Jump(UnconditionalJumpNode): def __str__(self): - return f"j {self.jump}" + return f"j {self.jump}" + class JumpRegister(UnconditionalJumpNode): def __str__(self): - return f"jr {self.jump}" + return f"jr {self.jump}" + class JumpAndLink(UnconditionalJumpNode): def __str__(self): - return f"jal {self.jump}" + return f"jal {self.jump}" + class Label(InstructionNode): - def __init__(self,label): + def __init__(self, label): self.label = label - + def __str__(self): return f"{self.label}:" - + + class SyscallNode(InstructionNode): def __str__(self): return f"syscall" - + class CommentNode(MIPS_Node): - def __init__(self,text): + def __init__(self, text): self.text = text - + def __str__(self): - return f"#{self.text}" \ No newline at end of file + return f"#{self.text}" From d24d6958ab4e99456949296e2c721d4f8e8dfce6 Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Sat, 5 Mar 2022 18:06:17 -0500 Subject: [PATCH 094/162] feat: add data to LoadNode --- src/cmp/cil.py | 2 +- src/cmp/semantic.py | 3 ++- src/code_gen/cil_builder.py | 3 +-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cmp/cil.py b/src/cmp/cil.py index 43cb7ee9a..197ae0427 100644 --- a/src/cmp/cil.py +++ b/src/cmp/cil.py @@ -426,7 +426,7 @@ def visit(self, node): @visitor.when(LoadNode) def visit(self, node): - return f"{node.dest} = LOAD {node.msg}" + return f"{node.dest} = LOAD {node.msg.name}" @visitor.when(ConcatNode) def visit(self, node): diff --git a/src/cmp/semantic.py b/src/cmp/semantic.py index 22f6e9092..4f3d3a9ac 100644 --- a/src/cmp/semantic.py +++ b/src/cmp/semantic.py @@ -263,9 +263,10 @@ def __copy__(self): class VariableInfo: - def __init__(self, name, vtype=None, is_attr=False): + def __init__(self, name, vtype=None, is_attr=False, data=None): self.name = name self.type = vtype + self.data = data self.is_attr = is_attr self.offset = None diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index 58a7cf194..c52bb27b2 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -495,7 +495,6 @@ def visit(self, node): if not node.at_type else self.to_function_name(node.id, node.at_type) ) - if node.obj: self.visit(node.obj) @@ -721,7 +720,7 @@ def visit(self, node): idx = self.generate_next_string_id() self.data.append(DataNode(idx, node.lex)) solve = self.define_internal_local() - self.register_instruction(LoadNode(solve, idx)) + self.register_instruction(LoadNode(solve, VariableInfo(idx, False, node.lex))) return solve @visitor.when(cool.BooleanNode) From f5102e2c9d568b0ec06837237b9cc70ac67e17ab Mon Sep 17 00:00:00 2001 From: smartos99 Date: Sat, 5 Mar 2022 18:13:06 -0500 Subject: [PATCH 095/162] Fix Order of SetAttr args in cil_builder --- src/code_gen/cil_builder.py | 8 +- src/code_gen/mips_builder.py | 802 ++++++++++++++++++----------------- 2 files changed, 412 insertions(+), 398 deletions(-) diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index 58a7cf194..51eb08556 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -185,10 +185,10 @@ def build_constructor(self, node): self.register_instruction(DefaultValueNode(default_var, attr.type)) self.register_instruction( SetAttribNode( - node.id, + self_var, self.to_attr_name(self.current_type.name, attr.id), default_var, - self_var, + node.id, ) ) @@ -197,10 +197,10 @@ def build_constructor(self, node): init_expr_value = self.visit(attr.init_exp) self.register_instruction( SetAttribNode( - node.id, + self_var, self.to_attr_name(self.current_type.name, attr.id), init_expr_value, - self_var, + node.id, ) ) diff --git a/src/code_gen/mips_builder.py b/src/code_gen/mips_builder.py index 012c22baf..027fa0094 100644 --- a/src/code_gen/mips_builder.py +++ b/src/code_gen/mips_builder.py @@ -1,29 +1,35 @@ -# from soupsieve import select +#from atexit import register +#from email.quoprimime import body_length +#from operator import le +#from tkinter.tix import Select +#from soupsieve import select import cmp.visitor as visitor import cmp.cil as cil import random from code_gen import mips_nodes as mips -# type_info offsets + + +#type_info offsets TYPENAME_OFFSET = 0 FUNCTION_OFFSET = 4 RA_OFFSET = 8 OLD_FP_OFFSET = 4 -# str attributes offsets +#str attributes offsets LENGTH_ATTR_OFFSET = 4 CHARS_ATTR_OFFSET = 8 -FP_ARGS_DISTANCE = 3 # how far finishes $fp from arguments in method call -FP_LOCALS_DISTANCE = 0 # how far finishes $fp from localvars in method call +FP_ARGS_DISTANCE = 3 # how far finishes $fp from arguments in method call +FP_LOCALS_DISTANCE = 0 # how far finishes $fp from localvars in method call -ABORT_SIGNAL = "abort_signal" # CIL -CASE_MISSMATCH = "case_missmatch" # CIL -CASE_VOID = "case_on_void" # MIPS -DISPATCH_VOID = "dispatch_on_void" # MIPS -ZERO_DIVISION = "division_by_zero" # MIPS -SUBSTR_OUT_RANGE = "substr_out_of_range" # MIPS +ABORT_SIGNAL = "abort_signal"#CIL +CASE_MISSMATCH = "case_missmatch"#CIL +CASE_VOID = "case_on_void"#MIPS +DISPATCH_VOID = "dispatch_on_void"#MIPS +ZERO_DIVISION = "division_by_zero"#MIPS +SUBSTR_OUT_RANGE = "substr_out_of_range"#MIPS HEAP_OVERFLOW = "heap_overflow" STRING_SIZE = 12 VOID = "void" @@ -34,27 +40,27 @@ INPUT_STR_BUFFER = "input_str_buffer" BUFFER_SIZE = 1024 -# temporary registers +#temporary registers t0 = "$t0" t1 = "$t1" t2 = "$t2" t3 = "$t3" t4 = "$t4" t5 = "$t5" -t6 = "$t6" # convenios -t7 = "$t7" # convenios -t8 = "$t8" -t9 = "$t9" +t6 = "$t6" # convenios +t7 = "$t7" # convenios +t8 = "$t8" +t9 = "$t9" -# Arguments Registers +#Arguments Registers a0 = "$a0" a1 = "$a1" a2 = "$a2" a3 = "$a3" -# frame pointer +#frame pointer fp = "$fp" -# stack pointer +#stack pointer sp = "$sp" ra = "$ra" @@ -81,27 +87,25 @@ OBJECT = "Object" IO = "IO" - class MemoryManager: def __init__(self): - self.all_reg = [t0, t1, t2, t3, t4, t5, t6, t7, t8, t9] + self.all_reg = [t0,t1,t2,t3,t4,t5,t6,t7,t8,t9] self.used_reg = [] self.stored = [] - + def get_unused_reg(self): - unused = list(set(self.all_reg) - set(self.used_reg)) + list( - set(self.used_reg) - set(self.all_reg) - ) - reg = random.choice(unused) + unused = list(set(self.all_reg) - set(self.used_reg)) + list(set(self.used_reg) - set(self.all_reg)) + reg = random.choice(unused) self.used_reg.append(reg) return reg - + def clean(self): self.used_reg = self.stored self.stored = [] - + def save(self): self.stored = self.used_reg.copy() + class MIPSBuilder: @@ -118,67 +122,55 @@ def __init__(self): self.attr_offset = {} self.memo = MemoryManager() self.pushed_args = 0 - - def get_offset(self, x): + + + def get_offset(self,x): if x in self.locals: index = self.locals.index(x) - return -4 * index + return -4*index elif x in self.params: index = self.params.index(x) - return (-4 * (len(self.locals) + len(self.params))) + 4 - + return (-4 * (len(self.locals)+len(self.params)))+4 + def register_instruction(self, instruction_type, *args): instruction = instruction_type(*args) - self.current_procedure.instructions.append(instruction) - - def register_data(self, data_type, *args): + self.current_procedure.instructions.append(instruction) + + def register_data(self,data_type,*args): data = data_type(*args) self.data.append(data) - + + def register_push(self, reg): self.register_instruction(mips.StoreWordNode, reg, 0, sp) self.register_instruction(mips.AddiNode, sp, sp, -4) def register_pop(self, reg): self.register_instruction(mips.LoadWordNode, reg, 4, sp) - self.register_instruction(mips.AddiNode, sp, sp, 4) - + self.register_instruction(mips.AddiNode, sp, sp, 4) + def generate_exception_messages(self): - self.register_data( - mips.DataTypeNode, ABORT_SIGNAL, ".asciiz", ['"Program execution aborted"'] - ) - self.register_data( - mips.DataTypeNode, - CASE_MISSMATCH, - ".asciiz", - ['"Execution of a case statement without a matching branch"'], - ) - self.register_data(mips.DataTypeNode, CASE_VOID, ".asciiz", ['"Case on void"']) - self.register_data( - mips.DataTypeNode, DISPATCH_VOID, ".asciiz", ['"Dispatch on void"'] - ) - self.register_data( - mips.DataTypeNode, ZERO_DIVISION, ".asciiz", ['"Division by zero"'] - ) - self.register_data( - mips.DataTypeNode, SUBSTR_OUT_RANGE, ".asciiz", ['"Substring out of range"'] - ) - self.register_data( - mips.DataTypeNode, HEAP_OVERFLOW, ".asciiz", ['"Heap overflow"'] - ) - - def generate_attr_offset(self, type): + self.register_data(mips.DataTypeNode, ABORT_SIGNAL, '.asciiz', ['"Program execution aborted"']) + self.register_data(mips.DataTypeNode, CASE_MISSMATCH, '.asciiz', ['"Execution of a case statement without a matching branch"']) + self.register_data(mips.DataTypeNode, CASE_VOID, '.asciiz', ['"Case on void"']) + self.register_data(mips.DataTypeNode, DISPATCH_VOID, '.asciiz', ['"Dispatch on void"']) + self.register_data(mips.DataTypeNode, ZERO_DIVISION, '.asciiz', ['"Division by zero"']) + self.register_data(mips.DataTypeNode, SUBSTR_OUT_RANGE, '.asciiz', ['"Substring out of range"']) + self.register_data(mips.DataTypeNode, HEAP_OVERFLOW, '.asciiz', ['"Heap overflow"']) + + + def generate_attr_offset(self,type): attributes = self.types[type].attributes - self.attr_offset[type] = {} - for i, attr in enumerate(attributes): - self.attr_offset[type][attr] = 4 * (i + 1) - + self.attr_offset[type]={} + for i,attr in enumerate(attributes): + self.attr_offset[type][attr] = 4*(i+1) + def generate_str_length(self): - # calculates the length of the null-terminated char array referenced by $a0 and stores it in $a0 + #calculates the length of the null-terminated char array referenced by $a0 and stores it in $a0 self.memo.save() reg1 = self.memo.get_unused_reg() reg2 = self.memo.get_unused_reg() - + self.current_procedure = mips.ProcedureNode(LENGTH) self.register_instruction(mips.LoadInmediate, reg1, 0) @@ -196,610 +188,632 @@ def generate_str_length(self): self.register_instruction(mips.Jump, ra) self.text.append(self.current_procedure) - - # def register_main_allocation(self): + + #def register_main_allocation(self): # self.register_instruction(mips.CommentNode,"Allocating Main instance") # self.register_instruction(mips.MoveNode,fp,sp) # self.register_instruction(mips.AddiNode,sp,sp,-4) - # + # # self.register_instruction(mips.CommentNode,"Allocating Main instance") # #Allocate # self.register_instruction(mips.LoadInmediate,v0,SYSCALL_SBRK) # self.register_instruction(mips.LoadInmediate,a0,self.main_size) # self.register_instruction(mips.SyscallNode) # self.register_instruction(mips.StoreWordNode,v0,0,fp) - # + # # self.register_instruction(mips.CommentNode,"Calling Main Constructor") # self.register_push(fp) # self.register_instruction(mips.JumpAndLink,"Main_constructor") - + + @visitor.on("node") def visit(self, node=None): pass - + @visitor.when(cil.ProgramNode) def visit(self, node): for type in node.dottypes: self.visit(type) self.generate_attr_offset(type.name) - + + self.generate_exception_messages() - + for str_data in node.dotdata: self.visit(str_data) - + for instruction in node.dotcode: self.visit(instruction) - - return mips.ProgramNode(self.data, self.text) + + + return mips.ProgramNode(self.data,self.text) + @visitor.when(cil.TypeNode) def visit(self, node): self.types[node.name] = node if node.name == "Main": - self.main_size = (len(node.attributes) + 1) * 4 + self.main_size = (len(node.attributes)+1)*4 values = [] for func in node.methods: values.append(func[1]) - - self.register_data(mips.DataTypeNode, ".word", node.name, values) - self.register_data( - mips.DataTypeNode, f"{node.name}_cname", ".asciiz", [f'"{node.name}"'] - ) - - # Filling type type info - # self.register_instruction(mips.CommentNode(f"Filling {node.name} VT")) - # self.register_instruction(mips.LoadAddress,t0,node.name) - # self.register_instruction(mips.LoadAddress,t1,f'{node.name}_cname') - - # self.register_instruction(mips.StoreWordNode,t1,TYPENAME_OFFSET,t0) - - # Filling type VT - # for i,func in enumerate(node.methods): + + self.register_data(mips.DataTypeNode,'.word',node.name,values) + self.register_data(mips.DataTypeNode, f'{node.name}_cname','.asciiz', [f'"{node.name}"']) + + + #Filling type type info + #self.register_instruction(mips.CommentNode(f"Filling {node.name} VT")) + #self.register_instruction(mips.LoadAddress,t0,node.name) + #self.register_instruction(mips.LoadAddress,t1,f'{node.name}_cname') + + #self.register_instruction(mips.StoreWordNode,t1,TYPENAME_OFFSET,t0) + + #Filling type VT + #for i,func in enumerate(node.methods): # offset = FUNCTION_OFFSET*i # self.register_instruction(mips.LoadAddress,t1,func.name) # self.register_instruction(mips.StoreWordNode,t1,offset,t0) - + @visitor.when(cil.DataNode) def visit(self, node): - self.register_data(mips.DataTypeNode, ".ascii", node.name, [node.value]) + self.register_data(mips.DataTypeNode,'.ascii',node.name,[node.value]) + + @visitor.when(cil.ParamNode) - def visit(self, node): + def visit(self,node): self.memo.save() reg = self.memo.get_unused_reg() - + self.params.append(node.name) - - self.register_instruction(mips.LoadInmediate, reg, node.name) - self.register_instruction(mips.StoreWordNode, reg, len(self.params) * 4, fp) - + + self.register_instruction(mips.LoadInmediate,reg,node.name) + self.register_instruction(mips.StoreWordNode,reg,len(self.params)*4,fp) + self.memo.clean() - - @visitor.when(cil.ArgNode) - def visit(self, node): + + + @visitor.when(cil.ArgNode) + def visit(self,node): self.memo.save() reg = self.memo.get_unused_reg() - + offset = self.get_offset(node.name) - self.register_instruction(mips.LoadWordNode, reg, offset, fp) + self.register_instruction(mips.LoadWordNode,reg,offset,fp) self.register_push(reg) self.pushed_args += 1 - + self.memo.clean() - + + + @visitor.when(cil.FunctionNode) - def visit(self, node): - + def visit(self,node): + locals_save = self.locals params_save = self.params self.locals, self.params = [], [] self.current_procedure = mips.ProcedureNode(node.name) - self.register_instruction(mips.CommentNode, "Pushing $ra") + self.register_instruction(mips.CommentNode,"Pushing $ra") self.register_push(ra) - self.register_instruction(mips.CommentNode, "Saving $fp") + self.register_instruction(mips.CommentNode,"Saving $fp") self.register_push(fp) - self.register_instruction(mips.CommentNode, "New $fp") + self.register_instruction(mips.CommentNode,"New $fp") self.register_instruction(mips.MoveNode, fp, sp) - - self.register_instruction(mips.CommentNode, "Reserving space for locals") - self.register_instruction(mips.AddiNode, sp, sp, -4 * len(node.localvars)) + + self.register_instruction(mips.CommentNode,"Reserving space for locals") + self.register_instruction(mips.AddiNode, sp, sp, -4*len(node.localvars)) for local in node.localvars: self.locals.append(local.name) - + for param in node.params: self.params.append(param.name) - self.register_instruction(mips.CommentNode, "Executing instructions") + self.register_instruction(mips.CommentNode,"Executing instructions") for inst in node.instructions: self.visit(inst) - - self.register_instruction(mips.CommentNode, "Restoring saved $ra") - self.register_instruction(mips.LoadWordNode, ra, RA_OFFSET, fp) # stored $ra - - self.register_instruction(mips.CommentNode, "Restoring saved $fp") - self.register_instruction( - mips.LoadWordNode, fp, OLD_FP_OFFSET, fp - ) # stored (old)$fp - - AR = 4 * (len(node.localvars) + len(node.params) + 2) - # AR = 4*(len(node.localvars) + 2) - - self.register_instruction(mips.CommentNode, "Cleaning stack after call") + + + self.register_instruction(mips.CommentNode,"Restoring saved $ra") + self.register_instruction(mips.LoadWordNode, ra, RA_OFFSET, fp)#stored $ra + + + self.register_instruction(mips.CommentNode,"Restoring saved $fp") + self.register_instruction(mips.LoadWordNode, fp, OLD_FP_OFFSET, fp)#stored (old)$fp + + AR = 4*(len(node.localvars) + len(node.params) + 2) + #AR = 4*(len(node.localvars) + 2) + + self.register_instruction(mips.CommentNode,"Cleaning stack after call") self.register_instruction(mips.AddiNode, sp, sp, AR) - - self.register_instruction(mips.CommentNode, "Return jump") + + self.register_instruction(mips.CommentNode,"Return jump") self.register_instruction(mips.JumpRegister, ra) self.text.append(self.current_procedure) self.locals = locals_save - self.params = params_save - - # @visitor.when(cil.LoadNode) - # def visit(self,node): + self.params = params_save + + + #@visitor.when(cil.LoadNode) + #def visit(self,node): # self.memo.save() # reg = self.memo.used_reg() - # + # # if isinstance(node.msg,int): # self.register_instruction(mips.LoadInmediate,reg,node.msg) # else: # self.register_instruction(mips.LoadAddress,reg,node.msg) - # + # # offset = self.get_offset(node.dest) # self.register_instruction(mips.StoreWordNode,reg,offset,fp) # self.memo.clean() - + @visitor.when(cil.LoadNode) def visit(self, node: cil.LoadNode): self.memo.save() _size = STRING_SIZE - self.register_instruction(mips.LoadInmediate, v0, SYSCALL_SBRK) - self.register_instruction(mips.LoadInmediate, a0, _size) + self.register_instruction(mips.LoadInmediate,v0,SYSCALL_SBRK) + self.register_instruction(mips.LoadInmediate,a0,_size) self.register_instruction(mips.SyscallNode) - + dest_offset = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode, v0, dest_offset, fp) + self.register_instruction(mips.StoreWordNode,v0,dest_offset,fp) reg = self.memo.get_unused_reg() - self.register_instruction(mips.LoadAddress, reg, STRING) - self.register_instruction(mips.StoreWordNode, reg, 0, v0) + self.register_instruction(mips.LoadAddress,reg,STRING) + self.register_instruction(mips.StoreWordNode,reg,0,v0) - # storing string length - self.register_instruction(mips.LoadInmediate, reg, len(node.msg)) + #storing string length + self.register_instruction(mips.LoadInmediate, reg, len(node.msg.data)) self.register_instruction(mips.StoreWordNode, reg, LENGTH_ATTR_OFFSET, v0) - # storing string chars ref - self.register_instruction(mips.LoadAddress, reg, node.msg) + #storing string chars ref + self.register_instruction(mips.LoadAddress, reg, node.msg.name) self.register_instruction(mips.StoreWordNode, reg, CHARS_ATTR_OFFSET, v0) self.memo.clean() - + @visitor.when(cil.LengthNode) def visit(self, node): self.memo.save() reg = self.memo.get_unused_reg() source_offset = self.get_offset(node.source) - self.register_instruction(mips.LoadNode, reg, source_offset, fp) + self.register_instruction(mips.LoadNode, reg,source_offset, fp) self.register_instruction(mips.LoadWordNode, reg, LENGTH_ATTR_OFFSET, reg) dest_offset = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode, reg, dest_offset, fp) - - # All return value is saved in register a1 + self.register_instruction(mips.StoreWordNode, reg,dest_offset, fp) + + + #All return value is saved in register a1 @visitor.when(cil.ReturnNode) - def visit(self, node): - if isinstance(node.value, int): - self.register_instruction(mips.LoadInmediate, a1, node.value) - else: + def visit(self,node): + if isinstance(node.value,int): + self.register_instruction(mips.LoadInmediate,a1,node.value) + else: offset = self.get_offset(node.value) - self.register_instruction(mips.LoadWordNode, a1, offset, fp) - + self.register_instruction(mips.LoadWordNode,a1,offset,fp) + @visitor.when(cil.GotoNode) - def visit(self, node): - self.register_instruction(mips.UnconditionalJumpNode, node.label) - + def visit(self,node): + self.register_instruction(mips.UnconditionalJumpNode,node.label) + + + @visitor.when(cil.AllocateNode) - def visit(self, node): + def visit(self,node): self.memo.save() - _size = (len(self.types[node.type].attributes) + 1) * 4 - self.register_instruction(mips.LoadInmediate, v0, SYSCALL_SBRK) - self.register_instruction(mips.LoadInmediate, a0, _size) + _size = (len(self.types[node.type].attributes)+1)*4 + self.register_instruction(mips.LoadInmediate,v0,SYSCALL_SBRK) + self.register_instruction(mips.LoadInmediate,a0,_size) self.register_instruction(mips.SyscallNode) - + dest_offset = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode, v0, dest_offset, fp) - + self.register_instruction(mips.StoreWordNode,v0,dest_offset,fp) + reg = self.memo.get_unused_reg() - self.register_instruction(mips.LoadAddress, reg, node.type) - self.register_instruction(mips.StoreWordNode, reg, 0, v0) + self.register_instruction(mips.LoadAddress,reg,node.type) + self.register_instruction(mips.StoreWordNode,reg,0,v0) self.memo.clean() - + @visitor.when(cil.AssignNode) - def visit(self, node): + def visit(self,node): self.save() - + reg = self.memo.get_unused_reg() - + source_offset = self.get_offset(node.source) dest_offset = self.get_offset(node.dest) - - self.register_instruction(mips.LoadWordNode, reg, source_offset, fp) - - self.register_instruction(mips.StoreWordNode, reg, dest_offset, fp) - - self.memo.clean() - + + self.register_instruction(mips.LoadWordNode,reg,source_offset,fp) + + self.register_instruction(mips.StoreWordNode,reg,dest_offset,fp) + + self.memo.clean() + + @visitor.when(cil.PlusNode) - def visit(self, node): + def visit(self,node): self.save() - + reg1 = self.memo.get_unused_reg() reg2 = self.memo.get_unused_reg() reg3 = self.memo.get_unused_reg() - - self.register_instruction(mips.LoadInmediate, reg1, node.left) - self.register_instruction(mips.LoadInmediate, reg2, node.right) - - self.register_instruction(mips.AddNode, reg3, reg1, reg2) - + + self.register_instruction(mips.LoadInmediate,reg1,node.left) + self.register_instruction(mips.LoadInmediate,reg2,node.right) + + self.register_instruction(mips.AddNode,reg3,reg1,reg2) + offset = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode, reg3, offset, fp) - + self.register_instruction(mips.StoreWordNode,reg3,offset,fp) + self.memo.clean() - + @visitor.when(cil.MinusNode) - def visit(self, node): + def visit(self,node): self.save() - + reg1 = self.memo.get_unused_reg() reg2 = self.memo.get_unused_reg() reg3 = self.memo.get_unused_reg() - - self.register_instruction(mips.LoadInmediate, reg1, node.left) - self.register_instruction(mips.LoadInmediate, reg2, node.right) - - self.register_instruction(mips.SubNode, reg3, reg1, reg2) - + + self.register_instruction(mips.LoadInmediate,reg1,node.left) + self.register_instruction(mips.LoadInmediate,reg2,node.right) + + self.register_instruction(mips.SubNode,reg3,reg1,reg2) + offset = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode, reg3, offset, fp) - + self.register_instruction(mips.StoreWordNode,reg3,offset,fp) + self.memo.clean() - + @visitor.when(cil.RuntimeErrorNode) - def visit(self, node): - - self.register_instruction(mips.CommentNode, "Printing Abort Message") - self.register_instruction(mips.LoadAddress, a0, ABORT_SIGNAL) - self.register_instruction(mips.LoadInmediate, v0, SYSCALL_PRINT_STR) + def visit(self,node): + + self.register_instruction(mips.CommentNode,"Printing Abort Message") + self.register_instruction(mips.LoadAddress,a0,ABORT_SIGNAL) + self.register_instruction(mips.LoadInmediate,v0,SYSCALL_PRINT_STR) self.register_instruction(mips.SyscallNode) - - self.register_instruction(mips.CommentNode, "Aborting execution") - self.register_instruction(mips.LoadInmediate, v0, SYSCALL_EXIT) + + self.register_instruction(mips.CommentNode,"Aborting execution") + self.register_instruction(mips.LoadInmediate,v0,SYSCALL_EXIT) self.register_instruction(mips.SyscallNode) - + + @visitor.when(cil.StaticCallNode) - def visit(self, node): - - self.register_instruction(mips.JumpAndLink, node.function) - + def visit(self,node): + + self.register_instruction(mips.JumpAndLink,node.function) + dest_offset = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode, a1, dest_offset, fp) - self.register_instruction(mips.AddiNode, sp, sp, self.pushed_args * 4) + self.register_instruction(mips.StoreWordNode,a1,dest_offset,fp) + self.register_instruction(mips.AddiNode,sp,sp,self.pushed_args * 4) self.pushed_args = 0 - + + @visitor.when(cil.DynamicCallNode) - def visit(self, node): + def visit(self,node): self.memo.save() - + reg1 = self.memo.get_unused_reg() reg2 = self.memo.get_unused_reg() - + instance_offset = self.get_offset(node.instance) - self.register_instruction(mips.CommentNode, "Getting type of instance") - self.register_instruction(mips.LoadWordNode, reg1, instance_offset, fp) - - # getting method offset + self.register_instruction(mips.CommentNode,"Getting type of instance") + self.register_instruction(mips.LoadWordNode,reg1,instance_offset,fp) + + #getting method offset _methods = self.types[node.type].methods meth_offset = _methods.index(node.method) - self.register_instruction(mips.LoadWordNode, reg2, meth_offset * 4, reg1) - - self.register_instruction(mips.JumpAndLink, reg2) - - # putting the return vslue in destination + self.register_instruction(mips.LoadWordNode,reg2,meth_offset*4,reg1) + + self.register_instruction(mips.JumpAndLink,reg2) + + #putting the return vslue in destination dest_offset = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode, a1, dest_offset, fp) - + self.register_instruction(mips.StoreWordNode,a1,dest_offset,fp) + self.memo.clean() - + + + + + + @visitor.when(cil.GetAttribNode) def visit(self, node): self.memo.save() - + reg1 = self.memo.get_unused_reg() reg2 = self.memo.get_unused_reg() - + instance_offset = self.get_offset(node.instance) - self.register_instruction(mips.LoadWordNode, reg1, instance_offset, fp) - + self.register_instruction(mips.LoadWordNode,reg1,instance_offset,fp) + attr_offs = self.attr_offset[node.type][node.attr] - self.register_instruction(mips.LoadWordNode, reg2, attr_offs, reg1) - + self.register_instruction(mips.LoadWordNode,reg2,attr_offs,reg1) + dest_offs = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode, reg2, dest_offs, fp) - + self.register_instruction(mips.StoreWordNode,reg2,dest_offs,fp) + + @visitor.when(cil.SetAttribNode) def visit(self, node): self.memo.save() reg1 = self.memo.get_unused_reg() reg2 = self.memo.get_unused_reg() - + instance_offset = self.get_offset(node.instance) - self.register_instruction(mips.LoadWordNode, reg1, instance_offset, fp) - + self.register_instruction(mips.LoadWordNode,reg1,instance_offset,fp) + value_offset = self.get_offset(node.value) - self.register_instruction(mips.LoadWordNode, reg2, value_offset, fp) - + self.register_instruction(mips.LoadWordNode,reg2,value_offset,fp) + attr_os = self.attr_offset[node.type][node.attr] - self.register_instruction(mips.StoreWordNode, reg2, attr_os, reg1) + self.register_instruction(mips.StoreWordNode,reg2,attr_os,reg1) self.memo.clean() - + @visitor.when(cil.DefaultValueNode) - def visit(self, node): + def visit(self,node): self.memo.save() reg = self.memo.get_unused_reg() dest_offset = self.get_offset(node.dest) - if node.type in [INT, BOOL]: - self.register_instruction(mips.LoadInmediate, reg, 0) - self.register_instruction(mips.StoreWordNode, reg, dest_offset, fp) + if node.type in [INT,BOOL]: + self.register_instruction(mips.LoadInmediate,reg,0) + self.register_instruction(mips.StoreWordNode,reg,dest_offset,fp) elif node.type == STRING: _size = STRING_SIZE - self.register_instruction(mips.LoadInmediate, v0, SYSCALL_SBRK) - self.register_instruction(mips.LoadInmediate, a0, _size) + self.register_instruction(mips.LoadInmediate,v0,SYSCALL_SBRK) + self.register_instruction(mips.LoadInmediate,a0,_size) self.register_instruction(mips.SyscallNode) - self.register_instruction(mips.StoreWordNode, v0, dest_offset, fp) + self.register_instruction(mips.StoreWordNode,v0,dest_offset,fp) reg = self.memo.get_unused_reg() - self.register_instruction(mips.LoadAddress, reg, STRING) - self.register_instruction(mips.StoreWordNode, reg, 0, v0) - - self.register_instruction(mips.LoadInmediate, reg, 0) - self.register_instruction( - mips.StoreWordNode, reg, LENGTH_ATTR_OFFSET, v0 - ) # pq en vo esta el allocate + self.register_instruction(mips.LoadAddress,reg,STRING) + self.register_instruction(mips.StoreWordNode,reg,0,v0) + + self.register_instruction(mips.LoadInmediate,reg,0) + self.register_instruction(mips.StoreWordNode, reg, LENGTH_ATTR_OFFSET, v0) #pq en vo esta el allocate self.register_instruction(mips.LoadAddress, reg, EMPTY_STRING) self.register_instruction(mips.StoreWordNode, reg, CHARS_ATTR_OFFSET, v0) else: self.register_instruction(mips.LoadAddress, reg, VOID) self.register_instruction(mips.StoreWordNode, reg, dest_offset, fp) - + self.memo.clean() - + + @visitor.when(cil.PlusNode) - def visit(self, node): + def visit(self,node): self.memo.save() reg_l = self.memo.get_unused_reg() reg_r = self.memo.get_unused_reg() reg_dest = self.memo.get_unused_reg() - + left_offset = self.get_offset(node.left) right_offset = self.get_offset(node.right) - - self.register_instruction(mips.LoadWordNode, reg_l, left_offset, fp) - self.register_instruction(mips.LoadWordNode, reg_r, right_offset, fp) - - self.register_instruction(mips.AddNode, reg_dest, reg_l, reg_r) - + + self.register_instruction(mips.LoadWordNode,reg_l,left_offset,fp) + self.register_instruction(mips.LoadWordNode,reg_r,right_offset,fp) + + self.register_instruction(mips.AddNode,reg_dest,reg_l,reg_r) + offset = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode, reg_dest, offset, fp) - + self.register_instruction(mips.StoreWordNode,reg_dest,offset,fp) + self.memo.clean() - + @visitor.when(cil.MinusNode) - def visit(self, node): + def visit(self,node): self.memo.save() reg_l = self.memo.get_unused_reg() reg_r = self.memo.get_unused_reg() reg_dest = self.memo.get_unused_reg() - + left_offset = self.get_offset(node.left) right_offset = self.get_offset(node.right) - - self.register_instruction(mips.LoadWordNode, reg_l, left_offset, fp) - self.register_instruction(mips.LoadWordNode, reg_r, right_offset, fp) - - self.register_instruction(mips.SubNode, reg_dest, reg_l, reg_r) - + + self.register_instruction(mips.LoadWordNode,reg_l,left_offset,fp) + self.register_instruction(mips.LoadWordNode,reg_r,right_offset,fp) + + self.register_instruction(mips.SubNode,reg_dest,reg_l,reg_r) + offset = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode, reg_dest, offset, fp) - + self.register_instruction(mips.StoreWordNode,reg_dest,offset,fp) + self.memo.clean() - + @visitor.when(cil.StarNode) - def visit(self, node): + def visit(self,node): self.memo.save() reg1 = self.memo.get_unused_reg() reg2 = self.memo.get_unused_reg() - + + left_offset = self.get_offset(node.left) right_offset = self.get_offset(node.right) - - self.register_instruction(mips.LoadWordNode, reg1, left_offset, fp) - self.register_instruction(mips.LoadWordNode, reg2, right_offset, fp) - - self.register_instruction(mips.MultNode, reg1, reg2) - + + self.register_instruction(mips.LoadWordNode,reg1,left_offset,fp) + self.register_instruction(mips.LoadWordNode,reg2,right_offset,fp) + + self.register_instruction(mips.MultNode,reg1,reg2) + dest_offset = self.get_offset(node.dest) - self.register_instruction(mips.MoveFromHi, reg1) - self.register_instruction(mips.StoreWordNode, reg1, dest_offset, fp) - + self.register_instruction(mips.MoveFromHi,reg1) + self.register_instruction(mips.StoreWordNode,reg1,dest_offset,fp) + self.memo.clean() - + @visitor.when(cil.DivNode) - def visit(self, node): + def visit(self,node): self.memo.save() reg1 = self.memo.get_unused_reg() reg2 = self.memo.get_unused_reg() - + + left_offset = self.get_offset(node.left) right_offset = self.get_offset(node.right) - - self.register_instruction(mips.LoadWordNode, reg1, left_offset, fp) - self.register_instruction(mips.LoadWordNode, reg2, right_offset, fp) - - self.register_instruction(mips.DivideNode, reg1, reg2) - + + self.register_instruction(mips.LoadWordNode,reg1,left_offset,fp) + self.register_instruction(mips.LoadWordNode,reg2,right_offset,fp) + + self.register_instruction(mips.DivideNode,reg1,reg2) + dest_offset = self.get_offset(node.dest) - self.register_instruction(mips.MoveFromLo, reg1) - self.register_instruction(mips.StoreWordNode, reg1, dest_offset, fp) - + self.register_instruction(mips.MoveFromLo,reg1) + self.register_instruction(mips.StoreWordNode,reg1,dest_offset,fp) + self.memo.clean() - - # PENDIENTEEEEEEEE + + + #PENDIENTEEEEEEEE @visitor.when(cil.CopyNode) - def visit(self, node): - self.register_instruction(mips.CommentNode, "CopyNode") - - self.register_instruction(mips.CommentNode, "Printing Abort Message") - self.register_instruction(mips.LoadAddress, a0, ABORT_SIGNAL) - self.register_instruction(mips.LoadInmediate, v0, SYSCALL_PRINT_STR) - self.register_instruction(mips.SyscallNode) - - self.register_instruction(mips.CommentNode, "Aborting execution") - self.register_instruction(mips.LoadInmediate, v0, SYSCALL_EXIT) + def visit(self,node): + self.register_instruction(mips.CommentNode,"CopyNode") + + self.register_instruction(mips.CommentNode,"Printing Abort Message") + self.register_instruction(mips.LoadAddress,a0,ABORT_SIGNAL) + self.register_instruction(mips.LoadInmediate,v0,SYSCALL_PRINT_STR) self.register_instruction(mips.SyscallNode) - - # READSTRING + + self.register_instruction(mips.CommentNode,"Aborting execution") + self.register_instruction(mips.LoadInmediate,v0,SYSCALL_EXIT) + self.register_instruction(mips.SyscallNode) + + #READSTRING @visitor.when(cil.ReadNode) - def visit(self, node): + def visit(self,node): self.memo.save() - self.register_instruction(mips.CommentNode, "ReadStrNode") - self.register_instruction(mips.CommentNode, "Reading String to buffer") + self.register_instruction(mips.CommentNode,"ReadStrNode") + self.register_instruction(mips.CommentNode,"Reading String to buffer") self.register_instruction(mips.LoadAddress, a0, INPUT_STR_BUFFER) self.register_instruction(mips.LoadInmediate, a1, BUFFER_SIZE) self.register_instruction(mips.LoadInmediate, v0, SYSCALL_READ_STR) self.register_instruction(mips.SyscallNode) - self.register_instruction(mips.CommentNode, "Saving reference to read string") + self.register_instruction(mips.CommentNode,"Saving reference to read string") reg1 = self.memo.get_unused_reg() if reg1 != t1: if t1 in self.memo.used_reg: - self.register_instruction(mips.MoveNode, reg1, t1) + self.register_instruction(mips.MoveNode,reg1,t1) else: self.memo.clean() self.register_instruction(mips.MoveNode, t1, a0) - self.register_instruction(mips.CommentNode, "Calculating str length") + self.register_instruction(mips.CommentNode,"Calculating str length") self.register_instruction(mips.JumpAndLink, LENGTH) + - self.register_instruction( - mips.CommentNode, "Allocating char array for new string" - ) + self.register_instruction(mips.CommentNode,"Allocating char array for new string") self.register_instruction(mips.LoadInmediate, v0, SYSCALL_SBRK) self.register_instruction(mips.SyscallNode) if t0 in self.memo.used_reg: reg2 = self.memo.get_unused_reg() - self.register_instruction(mips.MoveNode, reg2, t0) + self.register_instruction(mips.MoveNode,reg2,t0) self.register_instruction(mips.MoveNode, t0, v0) - + reg3 = self.memo.get_unused_reg() - self.register_instruction( - mips.MoveNode, reg3, v0 - ) # saving pointer to char array + self.register_instruction(mips.MoveNode, reg3, v0)#saving pointer to char array reg4 = self.memo.get_unused_reg() self.register_instruction(mips.AddNode, a0, a0, -1) - self.register_instruction(mips.MoveNode, reg4, a0) # saving length + self.register_instruction(mips.MoveNode, reg4, a0)#saving length - self.register_instruction( - mips.CommentNode, "Copying bytes from one char array to another" - ) + self.register_instruction(mips.CommentNode,"Copying bytes from one char array to another") self.register_instruction(mips.JumpAndLink, COPY) - self.register_instruction(mips.CommentNode, "Null-terminating the string") + self.register_instruction(mips.CommentNode,"Null-terminating the string") self.register_instruction(mips.StoreByteNode, zero, 0, t0) - self.register_instruction(mips.CommentNode, "Allocating new String instance") + self.register_instruction(mips.CommentNode,"Allocating new String instance") _size = STRING_SIZE - self.register_instruction(mips.LoadInmediate, v0, SYSCALL_SBRK) - self.register_instruction(mips.LoadInmediate, a0, _size) + self.register_instruction(mips.LoadInmediate,v0,SYSCALL_SBRK) + self.register_instruction(mips.LoadInmediate,a0,_size) self.register_instruction(mips.SyscallNode) - + dest_offset = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode, v0, dest_offset, fp) + self.register_instruction(mips.StoreWordNode,v0,dest_offset,fp) reg = self.memo.get_unused_reg() - self.register_instruction(mips.LoadAddress, reg, STRING) - self.register_instruction(mips.StoreWordNode, reg, 0, v0) + self.register_instruction(mips.LoadAddress,reg,STRING) + self.register_instruction(mips.StoreWordNode,reg,0,v0) - # storing string length - self.register_instruction( - mips.CommentNode, "Storing length and reference to char array" - ) + #storing string length + self.register_instruction(mips.CommentNode,"Storing length and reference to char array") self.register_instruction(mips.StoreWordNode, reg4, LENGTH_ATTR_OFFSET, v0) - # storing string chars ref + #storing string chars ref self.register_instruction(mips.StoreWordNode, reg3, CHARS_ATTR_OFFSET, v0) self.memo.clean() - + @visitor.when(cil.PrintStrNode) - def visit(self, node): - self.register_instruction(mips.CommentNode, "PrintStringNode") + def visit(self,node): + self.register_instruction(mips.CommentNode,"PrintStringNode") straddr_offset = self.get_offset(node.str_addr) self.register_instruction(mips.LoadWordNode, a0, straddr_offset, fp) self.register_instruction(mips.LoadWordNode, a0, CHARS_ATTR_OFFSET, a0) self.register_instruction(mips.LoadInmediate, v0, SYSCALL_PRINT_STR) self.register_instruction(mips.SyscallNode) - + @visitor.when(cil.PrintIntNode) - def visit(self, node): - self.register_instruction(mips.CommentNode, "PrintIntNode") - if isinstance(node.int_addr, int): - self.register_instruction(mips.LoadInmediate, a0, node.int_addr) + def visit(self,node): + self.register_instruction(mips.CommentNode,"PrintIntNode") + if isinstance(node.int_addr,int): + self.register_instruction(mips.LoadInmediate,a0,node.int_addr) else: int_offset = self.get_offset(node.int_addr) self.register_instruction(mips.LoadWordNode, a0, int_offset, fp) self.register_instruction(mips.LoadInmediate, v0, SYSCALL_PRINT_INT) self.register_instruction(mips.SyscallNode) - - # Incompleto + + #Incompleto @visitor.when(cil.TypeOfNode) - def visit(self, node): - # self.memo.save() - - # reg1 = self.get_offset() - # reg2 = self.get_offset() + def visit(self,node): + #self.memo.save() + + #reg1 = self.get_offset() + #reg2 = self.get_offset() pass - + + @visitor.when(cil.TypeNameNode) - def visit(self, node): + def visit(self,node): pass - + + @visitor.when(cil.ToStrNode) - def visit(self, node): + def visit(self,node): pass - + @visitor.when(cil.LengthNode) - def visit(self, node): + def visit(self,node): pass - @visitor.when(cil.ConcatNode) - def visit(self, node): + def visit(self,node): pass - @visitor.when(cil.SubstringNode) - def visit(self, node): - pass - + def visit(self,node): + pass + @visitor.when(cil.PrefixNode) - def visit(self, node): + def visit(self,node): pass - + @visitor.when(cil.GotoIfNode) - def visit(self, node): + def visit(self,node): pass - - @visitor.when(cil.LocalNode) # No hace falta - def visit(self, node): + + @visitor.when(cil.LocalNode) #No hace falta + def visit(self,node): pass + + + + + + \ No newline at end of file From 3c8fd064605d0704211998a77c6fbe8deaebf1a3 Mon Sep 17 00:00:00 2001 From: gabriela Date: Sat, 5 Mar 2022 20:03:15 -0500 Subject: [PATCH 096/162] Correct inheritance cycle detection. --- src/type_builder.py | 78 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 61 insertions(+), 17 deletions(-) diff --git a/src/type_builder.py b/src/type_builder.py index 2ffbef8a2..72edc2059 100644 --- a/src/type_builder.py +++ b/src/type_builder.py @@ -92,13 +92,14 @@ def visit(self, node): method.tset = Tset(parent_tset) # ------checking for in order definitions and cyclic heritage + self.check_cycles(node.declarations) + parent_child_dict = {} queue = deque() visited = {} not_visited = [] # ++ - for class_declaration in node.declarations: - not_visited.append(class_declaration) # ++ + not_visited.append(class_declaration) # ++ if not (class_declaration.parent is None): parent_type = class_declaration.parent.lex else: @@ -112,30 +113,22 @@ def visit(self, node): except SError: # parent is None or not definition provided queue.append(class_declaration) - main_round = 0 while not_visited: # ++ - main_round += 1 while queue: class_declaration = queue.popleft() try: - class_visited, roundn = visited[class_declaration] # .id - - if roundn == main_round: - self.errors.append( - f"{class_declaration.id} is involved in a cyclic heritage" - ) - + class_visited = visited[class_declaration] # .id except: not_visited.remove(class_declaration) try: children = parent_child_dict[class_declaration.id] for declaration in children: queue.append(declaration) - except: # no es padre de nadie + except: # no one inherits from this class pass self.visit(class_declaration) - visited[class_declaration] = (True, main_round) # .id + visited[class_declaration] = True # .id if not_visited: queue.append(not_visited[0]) @@ -150,10 +143,6 @@ def visit(self, node): except SError: self.errors.append("A class Main with a method main most be provided") - # ---------------------------------------------------- - # for declaration in node.declarations: - # self.visit(declaration) - copy_visitor = CopyVisitor() newAst = copy_visitor.visit(node) newAst.context = self.context @@ -218,3 +207,58 @@ def get_type(self, ntype): node_row, node_col = ntype.location self.errors.append(TypeError(node_row, node_col,error.text)) return ErrorType() + + def check_cycles(self, class_declarations): + # checking for cycles + paths = [] + modified_paths = paths + + for class_declaration in class_declarations: + if not (class_declaration.parent is None): + d = class_declaration.id + p = class_declaration.parent.lex + + modified_paths = paths + + already_in_some_path = False + for i in range(0,len(paths)): + path = paths[i] + if path[-1] == d: + if not (p in path): + modified_paths[i] = path + [p] + # add parent to last pos + else: + # error + node_row, node_col = class_declaration.parent.location + self.errors.append( + SemanticError(node_row, node_col, f"Class {class_declaration.id}, or an ancestor of {class_declaration.id}, is involved in an inheritance cycle.") + ) + already_in_some_path = True + + elif path[0] == p: + if not (d in path): + # add himself to first pos + modified_paths[i] = [d] + path + else: + # error + node_row, node_col = class_declaration.parent.location + self.errors.append( + SemanticError(node_row, node_col, f"Class {class_declaration.id}, or an ancestor of {class_declaration.id}, is involved in an inheritance cycle.") + ) + already_in_some_path = True + + elif p in path: + # duplicate list + indx = path.index(p) + modified_paths = modified_paths + [[d] + path[indx:len(path)]] + already_in_some_path = True + + if not already_in_some_path: + if d != p: + modified_paths = paths + [[d, p]] + else: # class inherits from itself + node_row, node_col = class_declaration.parent.location + self.errors.append( + SemanticError(node_row, node_col, f"Class {class_declaration.id}, or an ancestor of {class_declaration.id}, is involved in an inheritance cycle.") + ) + paths = modified_paths \ No newline at end of file From e8c672328be05ca3f4183dc81dc098c8ecdbcdaf Mon Sep 17 00:00:00 2001 From: smartos99 Date: Sun, 6 Mar 2022 00:28:59 -0500 Subject: [PATCH 097/162] Add TypeOfNode --- src/code_gen/cil_builder.py | 7 ++++--- src/code_gen/mips_builder.py | 38 +++++++++++++++++++++--------------- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index 00ac698f2..cf7e2cfe3 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -70,7 +70,7 @@ def __init__(self, errors=[]): self._count = 0 self.internal_count = 0 self.context = None - self.self_var = "self" + self.self_var = None def generate_next_method_id(self): self.method_count += 1 @@ -173,6 +173,7 @@ def build_constructor(self, node): self.current_type.define_method("constructor", [], [], "Object") self_var = self.define_internal_local() + self.self_var = self_var self.register_instruction(AllocateNode(node.id, self_var)) @@ -708,7 +709,7 @@ def visit(self, node): if self.is_attribute(node.lex): self.register_instruction( GetAttribNode( - solve, self.current_type.name, node.lex, self.current_type.name + solve, "self", self.to_attr_name(self.current_type.name, node.lex), self.current_type.name ) ) else: @@ -720,7 +721,7 @@ def visit(self, node): idx = self.generate_next_string_id() self.data.append(DataNode(idx, node.lex)) solve = self.define_internal_local() - self.register_instruction(LoadNode(solve, VariableInfo(idx, False, node.lex))) + self.register_instruction(LoadNode(solve, VariableInfo(idx,None, False, node.lex))) return solve @visitor.when(cool.BooleanNode) diff --git a/src/code_gen/mips_builder.py b/src/code_gen/mips_builder.py index 027fa0094..8aa314060 100644 --- a/src/code_gen/mips_builder.py +++ b/src/code_gen/mips_builder.py @@ -16,6 +16,7 @@ FUNCTION_OFFSET = 4 RA_OFFSET = 8 OLD_FP_OFFSET = 4 +TYPEINFO_ATTR_OFFSET = 0 #str attributes offsets LENGTH_ATTR_OFFSET = 4 @@ -130,7 +131,7 @@ def get_offset(self,x): return -4*index elif x in self.params: index = self.params.index(x) - return (-4 * (len(self.locals)+len(self.params)))+4 + return (-4 * (len(self.locals)+index)) def register_instruction(self, instruction_type, *args): instruction = instruction_type(*args) @@ -325,8 +326,7 @@ def visit(self,node): self.register_instruction(mips.CommentNode,"Restoring saved $fp") self.register_instruction(mips.LoadWordNode, fp, OLD_FP_OFFSET, fp)#stored (old)$fp - AR = 4*(len(node.localvars) + len(node.params) + 2) - #AR = 4*(len(node.localvars) + 2) + AR = 4*(len(node.localvars) + 2) self.register_instruction(mips.CommentNode,"Cleaning stack after call") self.register_instruction(mips.AddiNode, sp, sp, AR) @@ -365,7 +365,7 @@ def visit(self, node: cil.LoadNode): self.register_instruction(mips.StoreWordNode,v0,dest_offset,fp) reg = self.memo.get_unused_reg() - self.register_instruction(mips.LoadAddress,reg,STRING) + self.register_instruction(mips.LoadAddress,reg,f'{STRING}_name') self.register_instruction(mips.StoreWordNode,reg,0,v0) #storing string length @@ -415,13 +415,13 @@ def visit(self,node): self.register_instruction(mips.StoreWordNode,v0,dest_offset,fp) reg = self.memo.get_unused_reg() - self.register_instruction(mips.LoadAddress,reg,node.type) + self.register_instruction(mips.LoadAddress,reg,'f{node.type}_name') self.register_instruction(mips.StoreWordNode,reg,0,v0) self.memo.clean() @visitor.when(cil.AssignNode) def visit(self,node): - self.save() + self.memo.save() reg = self.memo.get_unused_reg() @@ -437,7 +437,7 @@ def visit(self,node): @visitor.when(cil.PlusNode) def visit(self,node): - self.save() + self.memo.save() reg1 = self.memo.get_unused_reg() reg2 = self.memo.get_unused_reg() @@ -455,7 +455,7 @@ def visit(self,node): @visitor.when(cil.MinusNode) def visit(self,node): - self.save() + self.memo.save() reg1 = self.memo.get_unused_reg() reg2 = self.memo.get_unused_reg() @@ -539,7 +539,7 @@ def visit(self, node): dest_offs = self.get_offset(node.dest) self.register_instruction(mips.StoreWordNode,reg2,dest_offs,fp) - + self.memo.clean() @visitor.when(cil.SetAttribNode) def visit(self, node): @@ -574,7 +574,7 @@ def visit(self,node): self.register_instruction(mips.StoreWordNode,v0,dest_offset,fp) reg = self.memo.get_unused_reg() - self.register_instruction(mips.LoadAddress,reg,STRING) + self.register_instruction(mips.LoadAddress,reg,f'{STRING}_name') self.register_instruction(mips.StoreWordNode,reg,0,v0) self.register_instruction(mips.LoadInmediate,reg,0) @@ -740,7 +740,7 @@ def visit(self,node): self.register_instruction(mips.StoreWordNode,v0,dest_offset,fp) reg = self.memo.get_unused_reg() - self.register_instruction(mips.LoadAddress,reg,STRING) + self.register_instruction(mips.LoadAddress,reg,f'{STRING}_name') self.register_instruction(mips.StoreWordNode,reg,0,v0) #storing string length @@ -771,14 +771,20 @@ def visit(self,node): self.register_instruction(mips.LoadInmediate, v0, SYSCALL_PRINT_INT) self.register_instruction(mips.SyscallNode) - #Incompleto + @visitor.when(cil.TypeOfNode) def visit(self,node): - #self.memo.save() + self.memo.save() + obj_offset = self.get_offset(node.obj) + dest_offset = self.get_offset(node.dest) - #reg1 = self.get_offset() - #reg2 = self.get_offset() - pass + reg1 = self.memo.get_unused_reg() + self.register_instruction(mips.CommentNode,"Executing typeof") + self.register_instruction(mips.LoadWordNode, reg1, obj_offset, fp) + self.register_instruction(mips.LoadWordNode, reg1, TYPEINFO_ATTR_OFFSET, reg1) + self.register_instruction(mips.StoreWordNode, reg1, dest_offset, fp) + + self.memo.clean() @visitor.when(cil.TypeNameNode) From 5eb985129d525407152025c60ef1d0656cdbabdd Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Sun, 6 Mar 2022 00:33:09 -0500 Subject: [PATCH 098/162] feat: add dynamic and static call functions --- src/code_gen/cil_builder.py | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index c52bb27b2..80f7961f7 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -490,14 +490,14 @@ def visit(self, node): # TODO: Pending .id(,...,) # TODO: Pending @.id(,...,) - function_name = ( - self.to_function_name(node.id, self.current_type.name) - if not node.at_type - else self.to_function_name(node.id, node.at_type) - ) + instance = self.define_internal_local() if node.obj: - self.visit(node.obj) + instance = self.visit(node.obj) + + else: + instance = self.self_var + self.register_instruction(ArgNode(instance)) for arg in node.args: temp = self.define_internal_local() value = self.visit(arg) @@ -505,7 +505,23 @@ def visit(self, node): self.register_instruction(ArgNode(temp)) solve = self.define_internal_local() - self.register_instruction(StaticCallNode(function_name, solve)) + + if node.at_type: + self.register_instruction( + StaticCallNode(self.to_function_name(node.id, node.at_type), solve) + ) + + else: + instance_type = self.define_internal_local() + self.register_instruction(TypeOfNode(instance, instance_type)) + self.register_instruction( + DynamicCallNode( + instance, + node.id, + solve, + instance_type, + ) + ) return solve @@ -711,6 +727,8 @@ def visit(self, node): solve, self.current_type.name, node.lex, self.current_type.name ) ) + elif node.lex == "self": + self.register_instruction(AssignNode(solve, self.self_var)) else: self.register_instruction(AssignNode(solve, node.lex)) return solve From 42b0f94474654eea399ce178c3bbc693a9a6031c Mon Sep 17 00:00:00 2001 From: smartos99 Date: Sun, 6 Mar 2022 00:39:08 -0500 Subject: [PATCH 099/162] Add static labels --- src/code_gen/cil_builder.py | 1 - src/code_gen/mips_builder.py | 5 +++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index cf7e2cfe3..66b64367a 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -705,7 +705,6 @@ def visit(self, node): @visitor.when(cool.VariableNode) def visit(self, node): solve = self.define_internal_local() - if self.is_attribute(node.lex): self.register_instruction( GetAttribNode( diff --git a/src/code_gen/mips_builder.py b/src/code_gen/mips_builder.py index 8aa314060..d5692fae4 100644 --- a/src/code_gen/mips_builder.py +++ b/src/code_gen/mips_builder.py @@ -158,6 +158,11 @@ def generate_exception_messages(self): self.register_data(mips.DataTypeNode, ZERO_DIVISION, '.asciiz', ['"Division by zero"']) self.register_data(mips.DataTypeNode, SUBSTR_OUT_RANGE, '.asciiz', ['"Substring out of range"']) self.register_data(mips.DataTypeNode, HEAP_OVERFLOW, '.asciiz', ['"Heap overflow"']) + + def generate_extra_static_labels(self): + self.register_data(mips.DataTypeNode, VOID, '.word', [-1]) + self.register_data(mips.DataTypeNode, EMPTY_STRING, '.asciiz', ['""']) + self.register_data(mips.DataTypeNode, INPUT_STR_BUFFER, '.space', [BUFFER_SIZE]) def generate_attr_offset(self,type): From 28e9ffcb7ee3ab0c76c49dd8e540d20974996780 Mon Sep 17 00:00:00 2001 From: gabriela Date: Sun, 6 Mar 2022 02:57:36 -0500 Subject: [PATCH 100/162] Add elements to method redef and self analisis. Check for correct method redefinition in inheritage. Add checkings for self keyword. Continue with semantic errors correction. --- src/main.py | 5 ++-- src/type_builder.py | 18 +++++++----- src/type_checker.py | 69 ++++++++++++++++++++++++++++++++++----------- tests/test_1file.py | 14 +++++++++ 4 files changed, 80 insertions(+), 26 deletions(-) create mode 100644 tests/test_1file.py diff --git a/src/main.py b/src/main.py index 79fcd6766..1a5715635 100644 --- a/src/main.py +++ b/src/main.py @@ -22,8 +22,9 @@ def report_and_exit(errors): if len(errors) == 0: raise typer.Exit(code=0) - for error in errors: - typer.echo(error) + typer.echo(errors[0]) + # for error in errors: + # typer.echo(error) raise typer.Exit(code=1) diff --git a/src/type_builder.py b/src/type_builder.py index 72edc2059..95c851b26 100644 --- a/src/type_builder.py +++ b/src/type_builder.py @@ -141,7 +141,7 @@ def visit(self, node): ) # modify in semantic get_method in order to get some ancestor where the method is already defined except SError: - self.errors.append("A class Main with a method main most be provided") + self.errors.append(SemanticError(0, 0 ,"A class Main with a method main most be provided")) copy_visitor = CopyVisitor() newAst = copy_visitor.visit(node) @@ -161,7 +161,7 @@ def visit(self, node): if node.parent is not None: try: - parent_type = self.get_type(node.parent) + parent_type = self.get_type(node.parent, f"declared as {node.id}'s parent") self.current_type.set_parent(parent_type) except SError as error: node_row, node_col = node.parent.location @@ -181,8 +181,8 @@ def visit(self, node): param_names = [fname.lex for fname, ftype in node.params] try: - param_types = [self.get_type(ftype) for fname, ftype in node.params] - return_type = self.get_type(node.type) + param_types = [self.get_type(ftype, f"of formal parameter {fname.lex}") for fname, ftype in node.params] + return_type = self.get_type(node.type, f"marked in '{node.id.lex}' as return type") self.current_type.define_method( node.id.lex, param_names, param_types, return_type ) @@ -193,19 +193,23 @@ def visit(self, node): @visitor.when(AttrDeclarationNode) def visit(self, node): + if node.id.lex == "self": + node_row, node_col = node.id.location + self.errors.append(SemanticError(node_row, node_col,"'self' cannot be the name of an attribute.")) + return try: - attr_type = self.get_type(node.type) + attr_type = self.get_type(node.type, f"of attribute {node.id.lex}") self.current_type.define_attribute(node.id.lex, attr_type) except SError as error: node_row, node_col = node.id.location self.errors.append(SemanticError(node_row, node_col,error.text)) - def get_type(self, ntype): + def get_type(self, ntype, comp_error_mesg): try: return self.context.get_type(ntype.lex) except SError as error: node_row, node_col = ntype.location - self.errors.append(TypeError(node_row, node_col,error.text)) + self.errors.append(TypeError(node_row, node_col, f"Type {ntype.lex} " + comp_error_mesg + " is not defined.")) return ErrorType() def check_cycles(self, class_declarations): diff --git a/src/type_checker.py b/src/type_checker.py index 4f2dceea9..ba860ea6b 100644 --- a/src/type_checker.py +++ b/src/type_checker.py @@ -148,10 +148,18 @@ def visit(self, node, scope): param_used = {} for i, param_name in enumerate(param_names): + if param_name == "self": + param_n, param_t = node.params[i] + node_row, node_col = param_n.location + self.errors.append( + SemanticError(node_row, node_col ,f"'self' cannot be the name of a formal parameter.") + ) try: param_used[param_name] + param_n, param_t = node.params[i] + node_row, node_col = param_n.location self.errors.append( - f"More tan one param in method {node.id} has the name {param_name}" + SemanticError(node_row, node_col ,f"Formal parameter '{param_name}' multiply defined in method '{node.id.lex}'") ) except: param_used[param_name] = True @@ -168,21 +176,38 @@ def visit(self, node, scope): if not body_type.conforms_to(method_return_type):#aqui se debe poner node_row, node_col = node.body.token.location - self.errors.append(TypeError( node_row, node_col, INCOMPATIBLE_TYPES % (body_type.name, method_return_type.name))) + self.errors.append(TypeError( node_row, node_col, f"Inferred return type '{body_type.name}' of method '{node.id.lex}' does not conform to declared return type '{method_return_type.name}'.")) if self.current_type.parent is not None: try: parent_method = self.current_type.parent.get_method( self.current_method.name ) - if parent_method != self.current_method: - self.errors.append( - WRONG_SIGNATURE - % ( - parent_method.name, - f"an ancestor of {self.current_type.name}", - ) - ) + # ensure same return type of redefined method + if parent_method.return_type != self.current_method.return_type: + node_row, node_col = node.type.location + self.errors.append(SemanticError(node_row, node_col, f"In redefined method '{node.id.lex}', return type {self.current_method.return_type.name} is different from original return type {parent_method.return_type.name}.")) + + # redefined method most have same number of parameters + if len(parent_method.param_names) != len(self.current_method.param_names): + node_row, node_col = node.id.location + self.errors.append(SemanticError(node_row, node_col, f"Incompatible number of formal parameters in redefined method '{node.id.lex}'.")) + len_parent_params = len(parent_method.param_names) + len_current_params = len(self.current_method.param_names) + if len_current_params >= len_parent_params: + max_len = len_parent_params + else: + max_len = len_current_params + else: + max_len = len(parent_method.param_names) + + # check that each param has the same type as in the original method + for i in range(0, max_len): + if self.current_method.param_types[i] != parent_method.param_types[i]: + param_i_name, param_i_type = node.params[i] + node_row, node_col = param_i_name.location + self.errors.append(SemanticError(node_row, node_col, f"In redefined method '{node.id.lex}', type {self.current_method.param_types[i].name} of parameter {param_i_name.lex} is different from original type {parent_method.param_types[i].name}.")) + except SError: pass @@ -200,8 +225,9 @@ def visit(self, node, scope): @visitor.when(VarDeclarationNode) def visit(self, node, scope): if scope.is_local(node.id.lex): + node_row, node_col = id.location self.errors.append( - LOCAL_ALREADY_DEFINED % (node.id, self.current_method.name) + SemanticError(node_row, node_col, LOCAL_ALREADY_DEFINED % (node.id, self.current_method.name)) ) elif node.id.lex == "self": self.errors.append(SELF_IS_READONLY) @@ -221,7 +247,8 @@ def visit(self, node, scope): @visitor.when(AssignNode) def visit(self, node, scope): if node.id.lex == "self": - self.errors.append(SELF_IS_READONLY) + node_row, node_col = node.token.location + self.errors.append(SemanticError(node_row, node_col, "Cannot assign to 'self'. " + SELF_IS_READONLY)) var_type = None if not scope.is_defined(node.id.lex): self.errors.append( @@ -307,8 +334,9 @@ def visit(self, node, scope): bool_type = self.context.get_type("Bool") if condition_type != bool_type and condition_type.name != "AUTO_TYPE": + node_row, node_col = node.token.location self.errors.append( - f"Expression after 'while' must be bool, current is {condition_type.name}" + TypeError(node_row, node_col, f"Expression in 'while' condition must be bool, current type is {condition_type.name}") ) return ErrorType() @@ -334,6 +362,9 @@ def visit(self, node, scope): @visitor.when(VarDeclarationNode) def visit(self, node, scope): + if node.id == "self": + node_row, node_col = node.token.location + self.errors.append(SemanticError(node_row, node_col, "'self' cannot be bound in a 'let' expression. " + SELF_IS_READONLY)) static_type = None try: @@ -343,13 +374,17 @@ def visit(self, node, scope): scope.define_variable(node.id, static_type) except SError as e: - self.errors.append(e) + node_row, node_col = node.type.location + self.errors.append( + TypeError(node_row, node_col, e.text) + ) return ErrorType() if node.expr != None: typex = self.visit(node.expr, scope) if not typex.conforms_to(static_type): - self.errors.append(INCOMPATIBLE_TYPES % (typex, static_type)) + line, col = node.token.location + self.errors.append(TypeError(line, col, INCOMPATIBLE_TYPES % (typex.name, static_type.name))) return static_type @@ -397,10 +432,10 @@ def visit(self, node, scope): typex = self.context.get_type(node.lex.lex) if typex.name == "SELF_TYPE": return self.current_type - return typex except SError as error: - self.errors.append(error.text) + node_row, node_col = node.lex.location + self.errors.append(TypeError(node_row, node_col, f"Type {node.lex.lex} of 'new' expression is not defined.")) return ErrorType() @visitor.when(IsvoidNode) diff --git a/tests/test_1file.py b/tests/test_1file.py new file mode 100644 index 000000000..b8d5726b3 --- /dev/null +++ b/tests/test_1file.py @@ -0,0 +1,14 @@ +import pytest +import os +from utils import compare_errors, first_error_only_line + +tests_dir = __file__.rpartition('/')[0] + '/semantic/' +tests = [(file) for file in os.listdir(tests_dir) if file.endswith('self4.cl')] + +@pytest.mark.semantic +@pytest.mark.error +@pytest.mark.run(order=3) +@pytest.mark.parametrize("cool_file", tests) +def test_semantic_errors(compiler_path, cool_file): + compare_errors(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_error.txt', \ + cmp=first_error_only_line) \ No newline at end of file From c88aa2c7fd9916493754bdc0dfcb120c14c879a4 Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Sun, 6 Mar 2022 11:38:42 -0500 Subject: [PATCH 101/162] fix: add missing parameter to Load in StringNode --- src/code_gen/cil_builder.py | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index 80f7961f7..1140504ee 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -462,7 +462,7 @@ def visit(self, node): self.current_function = None @visitor.when(cool.VarDeclarationNode) - def visit(self, node): + def visit(self, node, return_var=None): # Add LOCAL variable local = LocalNode(node.id) self.current_function.localvars.append(local) @@ -471,6 +471,10 @@ def visit(self, node): if node.expr: expr = self.visit(node.expr) self.register_instruction(AssignNode(local.id, expr)) + else: + self.register_instruction(DefaultValueNode(local)) + + self.register_instruction(AssignNode(return_var,local)) @visitor.when(cool.AssignNode) def visit(self, node): @@ -487,8 +491,8 @@ def visit(self, node): @visitor.when(cool.CallNode) def visit(self, node): - # TODO: Pending .id(,...,) - # TODO: Pending @.id(,...,) + # TODO: Pending test .id(,...,) + # TODO: Pending test @.id(,...,) instance = self.define_internal_local() if node.obj: @@ -603,7 +607,11 @@ def visit(self, node): @visitor.when(cool.CaseNode) def visit(self, node): - pass # TODO: Pending!!! + expr_value = self.visit(node.expr) + solve = self.define_internal_local() + for case_item in node.case_items: + item_expr_value = self.define_internal_local() + self.visit(case_item) @visitor.when(cool.CaseItemNode) def visit(self, node): @@ -724,7 +732,10 @@ def visit(self, node): if self.is_attribute(node.lex): self.register_instruction( GetAttribNode( - solve, self.current_type.name, node.lex, self.current_type.name + solve, + "self", + self.to_attr_name(self.current_type.name, node.lex), + self.current_type.name, ) ) elif node.lex == "self": @@ -738,7 +749,9 @@ def visit(self, node): idx = self.generate_next_string_id() self.data.append(DataNode(idx, node.lex)) solve = self.define_internal_local() - self.register_instruction(LoadNode(solve, VariableInfo(idx, False, node.lex))) + self.register_instruction( + LoadNode(solve, VariableInfo(idx, None, False, node.lex)) + ) return solve @visitor.when(cool.BooleanNode) From f2c1347e750c330e6d55b8180f874180a8a8f8c0 Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Sun, 6 Mar 2022 12:44:15 -0500 Subject: [PATCH 102/162] fix!: add return_var to visitor --- src/cmp/cil.py | 2 +- src/code_gen/cil_builder.py | 290 ++++++++++++++++-------------------- 2 files changed, 131 insertions(+), 161 deletions(-) diff --git a/src/cmp/cil.py b/src/cmp/cil.py index 197ae0427..9810e6cb6 100644 --- a/src/cmp/cil.py +++ b/src/cmp/cil.py @@ -374,7 +374,7 @@ def visit(self, node): @visitor.when(TypeOfNode) def visit(self, node): - return f"{node.dest} = TYPEOF {node.type}" + return f"{node.dest} = TYPEOF {node.obj}" @visitor.when(StaticCallNode) def visit(self, node): diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index 1140504ee..c7c428994 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -194,7 +194,8 @@ def build_constructor(self, node): for attr in attributeNodes: # Assign init_expr if not None if attr.init_exp: - init_expr_value = self.visit(attr.init_exp) + init_expr_value = self.define_internal_local() + self.visit(attr.init_exp, init_expr_value) self.register_instruction( SetAttribNode( node.id, @@ -346,11 +347,11 @@ def io_inint(self): self.register_instruction(ReturnNode(ret_vinfo)) @visitor.on("node") - def visit(self, node=None): + def visit(self, node=None, return_var=None): pass @visitor.when(cool.ProgramNode) - def visit(self, node): + def visit(self, node, return_var=None): self.context = node.context self.add_builtin_functions() @@ -397,7 +398,7 @@ def visit(self, node): return program_node @visitor.when(cool.ClassDeclarationNode) - def visit(self, node): + def visit(self, node, return_var=None): self.current_type = self.context.get_type(node.id) type_node = self.register_type(self.current_type.name) @@ -432,11 +433,11 @@ def visit(self, node): self.visit(feature) @visitor.when(cool.AttrDeclarationNode) - def visit(self, node): + def visit(self, node, return_var=None): pass @visitor.when(cool.FuncDeclarationNode) - def visit(self, node): + def visit(self, node, return_var=None): self.current_method = self.current_type.get_method(node.id) # Add function to .CODE @@ -450,7 +451,8 @@ def visit(self, node): self.current_function.params.append(ParamNode(pname)) # Body - value = self.visit(node.body) + value = self.define_internal_local() + self.visit(node.body, value) # Return if isinstance(self.current_method.return_type, VoidType): @@ -461,87 +463,65 @@ def visit(self, node): self.current_method = None self.current_function = None - @visitor.when(cool.VarDeclarationNode) - def visit(self, node, return_var=None): - # Add LOCAL variable - local = LocalNode(node.id) - self.current_function.localvars.append(local) - - # Add Assignment Node - if node.expr: - expr = self.visit(node.expr) - self.register_instruction(AssignNode(local.id, expr)) - else: - self.register_instruction(DefaultValueNode(local)) - - self.register_instruction(AssignNode(return_var,local)) - @visitor.when(cool.AssignNode) - def visit(self, node): - expr = self.visit(node.expr) + def visit(self, node, return_var): + self.visit(node.expr, return_var) if self.is_attribute(node.id): self.register_instruction( - SetAttribNode("self", node.id, expr, self.current_type.name) + SetAttribNode("self", node.id, return_var, self.current_type.name) ) else: - self.register_instruction(AssignNode(node.id, expr)) - - return node.id + self.register_instruction(AssignNode(node.id, return_var)) @visitor.when(cool.CallNode) - def visit(self, node): + def visit(self, node, return_var): # TODO: Pending test .id(,...,) # TODO: Pending test @.id(,...,) instance = self.define_internal_local() if node.obj: - instance = self.visit(node.obj) + self.visit(node.obj, instance) else: - instance = self.self_var + self.register_instruction(AssignNode(instance, self.self_var)) + + instance_type = None + if not node.at_type: + instance_type = self.define_internal_local() + self.register_instruction(TypeOfNode(instance, instance_type)) self.register_instruction(ArgNode(instance)) for arg in node.args: - temp = self.define_internal_local() - value = self.visit(arg) - self.register_instruction(AssignNode(temp, value)) - self.register_instruction(ArgNode(temp)) - - solve = self.define_internal_local() + arg_value = self.define_internal_local() + self.visit(arg, arg_value) + self.register_instruction(ArgNode(arg_value)) if node.at_type: self.register_instruction( - StaticCallNode(self.to_function_name(node.id, node.at_type), solve) + StaticCallNode(self.to_function_name(node.id, node.at_type), return_var) ) else: - instance_type = self.define_internal_local() - self.register_instruction(TypeOfNode(instance, instance_type)) self.register_instruction( DynamicCallNode( instance, node.id, - solve, + return_var, instance_type, ) ) - return solve - @visitor.when(cool.IfNode) - def visit(self, node): - # Result Variable - solve = self.define_internal_local() - + def visit(self, node, return_var): # IF condition GOTO label - condition_value = self.visit(node.if_expr) + condition_value = self.define_internal_local() + self.visit(node.if_expr, condition_value) then_label = "THEN_" + self.next_id() self.register_instruction(GotoIfNode(condition_value, then_label)) # Else - else_value = self.visit(node.else_expr) - self.register_instruction(AssignNode(solve, else_value)) + self.visit(node.else_expr, return_var) # GOTO end_label end_label = "END_IF_" + self.next_id() # Example: END_IF_120 @@ -549,22 +529,20 @@ def visit(self, node): # Then label self.register_instruction(LabelNode(then_label)) - then_value = self.visit(node.then_expr) - self.register_instruction(AssignNode(solve, then_value)) + self.visit(node.then_expr, return_var) # end_label self.register_instruction(LabelNode(end_label)) - return solve - @visitor.when(cool.WhileNode) - def visit(self, node): + def visit(self, node, return_var): # While label while_label = "WHILE_" + self.next_id() self.register_instruction(LabelNode(while_label)) # Condition - c = self.visit(node.condition) + c = self.define_internal_local() + self.visit(node.condition, c) # If condition GOTO body_label body_label = "BODY_" + self.next_id() @@ -584,184 +562,176 @@ def visit(self, node): # End while label self.register_instruction(LabelNode(end_while_label)) - solve = self.define_internal_local() - self.register_instruction(DefaultValueNode(solve, "Void")) - - return solve + self.register_instruction(DefaultValueNode(return_var, "Void")) @visitor.when(cool.BlockNode) - def visit(self, node): - value = None + def visit(self, node, return_var): for expr in node.expression_list: - value = self.visit(expr) - - return value + self.visit(expr, return_var) @visitor.when(cool.LetNode) - def visit(self, node): + def visit(self, node, return_var): for var_dec in node.identifiers: self.visit(var_dec.expr) - self.current_function.localvars.append(LocalNode(var_dec.id)) - return self.visit(node.body) + self.visit(node.body, return_var) + + @visitor.when(cool.VarDeclarationNode) + def visit(self, node, return_var=None): + # Add LOCAL variable + local = LocalNode(node.id) + self.current_function.localvars.append(local) + + # Add Assignment Node + if node.expr: + self.visit(node.expr, local.id) + else: + self.register_instruction(DefaultValueNode(local, node.type)) @visitor.when(cool.CaseNode) - def visit(self, node): - expr_value = self.visit(node.expr) - solve = self.define_internal_local() - for case_item in node.case_items: - item_expr_value = self.define_internal_local() - self.visit(case_item) + def visit(self, node, return_var=None): + pass # TODO: Pending!!! + + # expr_value = self.visit(node.expr) + # solve = self.define_internal_local() + # for case_item in node.case_items: + # item_expr_value = self.define_internal_local() + # self.visit(case_item) @visitor.when(cool.CaseItemNode) - def visit(self, node): + def visit(self, node, return_var=None): pass # TODO: Pending!!! # Arithmetic and comparison operators @visitor.when(cool.PlusNode) - def visit(self, node): - left = self.visit(node.left) - right = self.visit(node.right) + def visit(self, node, return_var): + left = self.define_internal_local() + self.visit(node.left, left) - solve = self.define_internal_local() - self.register_instruction(PlusNode(solve, left, right)) + right = self.define_internal_local() + self.visit(node.right, right) - return solve + self.register_instruction(PlusNode(return_var, left, right)) @visitor.when(cool.MinusNode) - def visit(self, node): - left = self.visit(node.left) - right = self.visit(node.right) + def visit(self, node, return_var): + left = self.define_internal_local() + self.visit(node.left, left) - solve = self.define_internal_local() - self.register_instruction(MinusNode(solve, left, right)) + right = self.define_internal_local() + self.visit(node.right, right) - return solve + self.register_instruction(MinusNode(return_var, left, right)) @visitor.when(cool.StarNode) - def visit(self, node): - left = self.visit(node.left) - right = self.visit(node.right) + def visit(self, node, return_var): + left = self.define_internal_local() + self.visit(node.left, left) - solve = self.define_internal_local() - self.register_instruction(StarNode(solve, left, right)) + right = self.define_internal_local() + self.visit(node.right, right) - return solve + self.register_instruction(StarNode(return_var, left, right)) @visitor.when(cool.DivNode) - def visit(self, node): - left = self.visit(node.left) - right = self.visit(node.right) + def visit(self, node, return_var): + left = self.define_internal_local() + self.visit(node.left, left) - solve = self.define_internal_local() - self.register_instruction(DivNode(solve, left, right)) + right = self.define_internal_local() + self.visit(node.right, right) - return solve + self.register_instruction(DivNode(return_var, left, right)) @visitor.when(cool.LessEqualNode) - def visit(self, node): - left = self.visit(node.left) - right = self.visit(node.right) + def visit(self, node, return_var): + left = self.define_internal_local() + self.visit(node.left, left) - solve = self.define_internal_local() - self.register_instruction(LessEqualNode(solve, left, right)) + right = self.define_internal_local() + self.visit(node.right, right) - return solve + self.register_instruction(LessEqualNode(return_var, left, right)) @visitor.when(cool.LessNode) - def visit(self, node): - left = self.visit(node.left) - right = self.visit(node.right) + def visit(self, node, return_var): + left = self.define_internal_local() + self.visit(node.left, left) - solve = self.define_internal_local() - self.register_instruction(LessNode(solve, left, right)) + right = self.define_internal_local() + self.visit(node.right, right) - return solve + self.register_instruction(LessNode(return_var, left, right)) @visitor.when(cool.EqualNode) - def visit(self, node): - left = self.visit(node.left) - right = self.visit(node.right) + def visit(self, node, return_var): + left = self.define_internal_local() + self.visit(node.left, left) - solve = self.define_internal_local() - self.register_instruction(EqualNode(solve, left, right)) + right = self.define_internal_local() + self.visit(node.right, right) - return solve + self.register_instruction(EqualNode(return_var, left, right)) # Unary operators @visitor.when(cool.InstantiateNode) # NewNode - def visit(self, node): - instance = self.define_internal_local() + def visit(self, node, return_var): self.register_instruction( - StaticCallNode(self.to_function_name("constructor", node.lex), instance) + StaticCallNode(self.to_function_name("constructor", node.lex), return_var) ) - return instance - @visitor.when(cool.IsvoidNode) - def visit(self, node): - value = self.visit(node.expr) - solve = self.define_internal_local() - self.register_instruction(IsVoidNode(solve, value)) - return solve + def visit(self, node, return_var): + value = self.define_internal_local() + self.visit(node.expr, value) + self.register_instruction(IsVoidNode(return_var, value)) @visitor.when(cool.NotNode) - def visit(self, node): - value = self.visit(node.expr) - solve = self.define_internal_local() - self.register_instruction(NotNode(solve, value)) - return solve + def visit(self, node, return_var): + value = self.define_internal_local() + self.visit(node.expr, value) + self.register_instruction(NotNode(return_var, value)) @visitor.when(cool.NegNode) - def visit(self, node): - value = self.visit(node.expr) - solve = self.define_internal_local() - self.register_instruction(IntComplementNode(solve, value)) - return solve + def visit(self, node, return_var): + value = self.define_internal_local() + self.visit(node.expr, value) + self.register_instruction(IntComplementNode(return_var, value)) @visitor.when(cool.ConstantNumNode) - def visit(self, node): - solve = self.define_internal_local() - self.register_instruction(AssignNode(solve, int(node.lex))) - return solve + def visit(self, node, return_var): + self.register_instruction(AssignNode(return_var, int(node.lex))) @visitor.when(cool.VariableNode) - def visit(self, node): - solve = self.define_internal_local() - + def visit(self, node, return_var): if self.is_attribute(node.lex): self.register_instruction( GetAttribNode( - solve, + return_var, "self", self.to_attr_name(self.current_type.name, node.lex), self.current_type.name, ) ) elif node.lex == "self": - self.register_instruction(AssignNode(solve, self.self_var)) + self.register_instruction(AssignNode(return_var, self.self_var)) else: - self.register_instruction(AssignNode(solve, node.lex)) - return solve + self.register_instruction(AssignNode(return_var, node.lex)) @visitor.when(cool.StringNode) - def visit(self, node): + def visit(self, node, return_var): idx = self.generate_next_string_id() self.data.append(DataNode(idx, node.lex)) - solve = self.define_internal_local() self.register_instruction( - LoadNode(solve, VariableInfo(idx, None, False, node.lex)) + LoadNode(return_var, VariableInfo(idx, None, False, node.lex)) ) - return solve @visitor.when(cool.BooleanNode) - def visit(self, node): - solve = self.define_internal_local() - self.register_instruction(AssignNode(solve, 1 if node.lex == "true" else 0)) - return solve + def visit(self, node, return_var): + self.register_instruction( + AssignNode(return_var, 1 if node.lex == "true" else 0) + ) @visitor.when(cool.DefaultValueNode) - def visit(self, node): - solve = self.define_internal_local() - self.register_instruction(DefaultValueNode(solve, node.type)) - return solve + def visit(self, node, return_var): + self.register_instruction(DefaultValueNode(return_var, node.type)) From 5c6be8fbee1464df65110d722a112b04b871a2fc Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Sun, 6 Mar 2022 12:47:42 -0500 Subject: [PATCH 103/162] fix: comment mips visitor in main --- src/main.py | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/main.py b/src/main.py index b89a04e81..4737dc32f 100644 --- a/src/main.py +++ b/src/main.py @@ -31,7 +31,7 @@ def report_and_exit(errors): def pipeline(input_file: Path, output_file: Path = None): errors = [] - + if not input_file.is_file: errors.append(InvalidInputFileError(str(input_file))) @@ -93,23 +93,22 @@ def pipeline(input_file: Path, output_file: Path = None): formatter = PrintVisitor() tree = formatter.visit(cil_ast) print(tree) - - cil_to_mips_visitor = MIPSBuilder() - mips_ast = cil_to_mips_visitor.visit(cil_ast) - - mips_writer = MIPSWriter() - output = mips_writer(mips_ast) - - output = '\n'.join(mips_writer.output) - if output_file is None: - output_file = input.with_suffix(".mips") - - output_file.write_text(output) + # cil_to_mips_visitor = MIPSBuilder() + # mips_ast = cil_to_mips_visitor.visit(cil_ast) + + # mips_writer = MIPSWriter() + # output = mips_writer(mips_ast) + + # output = '\n'.join(mips_writer.output) + + # if output_file is None: + # output_file = input.with_suffix(".mips") + # output_file.write_text(output) if __name__ == "__main__": - input_file = Path("/home/sandra/Desktop/FinalProjects/Compiler/cool-compiler-2021/customized_tests/test_hello_world.cl") - pipeline(input_file) - #typer.run(pipeline) + # input_file = Path("/home/sandra/Desktop/FinalProjects/Compiler/cool-compiler-2021/customized_tests/test_hello_world.cl") + # pipeline(input_file) + typer.run(pipeline) From e68cb4822355e5b42804e42e8b4b3ae8ea364c54 Mon Sep 17 00:00:00 2001 From: gabriela Date: Sun, 6 Mar 2022 13:11:11 -0500 Subject: [PATCH 104/162] Remove unnecessary code. Fix erros. Visit class involved in ciclyc heritage in type checker. (without defining them twice) Remove unnecessary errors that were being reported multiple times. Delete second definition of VarDeclarationNode. --- customized_tests/semantics/attrDecl.cl | 10 +++ customized_tests/semantics/attrDecl2.cl | 10 +++ customized_tests/semantics/inheritance.cl | 10 +++ src/type_builder.py | 11 ++-- src/type_checker.py | 75 ++++++++++------------- 5 files changed, 68 insertions(+), 48 deletions(-) create mode 100644 customized_tests/semantics/attrDecl.cl create mode 100644 customized_tests/semantics/attrDecl2.cl create mode 100644 customized_tests/semantics/inheritance.cl diff --git a/customized_tests/semantics/attrDecl.cl b/customized_tests/semantics/attrDecl.cl new file mode 100644 index 000000000..644d55381 --- /dev/null +++ b/customized_tests/semantics/attrDecl.cl @@ -0,0 +1,10 @@ +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; + +class Main inherits IO { + test1: X <- new Main; + + main(): IO { out_string("Hello World!")}; +}; \ No newline at end of file diff --git a/customized_tests/semantics/attrDecl2.cl b/customized_tests/semantics/attrDecl2.cl new file mode 100644 index 000000000..7bb18965f --- /dev/null +++ b/customized_tests/semantics/attrDecl2.cl @@ -0,0 +1,10 @@ +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; + +class Main inherits W { + test1: X <- new Main; + + main(): G { out_string("Hello World!")}; +}; \ No newline at end of file diff --git a/customized_tests/semantics/inheritance.cl b/customized_tests/semantics/inheritance.cl new file mode 100644 index 000000000..5b9033e6e --- /dev/null +++ b/customized_tests/semantics/inheritance.cl @@ -0,0 +1,10 @@ +class A inherits B{ }; +class B inherits C { }; +class C inherits A { }; +class D inherits B { }; + +class Main inherits A { + test1: B <- new Main; + + main(): C { out_string("Hello World!")}; +}; \ No newline at end of file diff --git a/src/type_builder.py b/src/type_builder.py index 95c851b26..e6180093f 100644 --- a/src/type_builder.py +++ b/src/type_builder.py @@ -99,24 +99,21 @@ def visit(self, node): visited = {} not_visited = [] # ++ for class_declaration in node.declarations: - not_visited.append(class_declaration) # ++ - if not (class_declaration.parent is None): - parent_type = class_declaration.parent.lex - else: - parent_type = None + not_visited.append(class_declaration) try: + parent_type = class_declaration.parent.lex self.context.get_type(parent_type) try: parent_child_dict[parent_type].append(class_declaration) except: # KeyError parent_child_dict[parent_type] = [class_declaration] - except SError: # parent is None or not definition provided + except Exception: # parent is None or not definition provided queue.append(class_declaration) while not_visited: # ++ while queue: class_declaration = queue.popleft() - try: + try: # avoid redefining classes involved in a ciclyc heritage class_visited = visited[class_declaration] # .id except: not_visited.remove(class_declaration) diff --git a/src/type_checker.py b/src/type_checker.py index ba860ea6b..a136c6e56 100644 --- a/src/type_checker.py +++ b/src/type_checker.py @@ -44,6 +44,7 @@ import copy from errors import TypeError, NameError, SemanticError, AttributeError +# some predefined errors WRONG_SIGNATURE = 'Method "%s" already defined in "%s" with a different signature.' SELF_IS_READONLY = 'Variable "self" is read-only.' LOCAL_ALREADY_DEFINED = 'Variable "%s" is already defined in method "%s".' @@ -68,25 +69,38 @@ def visit(self, node): scope = Scope() self.context = copy.copy(node.context) - #visit class in order + #visit classes in order (from tree root to leaves) parent_children_dict = {} initial_nodes = [] visited = {} + self.class_to_visit = [] + self.class_visited = {} for declaration in node.declarations: try: - visited[declaration.id] # checking is visited + visited[declaration.id] # checking if visited except: visited[declaration.id] = True + self.class_visited[declaration.id] = False + self.class_to_visit.append(declaration) if declaration.parent is None or declaration.parent.lex in ["IO", "Int", "String", "Bool"]: # is node has no parent, mark it to visit it first later initial_nodes.append(declaration) else: try: - parent_children_dict[declaration.parent.lex].append(declaration) - except: - parent_children_dict[declaration.parent.lex] = [declaration] + self.context.get_type(declaration.parent.lex) + try: + parent_children_dict[declaration.parent.lex].append(declaration) + except: + parent_children_dict[declaration.parent.lex] = [declaration] + except: # add declarations where parent is not defined + initial_nodes.append(declaration) + + for declaration in initial_nodes: # first visit root nodes + self.visit(declaration, scope.create_child(), parent_children_dict) - for declaration in initial_nodes: + while self.class_to_visit: # visiting classes involved in ciclyc heritage + declaration = self.class_to_visit[0] self.visit(declaration, scope.create_child(), parent_children_dict) + self.context = None self.current_type = None @@ -96,6 +110,9 @@ def visit(self, node): @visitor.when(ClassDeclarationNode) def visit(self, node, scope, parent_children_dict): + self.class_to_visit.remove(node) + self.class_visited[node.id] = True # arked class as visited + self.current_type = self.context.get_type(node.id) scope.define_variable("self", self.current_type) @@ -107,8 +124,9 @@ def visit(self, node, scope, parent_children_dict): try: children = parent_children_dict[node.id] - for child in children: - self.visit(child, scope.create_child(), parent_children_dict) + for child in children:# after initialization, each parent class visits its children (note the child scope creation) + if not self.class_visited[child.id]: + self.visit(child, scope.create_child(), parent_children_dict) except: return @@ -116,9 +134,8 @@ def visit(self, node, scope, parent_children_dict): def visit(self, node, scope): try: typex = self.context.get_type(node.type.lex) - except SError as e: - self.errors.append(e) + # ERROR already reported in type builder return ErrorType() if typex.name == "SELF_TYPE": @@ -142,6 +159,7 @@ def visit(self, node, scope): method_return_type = self.current_type child_scope = scope.create_child() + # ------------parameters most have differente names------------ param_names = self.current_method.param_names param_types = self.current_method.param_types @@ -167,11 +185,6 @@ def visit(self, node, scope): # ------------------------------------------------------------- - # for i in range(len(self.current_method.param_names)): - # child_scope.define_variable( - # self.current_method.param_names[i], self.current_method.param_types[i] - # ) - body_type = self.visit(node.body, child_scope) if not body_type.conforms_to(method_return_type):#aqui se debe poner @@ -209,7 +222,7 @@ def visit(self, node, scope): self.errors.append(SemanticError(node_row, node_col, f"In redefined method '{node.id.lex}', type {self.current_method.param_types[i].name} of parameter {param_i_name.lex} is different from original type {parent_method.param_types[i].name}.")) except SError: - pass + pass # parent has no method named like this try: return_type = self.context.get_type(node.type.lex) @@ -219,31 +232,9 @@ def visit(self, node, scope): return return_type except SError as e: - self.errors.append(e) + # Error already reported in type builder return ErrorType() - @visitor.when(VarDeclarationNode) - def visit(self, node, scope): - if scope.is_local(node.id.lex): - node_row, node_col = id.location - self.errors.append( - SemanticError(node_row, node_col, LOCAL_ALREADY_DEFINED % (node.id, self.current_method.name)) - ) - elif node.id.lex == "self": - self.errors.append(SELF_IS_READONLY) - try: - static_type = self.context.get_type(node.type.lex) - except SError as error: - self.errors.append(error.text) - static_type = ErrorType() - - expr_type = self.visit(node.expr, scope) - if not expr_type.conforms_to(static_type): - self.errors.append(INCOMPATIBLE_TYPES % (expr_type.name, static_type.name)) - - scope.define_variable(node.id.lex, static_type) - return static_type - @visitor.when(AssignNode) def visit(self, node, scope): if node.id.lex == "self": @@ -371,14 +362,15 @@ def visit(self, node, scope): static_type = self.context.get_type(node.type.lex) if static_type.name == "SELF_TYPE": static_type = self.current_type - scope.define_variable(node.id, static_type) + # scope.define_variable(node.id, static_type) except SError as e: node_row, node_col = node.type.location self.errors.append( TypeError(node_row, node_col, e.text) ) - return ErrorType() + # return ErrorType() + static_type = ErrorType() if node.expr != None: typex = self.visit(node.expr, scope) @@ -386,6 +378,7 @@ def visit(self, node, scope): line, col = node.token.location self.errors.append(TypeError(line, col, INCOMPATIBLE_TYPES % (typex.name, static_type.name))) + scope.define_variable(node.id, static_type) return static_type @visitor.when(CaseNode) From 889bdfb7919dca84d98fdf645b6f5860b9e14db7 Mon Sep 17 00:00:00 2001 From: smartos99 Date: Sun, 6 Mar 2022 13:39:28 -0500 Subject: [PATCH 105/162] Change stack order --- src/cmp/cil.py | 2 +- src/code_gen/mips_builder.py | 73 +++++++++++++++++++++--------------- 2 files changed, 43 insertions(+), 32 deletions(-) diff --git a/src/cmp/cil.py b/src/cmp/cil.py index fbb41acf6..141cacfab 100644 --- a/src/cmp/cil.py +++ b/src/cmp/cil.py @@ -374,7 +374,7 @@ def visit(self, node): @visitor.when(TypeOfNode) def visit(self, node): - return f"{node.dest} = TYPEOF {node.type}" + return f"{node.dest} = TYPEOF {node.obj}" @visitor.when(StaticCallNode) def visit(self, node): diff --git a/src/code_gen/mips_builder.py b/src/code_gen/mips_builder.py index d5692fae4..4400099a6 100644 --- a/src/code_gen/mips_builder.py +++ b/src/code_gen/mips_builder.py @@ -6,6 +6,7 @@ import cmp.visitor as visitor import cmp.cil as cil import random +import enum from code_gen import mips_nodes as mips @@ -128,10 +129,10 @@ def __init__(self): def get_offset(self,x): if x in self.locals: index = self.locals.index(x) - return -4*index + return 4*index elif x in self.params: index = self.params.index(x) - return (-4 * (len(self.locals)+index)) + return (4 * (-len(self.params)+index)) def register_instruction(self, instruction_type, *args): instruction = instruction_type(*args) @@ -144,7 +145,7 @@ def register_data(self,data_type,*args): def register_push(self, reg): self.register_instruction(mips.StoreWordNode, reg, 0, sp) - self.register_instruction(mips.AddiNode, sp, sp, -4) + self.register_instruction(mips.AddiNode, sp, sp, 4) def register_pop(self, reg): self.register_instruction(mips.LoadWordNode, reg, 4, sp) @@ -222,7 +223,7 @@ def visit(self, node): self.visit(type) self.generate_attr_offset(type.name) - + self.generate_extra_static_labels self.generate_exception_messages() for str_data in node.dotdata: @@ -263,7 +264,7 @@ def visit(self, node): @visitor.when(cil.DataNode) def visit(self, node): - self.register_data(mips.DataTypeNode,'.ascii',node.name,[node.value]) + self.register_data(mips.DataTypeNode,'.asciiz',node.name,[node.value]) @@ -296,22 +297,27 @@ def visit(self,node): @visitor.when(cil.FunctionNode) def visit(self,node): - + self.memo.save() locals_save = self.locals params_save = self.params self.locals, self.params = [], [] self.current_procedure = mips.ProcedureNode(node.name) + + saved_fp = self.memo.get_unused_reg() + self.register_instruction(mips.MoveNode, saved_fp, fp) + + self.register_instruction(mips.CommentNode,"New $fp") + self.register_instruction(mips.MoveNode, fp, sp) + + self.register_instruction(mips.CommentNode,"Reserving space for locals") + self.register_instruction(mips.AddiNode, sp, sp, 4*len(node.localvars)) self.register_instruction(mips.CommentNode,"Pushing $ra") self.register_push(ra) self.register_instruction(mips.CommentNode,"Saving $fp") - self.register_push(fp) - self.register_instruction(mips.CommentNode,"New $fp") - self.register_instruction(mips.MoveNode, fp, sp) - - self.register_instruction(mips.CommentNode,"Reserving space for locals") - self.register_instruction(mips.AddiNode, sp, sp, -4*len(node.localvars)) + self.register_push(saved_fp) + self.memo.clean() for local in node.localvars: self.locals.append(local.name) @@ -323,15 +329,16 @@ def visit(self,node): for inst in node.instructions: self.visit(inst) - + self.register_instruction(mips.CommentNode,"Restoring saved $fp") + self.register_instruction(mips.AddiNode,sp,sp,-4) + self.register_instruction(mips.LoadWordNode,fp,0,sp) + self.register_instruction(mips.CommentNode,"Restoring saved $ra") - self.register_instruction(mips.LoadWordNode, ra, RA_OFFSET, fp)#stored $ra - + self.register_instruction(mips.AddiNode,sp,sp,-4) + self.register_instruction(mips.LoadWordNode,fp,0,sp) - self.register_instruction(mips.CommentNode,"Restoring saved $fp") - self.register_instruction(mips.LoadWordNode, fp, OLD_FP_OFFSET, fp)#stored (old)$fp - AR = 4*(len(node.localvars) + 2) + AR = -4*(len(node.localvars)) self.register_instruction(mips.CommentNode,"Cleaning stack after call") self.register_instruction(mips.AddiNode, sp, sp, AR) @@ -370,7 +377,7 @@ def visit(self, node: cil.LoadNode): self.register_instruction(mips.StoreWordNode,v0,dest_offset,fp) reg = self.memo.get_unused_reg() - self.register_instruction(mips.LoadAddress,reg,f'{STRING}_name') + self.register_instruction(mips.LoadAddress,reg,STRING) self.register_instruction(mips.StoreWordNode,reg,0,v0) #storing string length @@ -420,7 +427,7 @@ def visit(self,node): self.register_instruction(mips.StoreWordNode,v0,dest_offset,fp) reg = self.memo.get_unused_reg() - self.register_instruction(mips.LoadAddress,reg,'f{node.type}_name') + self.register_instruction(mips.LoadAddress,reg,node.type) self.register_instruction(mips.StoreWordNode,reg,0,v0) self.memo.clean() @@ -496,24 +503,28 @@ def visit(self,node): dest_offset = self.get_offset(node.dest) self.register_instruction(mips.StoreWordNode,a1,dest_offset,fp) - self.register_instruction(mips.AddiNode,sp,sp,self.pushed_args * 4) + self.register_instruction(mips.AddiNode,sp,sp,self.pushed_args * -4) self.pushed_args = 0 @visitor.when(cil.DynamicCallNode) def visit(self,node): self.memo.save() - reg1 = self.memo.get_unused_reg() - reg2 = self.memo.get_unused_reg() - - instance_offset = self.get_offset(node.instance) - self.register_instruction(mips.CommentNode,"Getting type of instance") - self.register_instruction(mips.LoadWordNode,reg1,instance_offset,fp) - + #getting method offset _methods = self.types[node.type].methods - meth_offset = _methods.index(node.method) + _function = None + + for (meth,func) in _methods: + if node.method == meth: + _function = func + + _functions = [func for (meth,func) in (_methods)] + meth_offset = _functions.index(_function) + + self.register_instruction(mips.LoadAddress,reg1,node.type) + reg2 = self.memo.get_unused_reg() self.register_instruction(mips.LoadWordNode,reg2,meth_offset*4,reg1) self.register_instruction(mips.JumpAndLink,reg2) @@ -579,7 +590,7 @@ def visit(self,node): self.register_instruction(mips.StoreWordNode,v0,dest_offset,fp) reg = self.memo.get_unused_reg() - self.register_instruction(mips.LoadAddress,reg,f'{STRING}_name') + self.register_instruction(mips.LoadAddress,reg,STRING) self.register_instruction(mips.StoreWordNode,reg,0,v0) self.register_instruction(mips.LoadInmediate,reg,0) @@ -745,7 +756,7 @@ def visit(self,node): self.register_instruction(mips.StoreWordNode,v0,dest_offset,fp) reg = self.memo.get_unused_reg() - self.register_instruction(mips.LoadAddress,reg,f'{STRING}_name') + self.register_instruction(mips.LoadAddress,reg,STRING) self.register_instruction(mips.StoreWordNode,reg,0,v0) #storing string length From 6847e9af69ece0382def520e6509bb5eb8e80a00 Mon Sep 17 00:00:00 2001 From: gabriela Date: Sun, 6 Mar 2022 13:59:21 -0500 Subject: [PATCH 106/162] Correct details in error reporting mecanism. Remove unnecessary errors. Adecuate last errors to cool custom errors. --- src/type_builder.py | 6 +++--- src/type_checker.py | 16 ++++++---------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/type_builder.py b/src/type_builder.py index e6180093f..9b13090d6 100644 --- a/src/type_builder.py +++ b/src/type_builder.py @@ -153,7 +153,6 @@ def visit(self, node): @visitor.when(ClassDeclarationNode) def visit(self, node): - # print(f"------------visiting class {node.id}------------") self.current_type = self.context.get_type(node.id) if node.parent is not None: @@ -167,8 +166,9 @@ def visit(self, node): object_type = self.context.get_type("Object") try: self.current_type.set_parent(object_type) - except SError as error: - self.errors.append(error.text) + except SError as error: # this is actually an intern error, a class parent most not be setted twice (is valid to note that the intention to inherit from a prohibited class is considered a semantic error) + node_row, node_col = node.token.location + self.errors.append(SemanticError(node_row, node_col, error.text)) for feature in node.features: self.visit(feature) diff --git a/src/type_checker.py b/src/type_checker.py index a136c6e56..b29141dcd 100644 --- a/src/type_checker.py +++ b/src/type_checker.py @@ -242,8 +242,9 @@ def visit(self, node, scope): self.errors.append(SemanticError(node_row, node_col, "Cannot assign to 'self'. " + SELF_IS_READONLY)) var_type = None if not scope.is_defined(node.id.lex): + node_row, node_col = node.id.location self.errors.append( - VARIABLE_NOT_DEFINED % (node.id, self.current_method.name) + NameError(node_row, node_col, VARIABLE_NOT_DEFINED % (node.id.lex, self.current_method.name)) ) var_type = ErrorType() else: @@ -251,7 +252,8 @@ def visit(self, node, scope): expr_type = self.visit(node.expr, scope) if not expr_type.conforms_to(var_type): - self.errors.append(INCOMPATIBLE_TYPES % (expr_type.name, var_type.name)) + node_row, node_col = node.token.location + self.errors.append(TypeError(node_row, node_col, f"Inferred type {expr_type.name} of assigned expression does not conforms to type {var_type.name} of variable '{node.id.lex}'")) return expr_type @@ -362,14 +364,12 @@ def visit(self, node, scope): static_type = self.context.get_type(node.type.lex) if static_type.name == "SELF_TYPE": static_type = self.current_type - # scope.define_variable(node.id, static_type) except SError as e: node_row, node_col = node.type.location self.errors.append( TypeError(node_row, node_col, e.text) ) - # return ErrorType() static_type = ErrorType() if node.expr != None: @@ -406,14 +406,10 @@ def visit(self, node, scope): def visit(self, node, scope): try: static_type = self.context.get_type(node.type.lex) - try: - scope.define_variable(node.id.lex, static_type) - except SError as e: - self.errors.append(e) - return ErrorType() + scope.define_variable(node.id.lex, static_type) except SError as e: node_row, node_col = node.type.location - self.errors.append(TypeError(node_row, node_col, f"Class {node.type.lex} of case branch is undefined.")) + self.errors.append(TypeError(node_row, node_col, f"Type {node.type.lex} of case branch is undefined.")) typex = self.visit(node.expr, scope) From e647667bb90f68f4d030a30ebe82241ba7e2cd3d Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Sun, 6 Mar 2022 15:38:59 -0500 Subject: [PATCH 107/162] ref: clean unnecessary props from visitor --- src/code_gen/cil_builder.py | 41 +++++++++++-------------------------- 1 file changed, 12 insertions(+), 29 deletions(-) diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index c7c428994..3b2f58472 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -57,33 +57,22 @@ class CILBuilder: - def __init__(self, errors=[]): + def __init__(self): self.types = [] self.code = [] self.data = [] self.current_type = None self.current_function = None - self.errors = errors - self.method_count = 0 self.string_count = 0 - self.temp_vars_count = 0 self._count = 0 self.internal_count = 0 self.context = None self.self_var = "self" - def generate_next_method_id(self): - self.method_count += 1 - return "method_" + str(self.method_count) - def generate_next_string_id(self): self.string_count += 1 return "string_" + str(self.string_count) - def generate_next_tvar_id(self): - self.temp_vars_count += 1 - return "v_" + str(self.temp_vars_count) - def next_id(self): self._count += 1 return str(self._count) @@ -143,11 +132,6 @@ def define_internal_local(self): vinfo = VariableInfo("internal", None) return self.register_local(vinfo) - def register_data(self, name, value): - data_node = DataNode(name, value) - self.data.append(data_node) - return data_node - def is_attribute(self, vname): return vname not in [var.name for var in self.current_function.localvars] and ( vname not in [param.name for param in self.current_function.params] @@ -346,6 +330,16 @@ def io_inint(self): self.register_instruction(ReadNode(ret_vinfo)) # TODO: ReadInt? self.register_instruction(ReturnNode(ret_vinfo)) + def reset_state(self): + self.types = [] + self.code = [] + self.data = [] + self.current_type = None + self.current_function = None + self.string_count = 0 + self._count = 0 + self.context = None + @visitor.on("node") def visit(self, node=None, return_var=None): pass @@ -382,18 +376,7 @@ def visit(self, node, return_var=None): program_node = ProgramNode(self.types, self.data, self.code) - # Reset state - self.types = [] - self.code = [] - self.data = [] - self.current_type = None - self.current_function = None - self.errors = [] - self.method_count = 0 - self.string_count = 0 - self.temp_vars_count = 0 - self._count = 0 - self.context = None + self.reset_state() return program_node From 7a5140394f8561bae94742d6400245485ce36c2d Mon Sep 17 00:00:00 2001 From: smartos99 Date: Sun, 6 Mar 2022 16:07:31 -0500 Subject: [PATCH 108/162] Fix mips_writer --- src/code_gen/mips_builder.py | 38 ++++++++++++++++++------------------ src/code_gen/mips_writer.py | 4 ++-- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/code_gen/mips_builder.py b/src/code_gen/mips_builder.py index 4400099a6..00e026626 100644 --- a/src/code_gen/mips_builder.py +++ b/src/code_gen/mips_builder.py @@ -513,25 +513,25 @@ def visit(self,node): reg1 = self.memo.get_unused_reg() #getting method offset - _methods = self.types[node.type].methods - _function = None - - for (meth,func) in _methods: - if node.method == meth: - _function = func - - _functions = [func for (meth,func) in (_methods)] - meth_offset = _functions.index(_function) - - self.register_instruction(mips.LoadAddress,reg1,node.type) - reg2 = self.memo.get_unused_reg() - self.register_instruction(mips.LoadWordNode,reg2,meth_offset*4,reg1) - - self.register_instruction(mips.JumpAndLink,reg2) - - #putting the return vslue in destination - dest_offset = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode,a1,dest_offset,fp) + #_methods = self.types[node.type].methods + #_function = None + # + #for (meth,func) in _methods: + # if node.method == meth: + # _function = func + # + #_functions = [func for (meth,func) in (_methods)] + #meth_offset = _functions.index(_function) + # + #self.register_instruction(mips.LoadAddress,reg1,node.type) + #reg2 = self.memo.get_unused_reg() + #self.register_instruction(mips.LoadWordNode,reg2,meth_offset*4,reg1) + # + #self.register_instruction(mips.JumpAndLink,reg2) + # + ##putting the return vslue in destination + #dest_offset = self.get_offset(node.dest) + #self.register_instruction(mips.StoreWordNode,a1,dest_offset,fp) self.memo.clean() diff --git a/src/code_gen/mips_writer.py b/src/code_gen/mips_writer.py index 3ce0a79aa..8dabf5e26 100644 --- a/src/code_gen/mips_writer.py +++ b/src/code_gen/mips_writer.py @@ -17,14 +17,14 @@ def black(self): def visit(self, node:mips.ProgramNode): self.emit(".data") self.black() - for data in node.dotdata: + for data in node.data: self.emit(str(data)) self.black() self.emit(".text") self.emit(".globl main") self.black() - for proc in node.dottext: + for proc in node.text: self.emit(f'{proc.label}:') self.tabs += 4 for inst in proc.instructions: From 83d06305ed380023780862c54aee23c532e19490 Mon Sep 17 00:00:00 2001 From: gabriela Date: Sun, 6 Mar 2022 19:16:10 -0500 Subject: [PATCH 109/162] Complete sematic checking. Adjust final details related to tokens added to the pipeline. --- customized_tests/semantics/assignment.cl | 12 ++++++++ src/cool_grammar.py | 4 +-- src/type_builder.py | 22 +++++++------- src/type_checker.py | 38 ++++++++++++------------ src/type_collector.py | 6 ++-- 5 files changed, 47 insertions(+), 35 deletions(-) create mode 100644 customized_tests/semantics/assignment.cl diff --git a/customized_tests/semantics/assignment.cl b/customized_tests/semantics/assignment.cl new file mode 100644 index 000000000..0575c98aa --- /dev/null +++ b/customized_tests/semantics/assignment.cl @@ -0,0 +1,12 @@ +--Attributes are local to the class in which they are defined or inherited. + +class A { + a: Int <- 5; + test(x1: Int, y1: Int): Int { + let x: Int <- x1, y: Int <-y1 in { + x <- "x + a"; + f <- y + a; + if b then x + y else x - y fi; + } + }; +}; \ No newline at end of file diff --git a/src/cool_grammar.py b/src/cool_grammar.py index b2b767476..d375edbc6 100644 --- a/src/cool_grammar.py +++ b/src/cool_grammar.py @@ -71,11 +71,11 @@ def define_cool_grammar(print_grammar=False): def_class %= ( classx + type_id + ocur + feature_list + ccur + semi, - lambda h, s: ClassDeclarationNode(s[2].lex, s[4], s[1]), + lambda h, s: ClassDeclarationNode(s[2], s[4], s[1]), ) def_class %= ( classx + type_id + inherits + type_id + ocur + feature_list + ccur + semi, - lambda h, s: ClassDeclarationNode(s[2].lex, s[6], s[1], s[4]), # aqui hay que buscar otra alternativa a simplemente pasar el lexema pues a la hora de dar errores estaria bien decir que el tipo que se refencia noe sta definido + lambda h, s: ClassDeclarationNode(s[2], s[6], s[1], s[4]), # aqui hay que buscar otra alternativa a simplemente pasar el lexema pues a la hora de dar errores estaria bien decir que el tipo que se refencia noe sta definido ) feature_list %= def_attr + semi + feature_list, lambda h, s: [s[1]] + s[3] diff --git a/src/type_builder.py b/src/type_builder.py index 9b13090d6..c5933cd43 100644 --- a/src/type_builder.py +++ b/src/type_builder.py @@ -118,7 +118,7 @@ def visit(self, node): except: not_visited.remove(class_declaration) try: - children = parent_child_dict[class_declaration.id] + children = parent_child_dict[class_declaration.id.lex] for declaration in children: queue.append(declaration) except: # no one inherits from this class @@ -134,7 +134,7 @@ def visit(self, node): main_meth = self.context.get_type("Main").get_method("main", non_rec=True) if len(main_meth.param_names) > 0: self.errors.append( - '"main" method in class Main does not receive any parameters' + SemanticError(0, 0, '"main" method in class Main does not receive any parameters') ) # modify in semantic get_method in order to get some ancestor where the method is already defined except SError: @@ -153,12 +153,12 @@ def visit(self, node): @visitor.when(ClassDeclarationNode) def visit(self, node): - self.current_type = self.context.get_type(node.id) + self.current_type = self.context.get_type(node.id.lex) if node.parent is not None: try: - parent_type = self.get_type(node.parent, f"declared as {node.id}'s parent") - self.current_type.set_parent(parent_type) + parent_type = self.get_type(node.parent, f"declared as {node.id.lex}'s parent") + self.current_type.set_parent(parent_type) # set parent type if defined except SError as error: node_row, node_col = node.parent.location self.errors.append(SemanticError(node_row, node_col, error.text)) @@ -183,7 +183,7 @@ def visit(self, node): self.current_type.define_method( node.id.lex, param_names, param_types, return_type ) - except SError as error: + except SError as error: # method already defined node_row, node_col = node.id.location # print("--------aqui se esta reportando el error del metodo doble---------") self.errors.append(SemanticError(node_row, node_col,error.text)) @@ -197,7 +197,7 @@ def visit(self, node): try: attr_type = self.get_type(node.type, f"of attribute {node.id.lex}") self.current_type.define_attribute(node.id.lex, attr_type) - except SError as error: + except SError as error: # attribute already defined node_row, node_col = node.id.location self.errors.append(SemanticError(node_row, node_col,error.text)) @@ -216,7 +216,7 @@ def check_cycles(self, class_declarations): for class_declaration in class_declarations: if not (class_declaration.parent is None): - d = class_declaration.id + d = class_declaration.id.lex p = class_declaration.parent.lex modified_paths = paths @@ -232,7 +232,7 @@ def check_cycles(self, class_declarations): # error node_row, node_col = class_declaration.parent.location self.errors.append( - SemanticError(node_row, node_col, f"Class {class_declaration.id}, or an ancestor of {class_declaration.id}, is involved in an inheritance cycle.") + SemanticError(node_row, node_col, f"Class {class_declaration.id.lex}, or an ancestor of {class_declaration.id.lex}, is involved in an inheritance cycle.") ) already_in_some_path = True @@ -244,7 +244,7 @@ def check_cycles(self, class_declarations): # error node_row, node_col = class_declaration.parent.location self.errors.append( - SemanticError(node_row, node_col, f"Class {class_declaration.id}, or an ancestor of {class_declaration.id}, is involved in an inheritance cycle.") + SemanticError(node_row, node_col, f"Class {class_declaration.id.lex}, or an ancestor of {class_declaration.id.lex}, is involved in an inheritance cycle.") ) already_in_some_path = True @@ -260,6 +260,6 @@ def check_cycles(self, class_declarations): else: # class inherits from itself node_row, node_col = class_declaration.parent.location self.errors.append( - SemanticError(node_row, node_col, f"Class {class_declaration.id}, or an ancestor of {class_declaration.id}, is involved in an inheritance cycle.") + SemanticError(node_row, node_col, f"Class {class_declaration.id.lex}, or an ancestor of {class_declaration.id.lex}, is involved in an inheritance cycle.") ) paths = modified_paths \ No newline at end of file diff --git a/src/type_checker.py b/src/type_checker.py index b29141dcd..dbde319be 100644 --- a/src/type_checker.py +++ b/src/type_checker.py @@ -77,10 +77,10 @@ def visit(self, node): self.class_visited = {} for declaration in node.declarations: try: - visited[declaration.id] # checking if visited + visited[declaration.id.lex] # checking if visited except: - visited[declaration.id] = True - self.class_visited[declaration.id] = False + visited[declaration.id.lex] = True + self.class_visited[declaration.id.lex] = False self.class_to_visit.append(declaration) if declaration.parent is None or declaration.parent.lex in ["IO", "Int", "String", "Bool"]: # is node has no parent, mark it to visit it first later initial_nodes.append(declaration) @@ -111,9 +111,9 @@ def visit(self, node): @visitor.when(ClassDeclarationNode) def visit(self, node, scope, parent_children_dict): self.class_to_visit.remove(node) - self.class_visited[node.id] = True # arked class as visited + self.class_visited[node.id.lex] = True # arked class as visited - self.current_type = self.context.get_type(node.id) + self.current_type = self.context.get_type(node.id.lex) scope.define_variable("self", self.current_type) for attr in self.current_type.attributes: @@ -123,9 +123,9 @@ def visit(self, node, scope, parent_children_dict): self.visit(feature, scope) try: - children = parent_children_dict[node.id] - for child in children:# after initialization, each parent class visits its children (note the child scope creation) - if not self.class_visited[child.id]: + children = parent_children_dict[node.id.lex] + for child in children: # after initialization, each parent class visits its children (note the child scope creation) + if not self.class_visited[child.id.lex]: self.visit(child, scope.create_child(), parent_children_dict) except: return @@ -168,7 +168,7 @@ def visit(self, node, scope): for i, param_name in enumerate(param_names): if param_name == "self": param_n, param_t = node.params[i] - node_row, node_col = param_n.location + node_row, node_col = param_n.location # location of param name self.errors.append( SemanticError(node_row, node_col ,f"'self' cannot be the name of a formal parameter.") ) @@ -187,9 +187,9 @@ def visit(self, node, scope): body_type = self.visit(node.body, child_scope) - if not body_type.conforms_to(method_return_type):#aqui se debe poner + if not body_type.conforms_to(method_return_type): node_row, node_col = node.body.token.location - self.errors.append(TypeError( node_row, node_col, f"Inferred return type '{body_type.name}' of method '{node.id.lex}' does not conform to declared return type '{method_return_type.name}'.")) + self.errors.append(TypeError( node_row, node_col, f"Inferred return type '{body_type.name}' of method '{node.id.lex}' (the type of the last expression) does not conform to declared return type '{method_return_type.name}'.")) if self.current_type.parent is not None: try: @@ -275,7 +275,7 @@ def visit(self, node, scope): node_at_type = self.context.get_type(node.at_type.lex) method = node_at_type.get_method(node.id.lex) if not typex.conforms_to(node_at_type): - node_row, node_col = node.token.location + node_row, node_col = node.at_type.location # maybe in node.obj self.errors.append( TypeError(node_row, node_col, f"Expression type {typex.name} does not conform to declared static dispatch type {node_at_type.name}.") ) @@ -296,7 +296,7 @@ def visit(self, node, scope): for arg, ptype in zip(node.args, method.param_types): arg_type = self.visit(arg, scope) if not arg_type.conforms_to(ptype): - node_row, node_col = arg.token.location # verificar si esto siempre da ok + node_row, node_col = arg.token.location self.errors.append(TypeError(node_row, node_col,f"In call of method {node.id.lex} parameter of type {arg_type.name} does not conforms to declared type {ptype.name}")) if method.return_type == self.context.get_type("SELF_TYPE"): @@ -309,7 +309,7 @@ def visit(self, node, scope): predicate_type = self.visit(node.if_expr, scope) if predicate_type.name != "Bool" and predicate_type.name != "AUTO_TYPE": - node_row, node_col = node.token.location + node_row, node_col = node.if_expr.token.location self.errors.append( TypeError(node_row, node_col, f"Expression after 'if' must be Bool, current type is {predicate_type.name}") ) @@ -327,7 +327,7 @@ def visit(self, node, scope): bool_type = self.context.get_type("Bool") if condition_type != bool_type and condition_type.name != "AUTO_TYPE": - node_row, node_col = node.token.location + node_row, node_col = node.condition.token.location self.errors.append( TypeError(node_row, node_col, f"Expression in 'while' condition must be bool, current type is {condition_type.name}") ) @@ -375,7 +375,7 @@ def visit(self, node, scope): if node.expr != None: typex = self.visit(node.expr, scope) if not typex.conforms_to(static_type): - line, col = node.token.location + line, col = node.expr.token.location self.errors.append(TypeError(line, col, INCOMPATIBLE_TYPES % (typex.name, static_type.name))) scope.define_variable(node.id, static_type) @@ -388,7 +388,7 @@ def visit(self, node, scope): current_case_type = None case_types_found = [] for item in node.case_items: - if not ( item.type.lex in case_types_found): + if not (item.type.lex in case_types_found): case_types_found.append(item.type.lex) child_scope = scope.create_child() case_item_type = self.visit(item, child_scope) @@ -489,7 +489,7 @@ def visit(self, node, scope): typex = self.visit(node.expr, scope) if typex != bool_type and not typex.name == "AUTO_TYPE": - line, col = node.token.location + line, col = node.expr.token.location self.errors.append( TypeError(line, col, f"Expression after 'not' must be Bool, current is {typex.name}") ) @@ -503,7 +503,7 @@ def visit(self, node, scope): typex = self.visit(node.expr, scope) if typex != int_type and not typex.name == "AUTO_TYPE": - node_row, node_col = node.token.location + node_row, node_col = node.expr.token.location self.errors.append( TypeError( node_row, node_col,f"Expression after '~' must be Int, current is {typex.name}") ) diff --git a/src/type_collector.py b/src/type_collector.py index c5837c1c3..7377a7bfb 100644 --- a/src/type_collector.py +++ b/src/type_collector.py @@ -60,7 +60,7 @@ def visit(self, node): @visitor.when(ClassDeclarationNode) def visit(self, node): try: - self.context.create_type(node.id) - except SError as error: - node_row, node_col = node.token.location + self.context.create_type(node.id.lex) + except SError as error: # class alerady defined + node_row, node_col = node.id.location self.errors.append(SemanticError(node_row, node_col, error.text)) From 085fa5a912f0e32447ac379ebd814937c1d143a7 Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Mon, 7 Mar 2022 01:10:51 -0500 Subject: [PATCH 110/162] fix: remove self.self_var. Add methods & attrs dicts --- customized_tests/test_hello_world.cl | 2 +- src/code_gen/cil_builder.py | 35 +++++++++++++++++++++++----- src/main.py | 2 +- 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/customized_tests/test_hello_world.cl b/customized_tests/test_hello_world.cl index 84701ff26..687c57c96 100644 --- a/customized_tests/test_hello_world.cl +++ b/customized_tests/test_hello_world.cl @@ -2,7 +2,7 @@ class Main inherits IO { msg : String <- "Hello World"; main() : IO{ - out_string(msg) + self@IO.out_string(msg) }; }; diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index 63336f53c..8c71bb72d 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -68,6 +68,8 @@ def __init__(self): self.internal_count = 0 self.context = None self.self_var = None + self.methods = {} + self.attrs = {} def generate_next_string_id(self): self.string_count += 1 @@ -352,6 +354,28 @@ def visit(self, node, return_var=None): self.add_builtin_functions() self.add_builtin_constructors() + for type in self.context.types.values(): + self.attrs[type.name] = { + attr.name: (i, htype.name) + for i, (attr, htype) in enumerate(type.all_attributes()) + } + self.methods[type.name] = { + method.name: (i, htype.name) + if htype.name != "Object" or method.name not in ["type_name", "copy"] + else (i, type.name) + for i, (method, htype) in enumerate(type.all_methods()) + } + # self.dottypes.append( + # cil.TypeNode( + # type.name, + # list(self.attrs[type.name].keys()), + # [ + # self.get_func_id(htype, method) + # for method, (_, htype) in self.methods[type.name].items() + # ], + # ) + # ) + self.current_function = FunctionNode("main", [], [], []) self.code.append(self.current_function) @@ -359,7 +383,7 @@ def visit(self, node, return_var=None): result = self.define_internal_local() main_constructor = self.to_function_name("constructor", "Main") - main_method_name = self.to_function_name("Main", "main") + main_method_name = self.to_function_name("main", "Main") # Get instance from constructor self.register_instruction(StaticCallNode(main_constructor, instance)) @@ -468,7 +492,7 @@ def visit(self, node, return_var): self.visit(node.obj, instance) else: - self.register_instruction(AssignNode(instance, self.self_var)) + self.register_instruction(AssignNode(instance, "self")) instance_type = None if not node.at_type: @@ -576,11 +600,12 @@ def visit(self, node, return_var=None): def visit(self, node, return_var=None): pass # TODO: Pending!!! - # expr_value = self.visit(node.expr) + # expr_value = self.define_internal_local() + # self.visit(node.expr, expr_value) # solve = self.define_internal_local() # for case_item in node.case_items: # item_expr_value = self.define_internal_local() - # self.visit(case_item) + # self.visit(case_item.) @visitor.when(cool.CaseItemNode) def visit(self, node, return_var=None): @@ -697,8 +722,6 @@ def visit(self, node, return_var): self.current_type.name, ) ) - elif node.lex == "self": - self.register_instruction(AssignNode(return_var, self.self_var)) else: self.register_instruction(AssignNode(return_var, node.lex)) diff --git a/src/main.py b/src/main.py index 4737dc32f..9e4d552c5 100644 --- a/src/main.py +++ b/src/main.py @@ -87,7 +87,7 @@ def pipeline(input_file: Path, output_file: Path = None): if len(errors) > 0: report_and_exit(errors) - cool_to_cil_visitor = CILBuilder(errors) + cool_to_cil_visitor = CILBuilder() cil_ast = cool_to_cil_visitor.visit(ast) formatter = PrintVisitor() From 455bbf464978525e8fd29ac7ffeb7f90fb2af864 Mon Sep 17 00:00:00 2001 From: gabriela Date: Mon, 7 Mar 2022 02:39:35 -0500 Subject: [PATCH 111/162] Modify type checker to add types. Creates a new ast (compatible with cil ast) while visiting original one for check semantics. Add return types. --- src/ast_typed_nodes.py | 196 +++++++++++++++++++++++++++++++++++++++++ src/main.py | 26 ++---- src/type_checker.py | 195 +++++++++++++++++++++++++--------------- 3 files changed, 331 insertions(+), 86 deletions(-) create mode 100644 src/ast_typed_nodes.py diff --git a/src/ast_typed_nodes.py b/src/ast_typed_nodes.py new file mode 100644 index 000000000..37e36a22b --- /dev/null +++ b/src/ast_typed_nodes.py @@ -0,0 +1,196 @@ +from cmp.semantic import Context + + +class Node: + pass + + +class ProgramNode(Node): + def __init__(self, declarations, context=None): + self.declarations = declarations + self.context = context + + +class ExpressionNode(Node): + def __init__(self, etype): + self.static_type = etype + + +class ClassDeclarationNode: + def __init__(self, idx, features, parent=None): + self.id = idx + self.parent = parent + self.features = features + +class FuncDeclarationNode: + def __init__(self, idx, params, return_type, body): + self.id = idx + self.params = params + self.type = return_type + self.body = body + + +class AttrDeclarationNode: + def __init__(self, idx, typex, init_exp=None): + self.id = idx + self.type = typex + self.init_exp = init_exp + + +class AssignNode(ExpressionNode): + def __init__(self, idx, expr, etype = None ): + self.id = idx + self.expr = expr + self.static_type = etype + + +class LetNode(ExpressionNode): + def __init__(self, identifiers, body, etype = None ): + self.identifiers = identifiers + self.body = body + self.static_type = etype + + +class VarDeclarationNode: + def __init__(self, idx, typex, expr=None, etype = None ): + self.id = idx + self.type = typex + self.expr = expr + self.static_type = etype + + +class IfNode(ExpressionNode): + def __init__(self, if_exp, then_exp, else_exp, etype = None ): + self.if_expr = if_exp + self.then_expr = then_exp + self.else_expr = else_exp + self.static_type = etype + + +class WhileNode(ExpressionNode): + def __init__(self, condition, body, etype = None ): + self.condition = condition + self.body = body + self.static_type = etype + + +class CaseNode(ExpressionNode): + def __init__(self, exp, case_items, etype = None ): + self.expr = exp + self.case_items = case_items + self.static_type = etype + + +class CaseItemNode(ExpressionNode): + def __init__(self, idx, typex, exp, etype = None ): + self.id = idx + self.type = typex + self.expr = exp + self.static_type = etype + + +class CallNode(ExpressionNode): + def __init__(self, idx, args, obj=None, at_type=None, obj_type = None, etype = None): + self.obj = obj + self.id = idx + self.args = args + self.at_type = at_type + self.obj_type = obj_type + self.static_type = etype + +class BlockNode(ExpressionNode): + def __init__(self, expression_list, etype = None ): + self.expression_list = expression_list + self.static_type = etype + + +class AtomicNode(ExpressionNode): + def __init__(self, lex, etype = None ): + self.lex = lex + self.static_type = etype + + +class UnaryNode(ExpressionNode): + def __init__(self, expr, etype = None ): + self.expr = expr + self.static_type = etype + + +class BinaryNode(ExpressionNode): + def __init__(self, left, right, etype = None ): + self.left = left + self.right = right + self.static_type = etype + + +class ArithmeticOperation(BinaryNode): + pass + + +class ComparisonOperation(BinaryNode): + pass + + +class ConstantNumNode(AtomicNode): + pass + + +class VariableNode(AtomicNode): + pass + + +class StringNode(AtomicNode): + pass + + +class BooleanNode(AtomicNode): + pass + + +class InstantiateNode(AtomicNode): + pass + + +class NotNode(UnaryNode): + pass + + +class IsvoidNode(UnaryNode): + pass + + +class NegNode(UnaryNode): + pass + + +class PlusNode(ArithmeticOperation): + pass + + +class MinusNode(ArithmeticOperation): + pass + + +class StarNode(ArithmeticOperation): + pass + + +class DivNode(ArithmeticOperation): + pass + + +class LessNode(ComparisonOperation): + pass + + +class LessEqualNode(ComparisonOperation): + pass + + +class EqualNode(ComparisonOperation): + pass + + +class DefaultValueNode(ExpressionNode): + def __init__(self, typex): + self.type = typex \ No newline at end of file diff --git a/src/main.py b/src/main.py index 1a5715635..d717e51a8 100644 --- a/src/main.py +++ b/src/main.py @@ -22,9 +22,9 @@ def report_and_exit(errors): if len(errors) == 0: raise typer.Exit(code=0) - typer.echo(errors[0]) - # for error in errors: - # typer.echo(error) + # typer.echo(errors[0]) + for error in errors: + typer.echo(error) raise typer.Exit(code=1) @@ -64,28 +64,20 @@ def pipeline(input_file: Path, output_file: Path = None): #get parsing tree ast = evaluate_reverse_parse(parse, operations, tokens) - # print("AST") - # print(ast) - #printing tree formatter = FormatVisitorST() tree = formatter.visit(ast) - # print(tree) - - # type_visitor = TypeCollector(errors) - # ast = type_visitor.visit(ast) - # print("Type visitor tree") - # print(ast.context) - + print(tree) + visitors = [TypeCollector(errors), TypeBuilder(errors)] for visitor in visitors: ast = visitor.visit(ast) type_checker = TypeChecker(errors) - scope = type_checker.visit(ast) + scope, typed_ast = type_checker.visit(ast) - # formatter = FormatVisitor() - # tree = formatter.visit(ast) - # print(tree) + formatter = FormatVisitor() + tree = formatter.visit(typed_ast) + print(tree) if len(errors) > 0: report_and_exit(errors) diff --git a/src/type_checker.py b/src/type_checker.py index dbde319be..8bdd3e8a6 100644 --- a/src/type_checker.py +++ b/src/type_checker.py @@ -41,8 +41,10 @@ from cmp.semantic import Scope from cmp.utils import find_least_type + import copy from errors import TypeError, NameError, SemanticError, AttributeError +import ast_typed_nodes as cool_type_nodes # some predefined errors WRONG_SIGNATURE = 'Method "%s" already defined in "%s" with a different signature.' @@ -94,6 +96,9 @@ def visit(self, node): except: # add declarations where parent is not defined initial_nodes.append(declaration) + # initialize a list for classDeclNodes of typed ast + self.tast_class_nodes = [] + for declaration in initial_nodes: # first visit root nodes self.visit(declaration, scope.create_child(), parent_children_dict) @@ -106,7 +111,7 @@ def visit(self, node): self.current_type = None self.current_method = None - return scope + return (scope, cool_type_nodes.ProgramNode(self.tast_class_nodes, copy.copy(self.context))) @visitor.when(ClassDeclarationNode) def visit(self, node, scope, parent_children_dict): @@ -119,8 +124,10 @@ def visit(self, node, scope, parent_children_dict): for attr in self.current_type.attributes: scope.define_variable(attr.name, attr.type) + new_features = [] for feature in node.features: - self.visit(feature, scope) + feature_node = self.visit(feature, scope) + new_features.append(feature_node) try: children = parent_children_dict[node.id.lex] @@ -128,7 +135,15 @@ def visit(self, node, scope, parent_children_dict): if not self.class_visited[child.id.lex]: self.visit(child, scope.create_child(), parent_children_dict) except: - return + # return + pass + if node.parent is None: + parent = None + else: + parent = node.parent.lex + + self.tast_class_nodes.append(cool_type_nodes.ClassDeclarationNode(node.id.lex, parent, new_features)) + @visitor.when(AttrDeclarationNode) def visit(self, node, scope): @@ -143,13 +158,14 @@ def visit(self, node, scope): if node.init_exp != None: - init_expr_type = self.visit(node.init_exp, scope) + init_expr_type, init_exp = self.visit(node.init_exp, scope) if not init_expr_type.conforms_to(typex): line, col = node.token.location self.errors.append(TypeError(line, col,INCOMPATIBLE_TYPES % (init_expr_type.name, typex.name))) - return typex + # return typex AQUI SE RETORNABA UN TIPO PERO NO ES NECESARIO + return cool_type_nodes.AttrDeclarationNode(node.id.lex, node.type.lex, init_exp) @visitor.when(FuncDeclarationNode) def visit(self, node, scope): @@ -163,18 +179,19 @@ def visit(self, node, scope): # ------------parameters most have differente names------------ param_names = self.current_method.param_names param_types = self.current_method.param_types - param_used = {} + param_used = {} # VERIFICAR SI ESTOS TIPOS SON STRING O DE LOS .NAME + new_params = [] for i, param_name in enumerate(param_names): + param_n, param_t = node.params[i] # AQUI A ESTO NO LE DEBERIA PREGUNTAR POR EL LEX? + new_params.append((param_n.lex, param_t.lex)) if param_name == "self": - param_n, param_t = node.params[i] node_row, node_col = param_n.location # location of param name self.errors.append( SemanticError(node_row, node_col ,f"'self' cannot be the name of a formal parameter.") ) try: param_used[param_name] - param_n, param_t = node.params[i] node_row, node_col = param_n.location self.errors.append( SemanticError(node_row, node_col ,f"Formal parameter '{param_name}' multiply defined in method '{node.id.lex}'") @@ -185,7 +202,7 @@ def visit(self, node, scope): # ------------------------------------------------------------- - body_type = self.visit(node.body, child_scope) + body_type, body_exp = self.visit(node.body, child_scope) if not body_type.conforms_to(method_return_type): node_row, node_col = node.body.token.location @@ -226,14 +243,16 @@ def visit(self, node, scope): try: return_type = self.context.get_type(node.type.lex) - if return_type.name == "SELF_TYPE": - return self.current_type - - return return_type + # if return_type.name == "SELF_TYPE": + # return self.current_type + # return return_type ESTAS LINEAS ESTAN DE MAS PUES NO HACE FALTA RETORNAR TIPO except SError as e: # Error already reported in type builder - return ErrorType() + # return ErrorType() + pass #it is not necessary to return a type in func declaration ndoes + + return cool_type_nodes.FuncDeclarationNode(node.id.lex, new_params, node.type.lex, body_exp) @visitor.when(AssignNode) def visit(self, node, scope): @@ -250,28 +269,37 @@ def visit(self, node, scope): else: var_type = scope.find_variable(node.id.lex).type - expr_type = self.visit(node.expr, scope) + expr_type, exp_node = self.visit(node.expr, scope) if not expr_type.conforms_to(var_type): node_row, node_col = node.token.location self.errors.append(TypeError(node_row, node_col, f"Inferred type {expr_type.name} of assigned expression does not conforms to type {var_type.name} of variable '{node.id.lex}'")) - return expr_type + return (expr_type, cool_type_nodes.AssignNode(node.id.lex, exp_node, expr_type)) @visitor.when(CallNode) def visit(self, node, scope): auto_type = self.context.get_type("AUTO_TYPE") typex = None if node.obj is not None: - typex = self.visit(node.obj, scope) + typex, obj_exp = self.visit(node.obj, scope) if typex == auto_type: return auto_type else: typex = self.current_type - + obj_exp = None + + new_args = [] + arg_types = [] + for arg in node.args: # visiting arguments in case of earlier return + arg_type, arg_node = self.visit(arg, scope) + new_args.append(arg_node) + arg_types.append(arg_type) + method = None try: if not( node.at_type is None): + at_type = node.at_type.lex node_at_type = self.context.get_type(node.at_type.lex) method = node_at_type.get_method(node.id.lex) if not typex.conforms_to(node_at_type): @@ -279,13 +307,16 @@ def visit(self, node, scope): self.errors.append( TypeError(node_row, node_col, f"Expression type {typex.name} does not conform to declared static dispatch type {node_at_type.name}.") ) - return ErrorType() + return (ErrorType(), cool_type_nodes.CallNode(obj_exp, node.id.lex, new_args, at_type, typex, ErrorType())) + else: + at_type = None method = typex.get_method(node.id.lex) except SError as error: node_col, node_row = node.token.location self.errors.append(AttributeError(node_col, node_row ,error.text)) - return ErrorType() + return (ErrorType(), cool_type_nodes.CallNode(obj_exp, node.id.lex, new_args, at_type, typex, ErrorType())) + if len(method.param_names) != len(node.args): node_row, node_col = node.id.location @@ -293,37 +324,41 @@ def visit(self, node, scope): SemanticError(node_row, node_col, f"There is no definition of {method.name} that takes {len(node.args)} arguments ") ) - for arg, ptype in zip(node.args, method.param_types): - arg_type = self.visit(arg, scope) + # for i in range(0, node.args): + for i, arg in enumerate(node.args): + arg_type = arg_types[i] + ptype = method.param_types[i] if not arg_type.conforms_to(ptype): node_row, node_col = arg.token.location self.errors.append(TypeError(node_row, node_col,f"In call of method {node.id.lex} parameter of type {arg_type.name} does not conforms to declared type {ptype.name}")) if method.return_type == self.context.get_type("SELF_TYPE"): - return typex + return (typex, cool_type_nodes.CallNode(obj_exp, node.id.lex, new_args, at_type, typex, typex)) + - return method.return_type + return (method.return_type, cool_type_nodes.CallNode(obj_exp, node.id.lex, new_args, at_type, typex, method.return_type)) @visitor.when(IfNode) def visit(self, node, scope): - predicate_type = self.visit(node.if_expr, scope) + predicate_type, if_node = self.visit(node.if_expr, scope) + then_type, then_node = self.visit(node.then_expr, scope) + else_type, else_node = self.visit(node.else_expr, scope) if predicate_type.name != "Bool" and predicate_type.name != "AUTO_TYPE": node_row, node_col = node.if_expr.token.location self.errors.append( TypeError(node_row, node_col, f"Expression after 'if' must be Bool, current type is {predicate_type.name}") ) - return ErrorType() - - then_type = self.visit(node.then_expr, scope) - else_type = self.visit(node.else_expr, scope) + return (ErrorType(), cool_type_nodes.IfNode(if_node, else_node, then_node, ErrorType())) least_type = find_least_type(then_type, else_type, self.context) - return least_type + return (least_type, cool_type_nodes.IfNode(if_node, else_node, then_node, least_type)) + @visitor.when(WhileNode) def visit(self, node, scope): - condition_type = self.visit(node.condition, scope) + condition_type, condition_node = self.visit(node.condition, scope) + body_type, body_node = self.visit(node.body, scope) bool_type = self.context.get_type("Bool") if condition_type != bool_type and condition_type.name != "AUTO_TYPE": @@ -331,27 +366,33 @@ def visit(self, node, scope): self.errors.append( TypeError(node_row, node_col, f"Expression in 'while' condition must be bool, current type is {condition_type.name}") ) - return ErrorType() + return (ErrorType(), cool_type_nodes.WhileNode(condition_node, body_node, ErrorType())) - return self.context.get_type("Object") + obj_type = self.context.get_type("Object") + return (obj_type, cool_type_nodes.WhileNode(condition_node, body_node, obj_type)) @visitor.when(BlockNode) def visit(self, node, scope): typex = None + new_exp_list = [] for expr in node.expression_list: - typex = self.visit(expr, scope) + typex, node_exp = self.visit(expr, scope) + new_exp_list.append(node_exp) - return typex + return (typex, cool_type_nodes.BlockNode(new_exp_list, typex)) @visitor.when(LetNode) def visit(self, node, scope): child_scope = scope.create_child() + new_var_list = [] for var_dec in node.identifiers: - self.visit(var_dec, child_scope) + var_type, var_node = self.visit(var_dec, child_scope) + new_var_list.append(var_node) - return self.visit(node.body, child_scope) + exp_type, body_exp = self.visit(node.body, child_scope) + return (exp_type, cool_type_nodes.LetNode(new_var_list, body_exp, exp_type)) @visitor.when(VarDeclarationNode) def visit(self, node, scope): @@ -373,25 +414,28 @@ def visit(self, node, scope): static_type = ErrorType() if node.expr != None: - typex = self.visit(node.expr, scope) + typex, node_exp = self.visit(node.expr, scope) if not typex.conforms_to(static_type): line, col = node.expr.token.location self.errors.append(TypeError(line, col, INCOMPATIBLE_TYPES % (typex.name, static_type.name))) + else: + node_exp = None scope.define_variable(node.id, static_type) - return static_type + return (static_type, cool_type_nodes.VarDeclarationNode(node.id, node.type.lex, node_exp, static_type)) @visitor.when(CaseNode) def visit(self, node, scope): - self.visit(node.expr, scope) - + exp_node_type, node_exp = self.visit(node.expr, scope) + new_case_items = [] current_case_type = None case_types_found = [] for item in node.case_items: if not (item.type.lex in case_types_found): case_types_found.append(item.type.lex) child_scope = scope.create_child() - case_item_type = self.visit(item, child_scope) + case_item_type, item_node = self.visit(item, child_scope) + new_case_items.append(item_node) current_case_type = find_least_type( current_case_type, case_item_type, self.context ) @@ -400,7 +444,8 @@ def visit(self, node, scope): self.errors.append(SemanticError(line, col, f"Duplicate branch {item.type.lex} in case statement")) - return current_case_type + return (current_case_type, cool_type_nodes.CaseNode(node_exp, new_case_items, current_case_type)) + @visitor.when(CaseItemNode) def visit(self, node, scope): @@ -411,9 +456,9 @@ def visit(self, node, scope): node_row, node_col = node.type.location self.errors.append(TypeError(node_row, node_col, f"Type {node.type.lex} of case branch is undefined.")) - typex = self.visit(node.expr, scope) + typex, node_exp = self.visit(node.expr, scope) + return (typex, cool_type_nodes.CaseItemNode(node.id.lex, node.type.lex, node_exp, typex)) - return typex @visitor.when(InstantiateNode) # NewNode def visit(self, node, scope): @@ -421,22 +466,25 @@ def visit(self, node, scope): typex = self.context.get_type(node.lex.lex) if typex.name == "SELF_TYPE": return self.current_type - return typex + return (typex, cool_type_nodes.InstantiateNode(node.lex.lex, typex)) + except SError as error: node_row, node_col = node.lex.location self.errors.append(TypeError(node_row, node_col, f"Type {node.lex.lex} of 'new' expression is not defined.")) - return ErrorType() + return (ErrorType(), cool_type_nodes.InstantiateNode(node.lex.lex, ErrorType())) @visitor.when(IsvoidNode) def visit(self, node, scope): - self.visit(node.expr, scope) - return self.context.get_type("Bool") + type_exp, node_exp = self.visit(node.expr, scope) + bool_type = self.context.get_type("Bool") + return (bool_type, cool_type_nodes.IsvoidNode(node_exp, bool_type)) + @visitor.when(ArithmeticOperation) def visit(self, node, scope): int_type = self.context.get_type("Int") - left_type = self.visit(node.left, scope) - right_type = self.visit(node.right, scope) + left_type, left_exp_node = self.visit(node.left, scope) + right_type, right_exp_node = self.visit(node.right, scope) if (left_type != int_type and left_type.name != "AUTO_TYPE") or ( right_type != int_type and right_type.name != "AUTO_TYPE" @@ -444,13 +492,14 @@ def visit(self, node, scope): node_row, node_col = node.token.location self.errors.append(TypeError( node_row, node_col, INVALID_OPERATION % (left_type.name, right_type.name))) - return int_type + return (int_type, cool_type_nodes.ArithmeticOperation(left_exp_node, right_exp_node, int_type)) + @visitor.when(ComparisonOperation) def visit(self, node, scope): int_type = self.context.get_type("Int") - left_type = self.visit(node.left, scope) - right_type = self.visit(node.right, scope) + left_type, left_exp_node = self.visit(node.left, scope) + right_type, right_exp_node, = self.visit(node.right, scope) if (left_type != int_type and left_type.name != "AUTO_TYPE") or ( right_type != int_type and right_type.name != "AUTO_TYPE" @@ -458,7 +507,8 @@ def visit(self, node, scope): node_row, node_col = node.token.location self.errors.append(TypeError( node_row, node_col, INVALID_OPERATION % (left_type.name, right_type.name))) - return self.context.get_type("Bool") + bool_type = self.context.get_type("Bool") + return (bool_type, cool_type_nodes.ComparisonOperation(left_exp_node, right_exp_node, bool_type)) @visitor.when(EqualNode) def visit(self, node, scope): @@ -467,8 +517,8 @@ def visit(self, node, scope): bool_type = self.context.get_type("Bool") built_in_types = [int_type, string_type, bool_type] - left_type = self.visit(node.left, scope) - right_type = self.visit(node.right, scope) + left_type, left_exp_node = self.visit(node.left, scope) + right_type, right_exp_node = self.visit(node.right, scope) if left_type in built_in_types or right_type in built_in_types: if ( @@ -481,39 +531,43 @@ def visit(self, node, scope): TypeError(node_row, node_col, f"One of the expressions of '=' operator is of type Int, String or Bool, the other must have the same static type. Left type: {left_type.name}. Right type: {right_type.name}") ) - return self.context.get_type("Bool") + return (bool_type, cool_type_nodes.EqualNode(left_exp_node, right_exp_node, bool_type)) + @visitor.when(NotNode) def visit(self, node, scope): bool_type = self.context.get_type("Bool") - typex = self.visit(node.expr, scope) + typex, exp_node = self.visit(node.expr, scope) if typex != bool_type and not typex.name == "AUTO_TYPE": line, col = node.expr.token.location self.errors.append( TypeError(line, col, f"Expression after 'not' must be Bool, current is {typex.name}") ) - return ErrorType() + return (ErrorType(), cool_type_nodes.NotNode(exp_node, ErrorType())) + + return (bool_type, cool_type_nodes.NotNode(exp_node, bool_type)) - return bool_type @visitor.when(NegNode) def visit(self, node, scope): int_type = self.context.get_type("Int") - typex = self.visit(node.expr, scope) + typex, exp_node = self.visit(node.expr, scope) if typex != int_type and not typex.name == "AUTO_TYPE": node_row, node_col = node.expr.token.location self.errors.append( TypeError( node_row, node_col,f"Expression after '~' must be Int, current is {typex.name}") ) - return ErrorType() + return (ErrorType(), cool_type_nodes.NegNode(exp_node, ErrorType())) + + return (int_type, cool_type_nodes.NegNode(exp_node, int_type)) - return int_type @visitor.when(ConstantNumNode) def visit(self, node, scope): - return self.context.get_type("Int") + node_type = self.context.get_type("Int") + return (node_type, cool_type_nodes.ConstantNumNode(node.lex, node_type)) @visitor.when(VariableNode) def visit(self, node, scope): @@ -523,13 +577,16 @@ def visit(self, node, scope): self.errors.append( NameError( node_row, node_col,VARIABLE_NOT_DEFINED % (node.lex, self.current_method.name)) ) - return ErrorType() - return var.type + return (ErrorType(), cool_type_nodes.VariableNode(node.lex, ErrorType())) + + return (var.type, cool_type_nodes.VariableNode(node.lex, var.type)) @visitor.when(StringNode) def visit(self, node, scope): - return self.context.get_type("String") + node_type = self.context.get_type("String") + return (node_type, cool_type_nodes.StringNode(node.lex, node_type)) @visitor.when(BooleanNode) def visit(self, node, scope): - return self.context.get_type("Bool") + node_type = self.context.get_type("Bool") + return (node_type, cool_type_nodes.BooleanNode(node.lex, node_type)) From 654ec3383c3e7459277b04e67854bf9f02ef7091 Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Mon, 7 Mar 2022 11:12:51 -0500 Subject: [PATCH 112/162] fix: send args all at once --- customized_tests/test_hello_world.cl | 20 ++++++++++---------- src/code_gen/cil_builder.py | 15 +++++++++------ 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/customized_tests/test_hello_world.cl b/customized_tests/test_hello_world.cl index 687c57c96..eff360d5b 100644 --- a/customized_tests/test_hello_world.cl +++ b/customized_tests/test_hello_world.cl @@ -1,27 +1,27 @@ -class Main inherits IO { +(* class Main inherits IO { msg : String <- "Hello World"; main() : IO{ self@IO.out_string(msg) }; }; +*) -(* class Main { +class Main inherits IO{ main (): Object { - 0 + self@IO.out_int((new Point)@Point.init(5, 6)) + }; }; -class Point { +class Point{ x: Int; y: Int; - init(x0: AUTO_TYPE, y0: AUTO_TYPE): AUTO_TYPE { { - x <- x0; - y <- y0; - self; - } }; + init(x0: AUTO_TYPE, y0: AUTO_TYPE): AUTO_TYPE { + x0 + y0 + }; }; -*) \ No newline at end of file + diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index 8c71bb72d..f0ccb842b 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -316,10 +316,10 @@ def io_outint(self): self.params.append(ParamNode("self")) int_arg = VariableInfo("int") self.register_param(int_arg) - result = self.define_internal_local() - self.register_instruction(ToStrNode(result, int_arg.name)) - self.register_instruction(PrintIntNode(result)) - self.register_instruction(ReturnNode(VariableInfo(result).name)) + # result = self.define_internal_local() + # self.register_instruction(ToStrNode(result, int_arg.name)) + self.register_instruction(PrintIntNode(int_arg)) + self.register_instruction(ReturnNode("self")) def io_instring(self): self.params.append(ParamNode("self")) @@ -499,11 +499,14 @@ def visit(self, node, return_var): instance_type = self.define_internal_local() self.register_instruction(TypeOfNode(instance, instance_type)) - self.register_instruction(ArgNode(instance)) + args = [instance] for arg in node.args: arg_value = self.define_internal_local() self.visit(arg, arg_value) - self.register_instruction(ArgNode(arg_value)) + args.append(arg_value) + + for arg in args: + self.register_instruction(ArgNode(arg)) if node.at_type: self.register_instruction( From d22332ccc9e0b8c0fea36ba2c2bf331017ee6b0a Mon Sep 17 00:00:00 2001 From: gabriela Date: Mon, 7 Mar 2022 11:28:12 -0500 Subject: [PATCH 113/162] Check for None params while building typed ast. Check for None params while building typed ast to avoid errors. Reorganized parameters that were being passed in the wrong order. --- customized_tests/semantics/methods.cl | 3 + src/main.py | 18 +-- src/type_checker.py | 117 ++++++++++---- src/visitor_type_ast.py | 215 ++++++++++++++++++++++++++ 4 files changed, 318 insertions(+), 35 deletions(-) create mode 100644 customized_tests/semantics/methods.cl create mode 100644 src/visitor_type_ast.py diff --git a/customized_tests/semantics/methods.cl b/customized_tests/semantics/methods.cl new file mode 100644 index 000000000..7376722f1 --- /dev/null +++ b/customized_tests/semantics/methods.cl @@ -0,0 +1,3 @@ +class A { + f(x: Int, y: Int): Int { x + y }; +}; \ No newline at end of file diff --git a/src/main.py b/src/main.py index d717e51a8..3d3f3910a 100644 --- a/src/main.py +++ b/src/main.py @@ -1,6 +1,7 @@ from lexical_analizer import tokenize_cool_text from cool_grammar import define_cool_grammar from cool_visitor import FormatVisitorST +from visitor_type_ast import FormatVisitorTypedAst from type_collector import TypeCollector from type_builder import TypeBuilder @@ -56,17 +57,15 @@ def pipeline(input_file: Path, output_file: Path = None): parse, operations = parser(tokens) - # print("Parse") - # print(parse) - if len(errors) > 0: report_and_exit(errors) #get parsing tree ast = evaluate_reverse_parse(parse, operations, tokens) - formatter = FormatVisitorST() - tree = formatter.visit(ast) - print(tree) + # print("-------------------------------Initial AST-------------------------------") + # formatter = FormatVisitorST() + # tree = formatter.visit(ast) + # print(tree) visitors = [TypeCollector(errors), TypeBuilder(errors)] for visitor in visitors: @@ -75,9 +74,10 @@ def pipeline(input_file: Path, output_file: Path = None): type_checker = TypeChecker(errors) scope, typed_ast = type_checker.visit(ast) - formatter = FormatVisitor() - tree = formatter.visit(typed_ast) - print(tree) + # formatter = FormatVisitorTypedAst() + # print("-------------------------------Typed AST-------------------------------") + # tree = formatter.visit(typed_ast) + # print(tree) if len(errors) > 0: report_and_exit(errors) diff --git a/src/type_checker.py b/src/type_checker.py index 8bdd3e8a6..ac2b34891 100644 --- a/src/type_checker.py +++ b/src/type_checker.py @@ -2,7 +2,7 @@ import cmp.nbpackage import cmp.visitor as visitor -from ast_nodes import Node, ProgramNode, ExpressionNode +from ast_nodes import LessEqualNode, LessNode, Node, ProgramNode, ExpressionNode from ast_nodes import ClassDeclarationNode, FuncDeclarationNode, AttrDeclarationNode from ast_nodes import VarDeclarationNode, AssignNode, CallNode from ast_nodes import ( @@ -142,28 +142,33 @@ def visit(self, node, scope, parent_children_dict): else: parent = node.parent.lex - self.tast_class_nodes.append(cool_type_nodes.ClassDeclarationNode(node.id.lex, parent, new_features)) + self.tast_class_nodes.append(cool_type_nodes.ClassDeclarationNode(node.id.lex, new_features, parent)) @visitor.when(AttrDeclarationNode) def visit(self, node, scope): + type_not_found = False try: typex = self.context.get_type(node.type.lex) - except SError as e: - # ERROR already reported in type builder - return ErrorType() - if typex.name == "SELF_TYPE": - typex = self.current_type + if typex.name == "SELF_TYPE": + typex = self.current_type + except SError as e: + # ERROR already reported in type builder + # return ErrorType() + type_not_found = True if node.init_exp != None: init_expr_type, init_exp = self.visit(node.init_exp, scope) + if type_not_found: + return cool_type_nodes.AttrDeclarationNode(node.id.lex, node.type.lex, init_exp) if not init_expr_type.conforms_to(typex): line, col = node.token.location self.errors.append(TypeError(line, col,INCOMPATIBLE_TYPES % (init_expr_type.name, typex.name))) - + else: + init_exp = None # return typex AQUI SE RETORNABA UN TIPO PERO NO ES NECESARIO return cool_type_nodes.AttrDeclarationNode(node.id.lex, node.type.lex, init_exp) @@ -241,16 +246,16 @@ def visit(self, node, scope): except SError: pass # parent has no method named like this - try: - return_type = self.context.get_type(node.type.lex) - # if return_type.name == "SELF_TYPE": - # return self.current_type - # return return_type ESTAS LINEAS ESTAN DE MAS PUES NO HACE FALTA RETORNAR TIPO + # try: + # return_type = self.context.get_type(node.type.lex) + # # if return_type.name == "SELF_TYPE": + # # return self.current_type + # # return return_type ESTAS LINEAS ESTAN DE MAS PUES NO HACE FALTA RETORNAR TIPO - except SError as e: - # Error already reported in type builder - # return ErrorType() - pass #it is not necessary to return a type in func declaration ndoes + # except SError as e: + # # Error already reported in type builder + # # return ErrorType() + # pass #it is not necessary to return a type in func declaration ndoes return cool_type_nodes.FuncDeclarationNode(node.id.lex, new_params, node.type.lex, body_exp) @@ -307,7 +312,7 @@ def visit(self, node, scope): self.errors.append( TypeError(node_row, node_col, f"Expression type {typex.name} does not conform to declared static dispatch type {node_at_type.name}.") ) - return (ErrorType(), cool_type_nodes.CallNode(obj_exp, node.id.lex, new_args, at_type, typex, ErrorType())) + return (ErrorType(), cool_type_nodes.CallNode(node.id.lex, new_args, obj_exp, at_type, typex, ErrorType())) else: at_type = None @@ -315,7 +320,7 @@ def visit(self, node, scope): except SError as error: node_col, node_row = node.token.location self.errors.append(AttributeError(node_col, node_row ,error.text)) - return (ErrorType(), cool_type_nodes.CallNode(obj_exp, node.id.lex, new_args, at_type, typex, ErrorType())) + return (ErrorType(), cool_type_nodes.CallNode(node.id.lex, new_args, obj_exp, at_type, typex, ErrorType())) if len(method.param_names) != len(node.args): @@ -324,8 +329,10 @@ def visit(self, node, scope): SemanticError(node_row, node_col, f"There is no definition of {method.name} that takes {len(node.args)} arguments ") ) - # for i in range(0, node.args): + n_method_args = len(method.param_names) for i, arg in enumerate(node.args): + if n_method_args == i: + break arg_type = arg_types[i] ptype = method.param_types[i] if not arg_type.conforms_to(ptype): @@ -333,10 +340,10 @@ def visit(self, node, scope): self.errors.append(TypeError(node_row, node_col,f"In call of method {node.id.lex} parameter of type {arg_type.name} does not conforms to declared type {ptype.name}")) if method.return_type == self.context.get_type("SELF_TYPE"): - return (typex, cool_type_nodes.CallNode(obj_exp, node.id.lex, new_args, at_type, typex, typex)) + return (typex, cool_type_nodes.CallNode(node.id.lex, new_args, obj_exp, at_type, typex, typex)) - return (method.return_type, cool_type_nodes.CallNode(obj_exp, node.id.lex, new_args, at_type, typex, method.return_type)) + return (method.return_type, cool_type_nodes.CallNode(node.id.lex, new_args, obj_exp, at_type, typex, method.return_type)) @visitor.when(IfNode) def visit(self, node, scope): @@ -480,7 +487,35 @@ def visit(self, node, scope): return (bool_type, cool_type_nodes.IsvoidNode(node_exp, bool_type)) - @visitor.when(ArithmeticOperation) + @visitor.when(PlusNode) + def visit(self, node, scope): + int_type = self.context.get_type("Int") + left_type, left_exp_node = self.visit(node.left, scope) + right_type, right_exp_node = self.visit(node.right, scope) + + if (left_type != int_type and left_type.name != "AUTO_TYPE") or ( + right_type != int_type and right_type.name != "AUTO_TYPE" + ): + node_row, node_col = node.token.location + self.errors.append(TypeError( node_row, node_col, INVALID_OPERATION % (left_type.name, right_type.name))) + + return (int_type, cool_type_nodes.PlusNode(left_exp_node, right_exp_node, int_type)) + + @visitor.when(MinusNode) + def visit(self, node, scope): + int_type = self.context.get_type("Int") + left_type, left_exp_node = self.visit(node.left, scope) + right_type, right_exp_node = self.visit(node.right, scope) + + if (left_type != int_type and left_type.name != "AUTO_TYPE") or ( + right_type != int_type and right_type.name != "AUTO_TYPE" + ): + node_row, node_col = node.token.location + self.errors.append(TypeError( node_row, node_col, INVALID_OPERATION % (left_type.name, right_type.name))) + + return (int_type, cool_type_nodes.MinusNode(left_exp_node, right_exp_node, int_type)) + + @visitor.when(StarNode) def visit(self, node, scope): int_type = self.context.get_type("Int") left_type, left_exp_node = self.visit(node.left, scope) @@ -492,10 +527,40 @@ def visit(self, node, scope): node_row, node_col = node.token.location self.errors.append(TypeError( node_row, node_col, INVALID_OPERATION % (left_type.name, right_type.name))) - return (int_type, cool_type_nodes.ArithmeticOperation(left_exp_node, right_exp_node, int_type)) + return (int_type, cool_type_nodes.StarNode(left_exp_node, right_exp_node, int_type)) + + @visitor.when(DivNode) + def visit(self, node, scope): + int_type = self.context.get_type("Int") + left_type, left_exp_node = self.visit(node.left, scope) + right_type, right_exp_node = self.visit(node.right, scope) + + if (left_type != int_type and left_type.name != "AUTO_TYPE") or ( + right_type != int_type and right_type.name != "AUTO_TYPE" + ): + node_row, node_col = node.token.location + self.errors.append(TypeError( node_row, node_col, INVALID_OPERATION % (left_type.name, right_type.name))) + + return (int_type, cool_type_nodes.DivNode(left_exp_node, right_exp_node, int_type)) + + + @visitor.when(LessNode) + def visit(self, node, scope): + int_type = self.context.get_type("Int") + left_type, left_exp_node = self.visit(node.left, scope) + right_type, right_exp_node, = self.visit(node.right, scope) + + if (left_type != int_type and left_type.name != "AUTO_TYPE") or ( + right_type != int_type and right_type.name != "AUTO_TYPE" + ): + node_row, node_col = node.token.location + self.errors.append(TypeError( node_row, node_col, INVALID_OPERATION % (left_type.name, right_type.name))) + + bool_type = self.context.get_type("Bool") + return (bool_type, cool_type_nodes.LessNode(left_exp_node, right_exp_node, bool_type)) - @visitor.when(ComparisonOperation) + @visitor.when(LessEqualNode) def visit(self, node, scope): int_type = self.context.get_type("Int") left_type, left_exp_node = self.visit(node.left, scope) @@ -508,7 +573,7 @@ def visit(self, node, scope): self.errors.append(TypeError( node_row, node_col, INVALID_OPERATION % (left_type.name, right_type.name))) bool_type = self.context.get_type("Bool") - return (bool_type, cool_type_nodes.ComparisonOperation(left_exp_node, right_exp_node, bool_type)) + return (bool_type, cool_type_nodes.LessEqualNode(left_exp_node, right_exp_node, bool_type)) @visitor.when(EqualNode) def visit(self, node, scope): diff --git a/src/visitor_type_ast.py b/src/visitor_type_ast.py new file mode 100644 index 000000000..79e47a705 --- /dev/null +++ b/src/visitor_type_ast.py @@ -0,0 +1,215 @@ +import cmp.visitor as visitor +from ast_typed_nodes import ( + ProgramNode, + ClassDeclarationNode, + FuncDeclarationNode, + AttrDeclarationNode, + IfNode, + WhileNode, + LetNode, + CaseNode, + AssignNode, + VarDeclarationNode, + CaseItemNode, + InstantiateNode, + BlockNode, + CallNode, + BinaryNode, + AtomicNode, + UnaryNode, + ArithmeticOperation, + ComparisonOperation, + ConstantNumNode, + VariableNode, + StringNode, + BooleanNode, + InstantiateNode, + NotNode, + IsvoidNode, + NegNode, + PlusNode, + MinusNode, + StarNode, + DivNode, + LessNode, + LessEqualNode, + EqualNode, +) + +class FormatVisitorTypedAst(object): + tree = [] + + @visitor.on("node") + def visit(self, node, tabs=0): + pass + + @visitor.when(ProgramNode) + def visit(self, node, tabs=0): + self.tree = [] + ans = "\\__\\__" * tabs + f"\\__ProgramNode [< class > ... < class >]" + self.tree.append(ans) + for child in node.declarations: + self.visit(child, tabs + 1) + return self.tree + + @visitor.when(ClassDeclarationNode) + def visit(self, node, tabs=0): + parent = "" if node.parent is None else f"inherits {node.parent}" + ans = ( + "\\__\\__" * tabs + + f"\\__ClassDeclarationNode: class {node.id} {parent} {{ ... }}" + ) + self.tree.append(ans) + for child in node.features: + self.visit(child, tabs + 1) + return + + @visitor.when(AttrDeclarationNode) + def visit(self, node, tabs=0): + ans = ( + "\\__\\__" * tabs + + f"\\__AttrDeclarationNode: {node.id} : {node.type} <- " + ) + exp = "\\__\\__" * (tabs + 1) + "\\__NONE" + self.tree.append(ans) + if not node.init_exp is None: + self.visit(node.init_exp, tabs + 1) + else: + self.tree.append(exp) + + return + + @visitor.when(VarDeclarationNode) + def visit(self, node, tabs=0): + ans = ( + "\\__\\__" * tabs + + f"\\__VarDeclarationNode: {node.id} : {node.type} <- " + ) + expr = "\\__\\__" * (tabs + 1) + "\\__NONE" + self.tree.append(ans) + + if not node.expr is None: + expr = self.visit(node.expr, tabs + 1) + else: # esto estaba antes sin el else + self.tree.append(expr) + + return + + @visitor.when(AssignNode) + def visit(self, node, tabs=0): + ans = "\\__\\__" * tabs + f"\\__AssignNode: {node.id} <- " + self.tree.append(ans) + self.visit(node.expr, tabs + 1) + return + + @visitor.when(FuncDeclarationNode) + def visit(self, node, tabs=0): + # params = ", ".join(":".join(param) for param in node.params) + params = ", ".join(":".join(param_name).join(param_type) for param_name, param_type in node.params) + ans = ( + "\\__\\__" * tabs + + f"\\__FuncDeclarationNode: {node.id}({params}) : {node.type} {{ }}" + ) + self.tree.append(ans) + self.visit(node.body, tabs + 1) + return + + @visitor.when(BinaryNode) + def visit(self, node, tabs=0): + ans = "\\__\\__" * tabs + f"\\__ {node.__class__.__name__} " + self.tree.append(ans) + self.visit(node.left, tabs + 1) + self.visit(node.right, tabs + 1) + return + + @visitor.when(AtomicNode) + def visit(self, node, tabs=0): + ans = "\\__\\__" * tabs + f"\\__ {node.__class__.__name__}: {node.lex}" + self.tree.append(ans) + return + + @visitor.when(UnaryNode) + def visit(self, node, tabs=0): + class_name = node.__class__.__name__.split("Node")[0] + ans = "\\__\\__" * tabs + f"\\__ {node.__class__.__name__}: {class_name} " + self.tree.append(ans) + self.visit(node.expr, tabs + 1) + return + + @visitor.when(CallNode) + def visit(self, node, tabs=0): + if not node.obj is None: + if not node.at_type is None: + ans = ( + "\\__\\__" * tabs + + f"\\__CallNode: @{node.at_type}.{node.id}(, ..., )" + ) + else: + ans = ( + "\\__\\__" * tabs + + f"\\__CallNode: .{node.id}(, ..., )" + ) + self.tree.append(ans) + self.visit(node.obj, tabs + 1) + else: + ans = "\\__\\__" * tabs + f"\\__CallNode: {node.id}(, ..., )" + self.tree.append(ans) + for arg in node.args: + self.visit(arg, tabs + 1) + return + + @visitor.when(InstantiateNode) + def visit(self, node, tabs=0): + ans = "\\__\\__" * tabs + f"\\__ InstantiateNode: new {node.lex}()" + self.tree.append(ans) + return + + @visitor.when(BlockNode) + def visit(self, node, tabs=0): + ans = "\\__\\__" * tabs + f"\\__BlockNode: {{; ... ;}}" + self.tree.append(ans) + for child in node.expression_list: + self.visit(child, tabs + 1) + return + + @visitor.when(IfNode) + def visit(self, node, tabs=0): + ans = "\\__\\__" * tabs + f"\\__IfNode: if then else fi" + self.tree.append(ans) + self.visit(node.if_expr, tabs + 1) + self.visit(node.then_expr, tabs + 1) + self.visit(node.else_expr, tabs + 1) + return + + @visitor.when(WhileNode) + def visit(self, node, tabs=0): + ans = "\\__\\__" * tabs + f"\\__WhileNode: while loop pool" + self.tree.append(ans) + self.visit(node.condition, tabs + 1) + self.visit(node.body, tabs + 1) + return + + @visitor.when(LetNode) + def visit(self, node, tabs=0): + ans = "\\__\\__" * tabs + f"\\__LetNode: let in " + self.tree.append(ans) + for child in node.identifiers: + self.visit(child, tabs + 1) + self.visit(node.body, tabs + 1) + return + + @visitor.when(CaseNode) + def visit(self, node, tabs=0): + ans = "\\__\\__" * tabs + f"\\__CaseNode: case of esac" + self.tree.append(ans) + self.visit(node.expr, tabs + 1) + for child in node.case_items: + self.visit(child, tabs + 1) + return + + @visitor.when(CaseItemNode) + def visit(self, node, tabs=0): + ans = "\\__\\__" * tabs + f"\\__CaseItemNode: {node.id} : {node.type} => ;" + self.tree.append(ans) + self.visit(node.expr, tabs + 1) + return From b482803c08beb905cd63dd12cb27b2b0e4174aee Mon Sep 17 00:00:00 2001 From: gabriela Date: Mon, 7 Mar 2022 11:29:21 -0500 Subject: [PATCH 114/162] Reorganize params while building typed ast. --- src/type_checker.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/type_checker.py b/src/type_checker.py index ac2b34891..5f240403f 100644 --- a/src/type_checker.py +++ b/src/type_checker.py @@ -356,10 +356,10 @@ def visit(self, node, scope): self.errors.append( TypeError(node_row, node_col, f"Expression after 'if' must be Bool, current type is {predicate_type.name}") ) - return (ErrorType(), cool_type_nodes.IfNode(if_node, else_node, then_node, ErrorType())) + return (ErrorType(), cool_type_nodes.IfNode(if_node, then_node, else_node, ErrorType())) least_type = find_least_type(then_type, else_type, self.context) - return (least_type, cool_type_nodes.IfNode(if_node, else_node, then_node, least_type)) + return (least_type, cool_type_nodes.IfNode(if_node, then_node, else_node, least_type)) @visitor.when(WhileNode) From 8c317cb1d1f45d938a9f56d76ae5cf3ca4b0cfbd Mon Sep 17 00:00:00 2001 From: smartos99 Date: Mon, 7 Mar 2022 11:34:32 -0500 Subject: [PATCH 115/162] Hello world works with Static call --- src/code_gen/cil_builder.py | 14 +-- src/code_gen/mips_builder.py | 159 +++++++++++++++-------------------- 2 files changed, 76 insertions(+), 97 deletions(-) diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index 63336f53c..486865666 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -315,9 +315,11 @@ def io_outint(self): int_arg = VariableInfo("int") self.register_param(int_arg) result = self.define_internal_local() - self.register_instruction(ToStrNode(result, int_arg.name)) - self.register_instruction(PrintIntNode(result)) - self.register_instruction(ReturnNode(VariableInfo(result).name)) + #self.register_instruction(ToStrNode(result, int_arg.name)) + self.register_instruction(PrintIntNode(int_arg.name)) + #self.register_instruction(ReturnNode(VariableInfo(result).name)) + self.register_instruction(ReturnNode("self")) + def io_instring(self): self.params.append(ParamNode("self")) @@ -359,7 +361,7 @@ def visit(self, node, return_var=None): result = self.define_internal_local() main_constructor = self.to_function_name("constructor", "Main") - main_method_name = self.to_function_name("Main", "main") + main_method_name = self.to_function_name("main", "Main") # Get instance from constructor self.register_instruction(StaticCallNode(main_constructor, instance)) @@ -468,7 +470,7 @@ def visit(self, node, return_var): self.visit(node.obj, instance) else: - self.register_instruction(AssignNode(instance, self.self_var)) + self.register_instruction(AssignNode(instance, "self")) instance_type = None if not node.at_type: @@ -697,8 +699,6 @@ def visit(self, node, return_var): self.current_type.name, ) ) - elif node.lex == "self": - self.register_instruction(AssignNode(return_var, self.self_var)) else: self.register_instruction(AssignNode(return_var, node.lex)) diff --git a/src/code_gen/mips_builder.py b/src/code_gen/mips_builder.py index 00e026626..181677966 100644 --- a/src/code_gen/mips_builder.py +++ b/src/code_gen/mips_builder.py @@ -3,6 +3,7 @@ #from operator import le #from tkinter.tix import Select #from soupsieve import select +from soupsieve import select import cmp.visitor as visitor import cmp.cil as cil import random @@ -113,10 +114,8 @@ def save(self): class MIPSBuilder: def __init__(self): self.mips_code = "" - self.main_procedure = mips.ProcedureNode("main") - self.current_procedure = self.main_procedure self.main_size = 0 - self.text = [self.main_procedure] + self.text = [] self.data = [] self.params = [] self.locals = [] @@ -152,18 +151,18 @@ def register_pop(self, reg): self.register_instruction(mips.AddiNode, sp, sp, 4) def generate_exception_messages(self): - self.register_data(mips.DataTypeNode, ABORT_SIGNAL, '.asciiz', ['"Program execution aborted"']) - self.register_data(mips.DataTypeNode, CASE_MISSMATCH, '.asciiz', ['"Execution of a case statement without a matching branch"']) - self.register_data(mips.DataTypeNode, CASE_VOID, '.asciiz', ['"Case on void"']) - self.register_data(mips.DataTypeNode, DISPATCH_VOID, '.asciiz', ['"Dispatch on void"']) - self.register_data(mips.DataTypeNode, ZERO_DIVISION, '.asciiz', ['"Division by zero"']) - self.register_data(mips.DataTypeNode, SUBSTR_OUT_RANGE, '.asciiz', ['"Substring out of range"']) - self.register_data(mips.DataTypeNode, HEAP_OVERFLOW, '.asciiz', ['"Heap overflow"']) + self.register_data(mips.DataTypeNode, '.asciiz',ABORT_SIGNAL, ['"Program execution aborted"']) + self.register_data(mips.DataTypeNode,'.asciiz', CASE_MISSMATCH, ['"Execution of a case statement without a matching branch"']) + self.register_data(mips.DataTypeNode,'.asciiz', CASE_VOID, ['"Case on void"']) + self.register_data(mips.DataTypeNode,'.asciiz', DISPATCH_VOID, ['"Dispatch on void"']) + self.register_data(mips.DataTypeNode,'.asciiz', ZERO_DIVISION, ['"Division by zero"']) + self.register_data(mips.DataTypeNode,'.asciiz', SUBSTR_OUT_RANGE, ['"Substring out of range"']) + self.register_data(mips.DataTypeNode,'.asciiz', HEAP_OVERFLOW, ['"Heap overflow"']) def generate_extra_static_labels(self): - self.register_data(mips.DataTypeNode, VOID, '.word', [-1]) - self.register_data(mips.DataTypeNode, EMPTY_STRING, '.asciiz', ['""']) - self.register_data(mips.DataTypeNode, INPUT_STR_BUFFER, '.space', [BUFFER_SIZE]) + self.register_data(mips.DataTypeNode, '.word',VOID, [-1]) + self.register_data(mips.DataTypeNode,'.asciiz', EMPTY_STRING, ['""']) + self.register_data(mips.DataTypeNode, '.space',INPUT_STR_BUFFER, [BUFFER_SIZE]) def generate_attr_offset(self,type): @@ -196,21 +195,32 @@ def generate_str_length(self): self.text.append(self.current_procedure) - #def register_main_allocation(self): - # self.register_instruction(mips.CommentNode,"Allocating Main instance") - # self.register_instruction(mips.MoveNode,fp,sp) - # self.register_instruction(mips.AddiNode,sp,sp,-4) - # - # self.register_instruction(mips.CommentNode,"Allocating Main instance") - # #Allocate - # self.register_instruction(mips.LoadInmediate,v0,SYSCALL_SBRK) - # self.register_instruction(mips.LoadInmediate,a0,self.main_size) - # self.register_instruction(mips.SyscallNode) - # self.register_instruction(mips.StoreWordNode,v0,0,fp) - # - # self.register_instruction(mips.CommentNode,"Calling Main Constructor") - # self.register_push(fp) - # self.register_instruction(mips.JumpAndLink,"Main_constructor") + def generate_copy(self): + #copies from t1 to t0 a0 bytes + self.memo.save() + self.memo.get_unused_reg() + self.current_procedure = mips.ProcedureNode(COPY) + + self.register_instruction(mips.Label, "copy_loop") + self.register_instruction(mips.BranchOnEqualNode, zero, a0, "copy_end") + self.register_instruction(mips.LoadByteNode, t7, 0, t1) + self.register_instruction(mips.StoreByteNode, t7, 0, t0) + self.register_instruction(mips.AddiNode, t0, t0, 1) + self.register_instruction(mips.AddiNode, t1, t1, 1) + self.register_instruction(mips.AddiNode, a0, a0, -1) + self.register_instruction(mips.Jump, "copy_loop") + + self.register_instruction(mips.Label, "copy_end") + self.register_instruction(mips.Jump, ra) + + self.text.append(self.current_procedure) + + def generate_auxiliar_procedures(self): + self.generate_str_length() + self.generate_copy() + + + @visitor.on("node") @@ -223,8 +233,10 @@ def visit(self, node): self.visit(type) self.generate_attr_offset(type.name) - self.generate_extra_static_labels + self.generate_extra_static_labels() self.generate_exception_messages() + + self.generate_auxiliar_procedures() for str_data in node.dotdata: self.visit(str_data) @@ -246,7 +258,7 @@ def visit(self, node): values.append(func[1]) self.register_data(mips.DataTypeNode,'.word',node.name,values) - self.register_data(mips.DataTypeNode, f'{node.name}_cname','.asciiz', [f'"{node.name}"']) + self.register_data(mips.DataTypeNode, '.asciiz',f'{node.name}_cname', [f'"{node.name}"']) #Filling type type info @@ -264,7 +276,7 @@ def visit(self, node): @visitor.when(cil.DataNode) def visit(self, node): - self.register_data(mips.DataTypeNode,'.asciiz',node.name,[node.value]) + self.register_data(mips.DataTypeNode,'.asciiz',node.name,[f'"{node.value}"']) @@ -284,6 +296,7 @@ def visit(self,node): @visitor.when(cil.ArgNode) def visit(self,node): self.memo.save() + self.register_instruction(mips.CommentNode,f"Receiving Arg {node.name}") reg = self.memo.get_unused_reg() offset = self.get_offset(node.name) @@ -335,7 +348,7 @@ def visit(self,node): self.register_instruction(mips.CommentNode,"Restoring saved $ra") self.register_instruction(mips.AddiNode,sp,sp,-4) - self.register_instruction(mips.LoadWordNode,fp,0,sp) + self.register_instruction(mips.LoadWordNode,ra,0,sp) AR = -4*(len(node.localvars)) @@ -368,6 +381,7 @@ def visit(self,node): @visitor.when(cil.LoadNode) def visit(self, node: cil.LoadNode): self.memo.save() + self.register_instruction(mips.CommentNode,"Executing Load") _size = STRING_SIZE self.register_instruction(mips.LoadInmediate,v0,SYSCALL_SBRK) self.register_instruction(mips.LoadInmediate,a0,_size) @@ -391,10 +405,11 @@ def visit(self, node: cil.LoadNode): @visitor.when(cil.LengthNode) def visit(self, node): + self.register_instruction(mips.CommentNode,"Executing Length") self.memo.save() reg = self.memo.get_unused_reg() source_offset = self.get_offset(node.source) - self.register_instruction(mips.LoadNode, reg,source_offset, fp) + self.register_instruction(mips.LoadWordNode, reg,source_offset,fp) self.register_instruction(mips.LoadWordNode, reg, LENGTH_ATTR_OFFSET, reg) dest_offset = self.get_offset(node.dest) self.register_instruction(mips.StoreWordNode, reg,dest_offset, fp) @@ -403,6 +418,7 @@ def visit(self, node): #All return value is saved in register a1 @visitor.when(cil.ReturnNode) def visit(self,node): + self.register_instruction(mips.CommentNode,"Executing Return") if isinstance(node.value,int): self.register_instruction(mips.LoadInmediate,a1,node.value) else: @@ -411,12 +427,14 @@ def visit(self,node): @visitor.when(cil.GotoNode) def visit(self,node): - self.register_instruction(mips.UnconditionalJumpNode,node.label) + self.register_instruction(mips.CommentNode,"Executing Goto") + self.register_instruction(mips.Jump,node.label) @visitor.when(cil.AllocateNode) def visit(self,node): + self.register_instruction(mips.CommentNode,"Executing Allocate") self.memo.save() _size = (len(self.types[node.type].attributes)+1)*4 self.register_instruction(mips.LoadInmediate,v0,SYSCALL_SBRK) @@ -433,6 +451,7 @@ def visit(self,node): @visitor.when(cil.AssignNode) def visit(self,node): + self.register_instruction(mips.CommentNode,"Executing Assign") self.memo.save() reg = self.memo.get_unused_reg() @@ -447,45 +466,9 @@ def visit(self,node): self.memo.clean() - @visitor.when(cil.PlusNode) - def visit(self,node): - self.memo.save() - - reg1 = self.memo.get_unused_reg() - reg2 = self.memo.get_unused_reg() - reg3 = self.memo.get_unused_reg() - - self.register_instruction(mips.LoadInmediate,reg1,node.left) - self.register_instruction(mips.LoadInmediate,reg2,node.right) - - self.register_instruction(mips.AddNode,reg3,reg1,reg2) - - offset = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode,reg3,offset,fp) - - self.memo.clean() - - @visitor.when(cil.MinusNode) - def visit(self,node): - self.memo.save() - - reg1 = self.memo.get_unused_reg() - reg2 = self.memo.get_unused_reg() - reg3 = self.memo.get_unused_reg() - - self.register_instruction(mips.LoadInmediate,reg1,node.left) - self.register_instruction(mips.LoadInmediate,reg2,node.right) - - self.register_instruction(mips.SubNode,reg3,reg1,reg2) - - offset = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode,reg3,offset,fp) - - self.memo.clean() - @visitor.when(cil.RuntimeErrorNode) def visit(self,node): - + self.register_instruction(mips.CommentNode,"Executing RuntimeError") self.register_instruction(mips.CommentNode,"Printing Abort Message") self.register_instruction(mips.LoadAddress,a0,ABORT_SIGNAL) self.register_instruction(mips.LoadInmediate,v0,SYSCALL_PRINT_STR) @@ -498,7 +481,7 @@ def visit(self,node): @visitor.when(cil.StaticCallNode) def visit(self,node): - + self.register_instruction(mips.CommentNode,"Executing Static Call") self.register_instruction(mips.JumpAndLink,node.function) dest_offset = self.get_offset(node.dest) @@ -510,6 +493,7 @@ def visit(self,node): @visitor.when(cil.DynamicCallNode) def visit(self,node): self.memo.save() + self.register_instruction(mips.CommentNode,"Executing Dynamic Call") reg1 = self.memo.get_unused_reg() #getting method offset @@ -542,8 +526,8 @@ def visit(self,node): @visitor.when(cil.GetAttribNode) def visit(self, node): + self.register_instruction(mips.CommentNode,"Executing GetAttr") self.memo.save() - reg1 = self.memo.get_unused_reg() reg2 = self.memo.get_unused_reg() @@ -559,6 +543,7 @@ def visit(self, node): @visitor.when(cil.SetAttribNode) def visit(self, node): + self.register_instruction(mips.CommentNode,"Executing SetAttr") self.memo.save() reg1 = self.memo.get_unused_reg() reg2 = self.memo.get_unused_reg() @@ -576,6 +561,7 @@ def visit(self, node): @visitor.when(cil.DefaultValueNode) def visit(self,node): + self.register_instruction(mips.CommentNode,"Executing DefaultValue") self.memo.save() reg = self.memo.get_unused_reg() dest_offset = self.get_offset(node.dest) @@ -606,6 +592,7 @@ def visit(self,node): @visitor.when(cil.PlusNode) def visit(self,node): + self.register_instruction(mips.CommentNode,"Executing Plus Operation") self.memo.save() reg_l = self.memo.get_unused_reg() reg_r = self.memo.get_unused_reg() @@ -626,6 +613,7 @@ def visit(self,node): @visitor.when(cil.MinusNode) def visit(self,node): + self.register_instruction(mips.CommentNode,"Executing Minus Operation") self.memo.save() reg_l = self.memo.get_unused_reg() reg_r = self.memo.get_unused_reg() @@ -646,6 +634,7 @@ def visit(self,node): @visitor.when(cil.StarNode) def visit(self,node): + self.register_instruction(mips.CommentNode,"Executing Star Operation") self.memo.save() reg1 = self.memo.get_unused_reg() reg2 = self.memo.get_unused_reg() @@ -667,6 +656,7 @@ def visit(self,node): @visitor.when(cil.DivNode) def visit(self,node): + self.register_instruction(mips.CommentNode,"Executing Div Operation") self.memo.save() reg1 = self.memo.get_unused_reg() reg2 = self.memo.get_unused_reg() @@ -686,20 +676,8 @@ def visit(self,node): self.memo.clean() - - #PENDIENTEEEEEEEE - @visitor.when(cil.CopyNode) - def visit(self,node): - self.register_instruction(mips.CommentNode,"CopyNode") - - self.register_instruction(mips.CommentNode,"Printing Abort Message") - self.register_instruction(mips.LoadAddress,a0,ABORT_SIGNAL) - self.register_instruction(mips.LoadInmediate,v0,SYSCALL_PRINT_STR) - self.register_instruction(mips.SyscallNode) - - self.register_instruction(mips.CommentNode,"Aborting execution") - self.register_instruction(mips.LoadInmediate,v0,SYSCALL_EXIT) - self.register_instruction(mips.SyscallNode) + + #READSTRING @visitor.when(cil.ReadNode) @@ -802,6 +780,9 @@ def visit(self,node): self.memo.clean() + @visitor.when(cil.CopyNode) + def visit(self,node): + pass @visitor.when(cil.TypeNameNode) def visit(self,node): @@ -812,9 +793,7 @@ def visit(self,node): def visit(self,node): pass - @visitor.when(cil.LengthNode) - def visit(self,node): - pass + @visitor.when(cil.ConcatNode) def visit(self,node): pass From 4cdc30d0a2e5eb77420e2471b2219516407f64d1 Mon Sep 17 00:00:00 2001 From: gabriela Date: Mon, 7 Mar 2022 11:42:13 -0500 Subject: [PATCH 116/162] Remove unnecessary import. --- src/code_gen/mips_builder.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/code_gen/mips_builder.py b/src/code_gen/mips_builder.py index 181677966..78e7f2752 100644 --- a/src/code_gen/mips_builder.py +++ b/src/code_gen/mips_builder.py @@ -3,7 +3,6 @@ #from operator import le #from tkinter.tix import Select #from soupsieve import select -from soupsieve import select import cmp.visitor as visitor import cmp.cil as cil import random From f4805fd60617627bccc4cc3b2cc614888f0e4d66 Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Mon, 7 Mar 2022 12:31:44 -0500 Subject: [PATCH 117/162] fix: import ast_type_nodes --- src/code_gen/cil_builder.py | 6 ++---- tests/test_1file.py | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 tests/test_1file.py diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index f0ccb842b..6a64d412c 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -1,7 +1,7 @@ import cmp.nbpackage import cmp.visitor as visitor -import ast_nodes as cool +import ast_typed_nodes as cool from cmp.cil import ( ProgramNode, @@ -316,9 +316,7 @@ def io_outint(self): self.params.append(ParamNode("self")) int_arg = VariableInfo("int") self.register_param(int_arg) - # result = self.define_internal_local() - # self.register_instruction(ToStrNode(result, int_arg.name)) - self.register_instruction(PrintIntNode(int_arg)) + self.register_instruction(PrintIntNode(int_arg.name)) self.register_instruction(ReturnNode("self")) def io_instring(self): diff --git a/tests/test_1file.py b/tests/test_1file.py new file mode 100644 index 000000000..c8c144a7f --- /dev/null +++ b/tests/test_1file.py @@ -0,0 +1,22 @@ +import pytest +import os +from utils import compare_errors, first_error_only_line + +# tests_dir = __file__.rpartition('/')[0] + '/semantic/' +# tests = [(file) for file in os.listdir(tests_dir) if file.endswith('self4.cl')] + +tests_dir = __file__.rpartition("/")[0] + "/parser/" +tests = [(file) for file in os.listdir(tests_dir) if file.endswith("block3.cl")] + + +@pytest.mark.semantic +@pytest.mark.error +@pytest.mark.run(order=3) +@pytest.mark.parametrize("cool_file", tests) +def test_semantic_errors(compiler_path, cool_file): + compare_errors( + compiler_path, + tests_dir + cool_file, + tests_dir + cool_file[:-3] + "_error.txt", + cmp=first_error_only_line, + ) From c26c85187c2380cc0cd2378ffb1a307c718b2808 Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Mon, 7 Mar 2022 13:20:39 -0500 Subject: [PATCH 118/162] feat: add dynamic call --- customized_tests/test_hello_world.cl | 2 +- src/cmp/cil.py | 9 ++++----- src/code_gen/cil_builder.py | 12 ++++++------ src/main.py | 5 +++-- src/type_checker.py | 8 +++++--- 5 files changed, 19 insertions(+), 17 deletions(-) diff --git a/customized_tests/test_hello_world.cl b/customized_tests/test_hello_world.cl index eff360d5b..d0c285a71 100644 --- a/customized_tests/test_hello_world.cl +++ b/customized_tests/test_hello_world.cl @@ -11,7 +11,7 @@ class Main inherits IO{ main (): Object { - self@IO.out_int((new Point)@Point.init(5, 6)) + self.out_int((new Point).init(5, 6)) }; }; diff --git a/src/cmp/cil.py b/src/cmp/cil.py index 141cacfab..9da9bc5c6 100644 --- a/src/cmp/cil.py +++ b/src/cmp/cil.py @@ -170,11 +170,10 @@ def __init__(self, function, dest): class DynamicCallNode(InstructionNode): - def __init__(self, instance, method, dest, typex): - self.instance = instance - self.method = method + def __init__(self, instance_type, method_index, dest): + self.instance_type = instance_type + self.method_index = method_index self.dest = dest - self.type = typex class ArgNode(InstructionNode): @@ -382,7 +381,7 @@ def visit(self, node): @visitor.when(DynamicCallNode) def visit(self, node): - return f"{node.dest} = VCALL {node.type} {node.method}" + return f"{node.dest} = VCALL {node.instance_type} {node.method_index}" @visitor.when(ArgNode) def visit(self, node): diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index 6a64d412c..c6a34d0ee 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -100,6 +100,10 @@ def localvars(self): def instructions(self): return self.current_function.instructions + def get_method_id(self, typex, name): + method_id, _ = self.methods[typex][name] + return method_id + def register_instruction(self, instruction): self.current_function.instructions.append(instruction) @@ -512,13 +516,9 @@ def visit(self, node, return_var): ) else: + method_index = self.get_method_id(node.obj.static_type.name, node.id) self.register_instruction( - DynamicCallNode( - instance, - node.id, - return_var, - instance_type, - ) + DynamicCallNode(instance_type, method_index, return_var) ) @visitor.when(cool.IfNode) diff --git a/src/main.py b/src/main.py index f332f1931..b6cf18fbf 100644 --- a/src/main.py +++ b/src/main.py @@ -64,11 +64,12 @@ def pipeline(input_file: Path, output_file: Path = None): # get parsing tree ast = evaluate_reverse_parse(parse, operations, tokens) + # print("-------------------------------Initial AST-------------------------------") # formatter = FormatVisitorST() # tree = formatter.visit(ast) # print(tree) - + visitors = [TypeCollector(errors), TypeBuilder(errors)] for visitor in visitors: ast = visitor.visit(ast) @@ -85,7 +86,7 @@ def pipeline(input_file: Path, output_file: Path = None): report_and_exit(errors) cool_to_cil_visitor = CILBuilder() - cil_ast = cool_to_cil_visitor.visit(ast) + cil_ast = cool_to_cil_visitor.visit(typed_ast) formatter = PrintVisitor() tree = formatter.visit(cil_ast) diff --git a/src/type_checker.py b/src/type_checker.py index 5f240403f..c3915a3e3 100644 --- a/src/type_checker.py +++ b/src/type_checker.py @@ -63,7 +63,7 @@ def __init__(self, errors=[]): self.errors = errors @visitor.on("node") - def visit(self, node, scope=None): + def visit(self, node, scope=None, parent_children_dict=None): pass @visitor.when(ProgramNode) @@ -107,11 +107,13 @@ def visit(self, node): self.visit(declaration, scope.create_child(), parent_children_dict) + program_node = (scope, cool_type_nodes.ProgramNode(self.tast_class_nodes, copy.copy(self.context))) + self.context = None self.current_type = None self.current_method = None - - return (scope, cool_type_nodes.ProgramNode(self.tast_class_nodes, copy.copy(self.context))) + + return program_node @visitor.when(ClassDeclarationNode) def visit(self, node, scope, parent_children_dict): From 99fd3abd940dd30793786661740afcd03ac4a89a Mon Sep 17 00:00:00 2001 From: smartos99 Date: Mon, 7 Mar 2022 13:39:06 -0500 Subject: [PATCH 119/162] Fix AssignNode visitor --- src/code_gen/mips_builder.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/code_gen/mips_builder.py b/src/code_gen/mips_builder.py index 181677966..388abb573 100644 --- a/src/code_gen/mips_builder.py +++ b/src/code_gen/mips_builder.py @@ -456,11 +456,13 @@ def visit(self,node): reg = self.memo.get_unused_reg() - source_offset = self.get_offset(node.source) + if isinstance(node.source,int): + self.register_instruction(mips.LoadInmediate,reg,node.source) + else: + source_offset = self.get_offset(node.source) + self.register_instruction(mips.LoadWordNode,reg,source_offset,fp) + dest_offset = self.get_offset(node.dest) - - self.register_instruction(mips.LoadWordNode,reg,source_offset,fp) - self.register_instruction(mips.StoreWordNode,reg,dest_offset,fp) self.memo.clean() From 74dfe8378499f2d4d6bf44d6867e58a29bb3c4ee Mon Sep 17 00:00:00 2001 From: smartos99 Date: Mon, 7 Mar 2022 16:41:46 -0500 Subject: [PATCH 120/162] Hello world works with dynamic call --- src/cmp/cil.py | 9 +++++- src/code_gen/cil_builder.py | 9 ++++-- src/code_gen/mips_builder.py | 53 ++++++++++++++++++++++++++---------- 3 files changed, 52 insertions(+), 19 deletions(-) diff --git a/src/cmp/cil.py b/src/cmp/cil.py index 9da9bc5c6..4fc1301ba 100644 --- a/src/cmp/cil.py +++ b/src/cmp/cil.py @@ -265,6 +265,11 @@ class IsVoidNode(InstructionNode): def __init__(self, dest, value): self.dest = dest self.value = value + +class ExitNode(InstructionNode): + def __init__(self): + pass + class PrintVisitor(object): @@ -443,6 +448,8 @@ def visit(self, node): def visit(self, node): return f"{node.dest} = ISVOID {node.value}" - + @visitor.when(ExitNode) + def visit(self, node): + return f"EXIT" # printer = PrintVisitor() # return lambda ast: printer.visit(ast) diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index c6a34d0ee..68da6c8fd 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -46,6 +46,7 @@ GetAttribNode, DefaultValueNode, IsVoidNode, + ExitNode, ) from cool_visitor import FormatVisitor @@ -394,7 +395,8 @@ def visit(self, node, return_var=None): self.register_instruction(ArgNode(instance)) self.register_instruction(StaticCallNode(main_method_name, result)) - self.register_instruction(ReturnNode(0)) + #self.register_instruction(ReturnNode(0)) + self.register_instruction(ExitNode()) self.current_function = None @@ -488,10 +490,11 @@ def visit(self, node, return_var): def visit(self, node, return_var): # TODO: Pending test .id(,...,) # TODO: Pending test @.id(,...,) - + obj_type = self.current_type.name instance = self.define_internal_local() if node.obj: self.visit(node.obj, instance) + obj_type = node.obj.static_type.name else: self.register_instruction(AssignNode(instance, "self")) @@ -516,7 +519,7 @@ def visit(self, node, return_var): ) else: - method_index = self.get_method_id(node.obj.static_type.name, node.id) + method_index = self.get_method_id(obj_type, node.id) self.register_instruction( DynamicCallNode(instance_type, method_index, return_var) ) diff --git a/src/code_gen/mips_builder.py b/src/code_gen/mips_builder.py index 7b0120c70..c3453b7bd 100644 --- a/src/code_gen/mips_builder.py +++ b/src/code_gen/mips_builder.py @@ -341,22 +341,7 @@ def visit(self,node): for inst in node.instructions: self.visit(inst) - self.register_instruction(mips.CommentNode,"Restoring saved $fp") - self.register_instruction(mips.AddiNode,sp,sp,-4) - self.register_instruction(mips.LoadWordNode,fp,0,sp) - self.register_instruction(mips.CommentNode,"Restoring saved $ra") - self.register_instruction(mips.AddiNode,sp,sp,-4) - self.register_instruction(mips.LoadWordNode,ra,0,sp) - - - AR = -4*(len(node.localvars)) - - self.register_instruction(mips.CommentNode,"Cleaning stack after call") - self.register_instruction(mips.AddiNode, sp, sp, AR) - - self.register_instruction(mips.CommentNode,"Return jump") - self.register_instruction(mips.JumpRegister, ra) self.text.append(self.current_procedure) self.locals = locals_save @@ -423,7 +408,25 @@ def visit(self,node): else: offset = self.get_offset(node.value) self.register_instruction(mips.LoadWordNode,a1,offset,fp) + + self.register_instruction(mips.CommentNode,"Restoring saved $fp") + self.register_instruction(mips.AddiNode,sp,sp,-4) + self.register_instruction(mips.LoadWordNode,fp,0,sp) + + self.register_instruction(mips.CommentNode,"Restoring saved $ra") + self.register_instruction(mips.AddiNode,sp,sp,-4) + self.register_instruction(mips.LoadWordNode,ra,0,sp) + + + AR = -4*(len(self.locals)) + + self.register_instruction(mips.CommentNode,"Cleaning stack after call") + self.register_instruction(mips.AddiNode, sp, sp, AR) + + self.register_instruction(mips.CommentNode,"Return jump") + self.register_instruction(mips.JumpRegister, ra) + @visitor.when(cil.GotoNode) def visit(self,node): self.register_instruction(mips.CommentNode,"Executing Goto") @@ -495,8 +498,21 @@ def visit(self,node): def visit(self,node): self.memo.save() self.register_instruction(mips.CommentNode,"Executing Dynamic Call") + reg1 = self.memo.get_unused_reg() + inst_offset = self.get_offset(node.instance_type) + self.register_instruction(mips.LoadWordNode,reg1,inst_offset,fp) + + #getting function + reg2 = self.memo.get_unused_reg() + self.register_instruction(mips.LoadWordNode,reg2,node.method_index*4,reg1) + + self.register_instruction(mips.JumpRegister,reg2) + #putting the return vslue in destination + dest_offset = self.get_offset(node.dest) + self.register_instruction(mips.StoreWordNode,a1,dest_offset,fp) + #getting method offset #_methods = self.types[node.type].methods #_function = None @@ -781,6 +797,13 @@ def visit(self,node): self.memo.clean() + @visitor.when(cil.ExitNode) + def visit(self,node): + self.register_instruction(mips.LoadInmediate,v0,SYSCALL_EXIT) + self.register_instruction(mips.SyscallNode) + + + @visitor.when(cil.CopyNode) def visit(self,node): pass From 6c262ed4ef09c0d6093cc892ce22799ba531397f Mon Sep 17 00:00:00 2001 From: smartos99 Date: Mon, 7 Mar 2022 20:40:25 -0500 Subject: [PATCH 121/162] Dynamic Call works --- src/code_gen/mips_builder.py | 13 +++++++++++++ src/code_gen/mips_nodes.py | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/code_gen/mips_builder.py b/src/code_gen/mips_builder.py index c3453b7bd..96d3701c9 100644 --- a/src/code_gen/mips_builder.py +++ b/src/code_gen/mips_builder.py @@ -123,6 +123,16 @@ def __init__(self): self.memo = MemoryManager() self.pushed_args = 0 + def print(self,x): + self.memo.save() + self.register_instruction(mips.CommentNode,"------------Printeooooo") + reg = self.memo.get_unused_reg() + self.register_instruction(mips.LoadInmediate,reg,x) + self.register_instruction(mips.MoveNode,a0,reg) + self.register_instruction(mips.LoadInmediate,v0,4) + self.register_instruction(mips.SyscallNode) + self.register_instruction(mips.CommentNode,"------------Fiiiin") + def get_offset(self,x): if x in self.locals: @@ -496,6 +506,7 @@ def visit(self,node): @visitor.when(cil.DynamicCallNode) def visit(self,node): + #self.print(node.instance_type) self.memo.save() self.register_instruction(mips.CommentNode,"Executing Dynamic Call") @@ -512,6 +523,8 @@ def visit(self,node): #putting the return vslue in destination dest_offset = self.get_offset(node.dest) self.register_instruction(mips.StoreWordNode,a1,dest_offset,fp) + self.register_instruction(mips.AddiNode,sp,sp,self.pushed_args * -4) + self.pushed_args = 0 #getting method offset #_methods = self.types[node.type].methods diff --git a/src/code_gen/mips_nodes.py b/src/code_gen/mips_nodes.py index 3bc3925e1..3f07ffa59 100644 --- a/src/code_gen/mips_nodes.py +++ b/src/code_gen/mips_nodes.py @@ -220,7 +220,7 @@ def __str__(self): class JumpRegister(UnconditionalJumpNode): def __str__(self): - return f"jr {self.jump}" + return f"jalr {self.jump}" class JumpAndLink(UnconditionalJumpNode): From 01387e3d18a604baeaf40fb24ac1e0ff8dec0ac9 Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Tue, 8 Mar 2022 01:52:26 -0500 Subject: [PATCH 122/162] ref: remove unnecessary nodes from cil --- src/cmp/cil.py | 28 +++------------------ src/code_gen/cil_builder.py | 50 +++++++++++++++++++++++++++++-------- 2 files changed, 43 insertions(+), 35 deletions(-) diff --git a/src/cmp/cil.py b/src/cmp/cil.py index 9da9bc5c6..d5a5c3fb8 100644 --- a/src/cmp/cil.py +++ b/src/cmp/cil.py @@ -123,18 +123,6 @@ def __init__(self, instance, attr, value, typex): self.type = typex -class ArrayNode(InstructionNode): - pass - - -class GetIndexNode(InstructionNode): - pass - - -class SetIndexNode(InstructionNode): - pass - - class AllocateNode(InstructionNode): def __init__(self, itype, dest): self.type = itype @@ -205,10 +193,6 @@ def __init__(self, dest, left, right): self.right = right -class PrefixNode(InstructionNode): - pass - - class SubstringNode(InstructionNode): def __init__(self, dest, source, idx, length): self.dest = dest @@ -217,12 +201,6 @@ def __init__(self, dest, source, idx, length): self.length = length -class ToStrNode(InstructionNode): - def __init__(self, dest, ivalue): - self.dest = dest - self.ivalue = ivalue - - class ReadNode(InstructionNode): def __init__(self, dest): self.dest = dest @@ -403,9 +381,9 @@ def visit(self, node): def visit(self, node): return f"{node.dest} = TYPE_NAME {node.source}" - @visitor.when(ToStrNode) - def visit(self, node): - return f"{node.dest} = STR {node.ivalue}" + # @visitor.when(ToStrNode) + # def visit(self, node): + # return f"{node.dest} = STR {node.ivalue}" @visitor.when(ReadNode) def visit(self, node): diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index c6a34d0ee..c91ed1f53 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -11,7 +11,6 @@ ParamNode, LocalNode, AssignNode, - ArithmeticNode, AllocateNode, TypeOfNode, LabelNode, @@ -24,9 +23,7 @@ LoadNode, LengthNode, ConcatNode, - PrefixNode, SubstringNode, - ToStrNode, ReadNode, PrintStrNode, PrintIntNode, @@ -599,14 +596,47 @@ def visit(self, node, return_var=None): @visitor.when(cool.CaseNode) def visit(self, node, return_var=None): - pass # TODO: Pending!!! + def least_type(type_set): + solve = self.context.get_type(type_set[0]) + for item in type_set[1:]: + typex = self.context.get_type(item) + solve = find_least_type(solve, typex) + + while solve is not None: + if type_b.conforms_to(solve): + return solve + solve = solve.parent + + return None + return solve.name if not solve else "Object" + + expr_value = self.define_internal_local() + self.visit(node.expr, expr_value) + + types = [case_item.type for case_item in node.case_items] + types.append(node.expr.static_type.name) + + _least_type = least_type(types) + print("-----------Least TYpE:", _least_type) + asserted_item = None + for case_item in node.case_items: + if case_item.type == _least_type: + asserted_item = case_item + break + + if not asserted_item: + self.register_instruction( + StaticCallNode( + self.to_function_name("abort", "Object"), + return_var, + ) + ) + return + + self.localvars.append(LocalNode(asserted_item.id)) + self.register_instruction(AssignNode(asserted_item.id, expr_value)) - # expr_value = self.define_internal_local() - # self.visit(node.expr, expr_value) - # solve = self.define_internal_local() - # for case_item in node.case_items: - # item_expr_value = self.define_internal_local() - # self.visit(case_item.) + self.visit(asserted_item.expr, return_var) @visitor.when(cool.CaseItemNode) def visit(self, node, return_var=None): From 84a95c7f4f4b36113ed98fce902c5a72a69314e1 Mon Sep 17 00:00:00 2001 From: smartos99 Date: Tue, 8 Mar 2022 10:31:20 -0500 Subject: [PATCH 123/162] ReadString works --- src/code_gen/cil_builder.py | 8 ++-- src/code_gen/mips_builder.py | 89 ++++++++---------------------------- 2 files changed, 23 insertions(+), 74 deletions(-) diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index 68da6c8fd..24fdf5d29 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -481,7 +481,7 @@ def visit(self, node, return_var): if self.is_attribute(node.id): self.register_instruction( - SetAttribNode("self", node.id, return_var, self.current_type.name) + SetAttribNode("self", self.to_attr_name(self.current_type.name, node.id), return_var, self.current_type.name) ) else: self.register_instruction(AssignNode(node.id, return_var)) @@ -566,7 +566,7 @@ def visit(self, node, return_var): # Body self.register_instruction(LabelNode(body_label)) - self.visit(node.body) + self.visit(node.body, self.define_internal_local()) # GOTO while label self.register_instruction(GotoNode(while_label)) @@ -584,7 +584,7 @@ def visit(self, node, return_var): @visitor.when(cool.LetNode) def visit(self, node, return_var): for var_dec in node.identifiers: - self.visit(var_dec.expr) + self.visit(var_dec) self.visit(node.body, return_var) @@ -596,7 +596,7 @@ def visit(self, node, return_var=None): # Add Assignment Node if node.expr: - self.visit(node.expr, local.id) + self.visit(node.expr, local.name) else: self.register_instruction(DefaultValueNode(local, node.type)) diff --git a/src/code_gen/mips_builder.py b/src/code_gen/mips_builder.py index 96d3701c9..77ab44e53 100644 --- a/src/code_gen/mips_builder.py +++ b/src/code_gen/mips_builder.py @@ -91,7 +91,9 @@ class MemoryManager: def __init__(self): - self.all_reg = [t0,t1,t2,t3,t4,t5,t6,t7,t8,t9] + #self.all_reg = [t0,t1,t2,t3,t4,t5,t6,t7,t8,t9] + self.all_reg = [t0,t1,t2,t3,t4,t5,t9] + self.used_reg = [] self.stored = [] @@ -205,17 +207,16 @@ def generate_str_length(self): self.text.append(self.current_procedure) def generate_copy(self): - #copies from t1 to t0 a0 bytes + #copies from t1 to t6 a0 bytes self.memo.save() - self.memo.get_unused_reg() self.current_procedure = mips.ProcedureNode(COPY) self.register_instruction(mips.Label, "copy_loop") self.register_instruction(mips.BranchOnEqualNode, zero, a0, "copy_end") - self.register_instruction(mips.LoadByteNode, t7, 0, t1) - self.register_instruction(mips.StoreByteNode, t7, 0, t0) - self.register_instruction(mips.AddiNode, t0, t0, 1) - self.register_instruction(mips.AddiNode, t1, t1, 1) + self.register_instruction(mips.LoadByteNode, t8, 0, t7) + self.register_instruction(mips.StoreByteNode, t8, 0, t6) + self.register_instruction(mips.AddiNode, t6, t6, 1) + self.register_instruction(mips.AddiNode, t7, t7, 1) self.register_instruction(mips.AddiNode, a0, a0, -1) self.register_instruction(mips.Jump, "copy_loop") @@ -269,19 +270,6 @@ def visit(self, node): self.register_data(mips.DataTypeNode,'.word',node.name,values) self.register_data(mips.DataTypeNode, '.asciiz',f'{node.name}_cname', [f'"{node.name}"']) - - #Filling type type info - #self.register_instruction(mips.CommentNode(f"Filling {node.name} VT")) - #self.register_instruction(mips.LoadAddress,t0,node.name) - #self.register_instruction(mips.LoadAddress,t1,f'{node.name}_cname') - - #self.register_instruction(mips.StoreWordNode,t1,TYPENAME_OFFSET,t0) - - #Filling type VT - #for i,func in enumerate(node.methods): - # offset = FUNCTION_OFFSET*i - # self.register_instruction(mips.LoadAddress,t1,func.name) - # self.register_instruction(mips.StoreWordNode,t1,offset,t0) @visitor.when(cil.DataNode) def visit(self, node): @@ -356,21 +344,6 @@ def visit(self,node): self.text.append(self.current_procedure) self.locals = locals_save self.params = params_save - - - #@visitor.when(cil.LoadNode) - #def visit(self,node): - # self.memo.save() - # reg = self.memo.used_reg() - # - # if isinstance(node.msg,int): - # self.register_instruction(mips.LoadInmediate,reg,node.msg) - # else: - # self.register_instruction(mips.LoadAddress,reg,node.msg) - # - # offset = self.get_offset(node.dest) - # self.register_instruction(mips.StoreWordNode,reg,offset,fp) - # self.memo.clean() @visitor.when(cil.LoadNode) def visit(self, node: cil.LoadNode): @@ -525,28 +498,6 @@ def visit(self,node): self.register_instruction(mips.StoreWordNode,a1,dest_offset,fp) self.register_instruction(mips.AddiNode,sp,sp,self.pushed_args * -4) self.pushed_args = 0 - - #getting method offset - #_methods = self.types[node.type].methods - #_function = None - # - #for (meth,func) in _methods: - # if node.method == meth: - # _function = func - # - #_functions = [func for (meth,func) in (_methods)] - #meth_offset = _functions.index(_function) - # - #self.register_instruction(mips.LoadAddress,reg1,node.type) - #reg2 = self.memo.get_unused_reg() - #self.register_instruction(mips.LoadWordNode,reg2,meth_offset*4,reg1) - # - #self.register_instruction(mips.JumpAndLink,reg2) - # - ##putting the return vslue in destination - #dest_offset = self.get_offset(node.dest) - #self.register_instruction(mips.StoreWordNode,a1,dest_offset,fp) - self.memo.clean() @@ -679,7 +630,7 @@ def visit(self,node): self.register_instruction(mips.MultNode,reg1,reg2) dest_offset = self.get_offset(node.dest) - self.register_instruction(mips.MoveFromHi,reg1) + self.register_instruction(mips.MoveFromLo,reg1) self.register_instruction(mips.StoreWordNode,reg1,dest_offset,fp) self.memo.clean() @@ -722,12 +673,12 @@ def visit(self,node): self.register_instruction(mips.CommentNode,"Saving reference to read string") reg1 = self.memo.get_unused_reg() - if reg1 != t1: - if t1 in self.memo.used_reg: - self.register_instruction(mips.MoveNode,reg1,t1) - else: - self.memo.clean() - self.register_instruction(mips.MoveNode, t1, a0) + #if reg1 != t1: + # if t1 in self.memo.used_reg: + # self.register_instruction(mips.MoveNode,reg1,t1) + # else: + # self.memo.clean() + self.register_instruction(mips.MoveNode, t7, a0) self.register_instruction(mips.CommentNode,"Calculating str length") self.register_instruction(mips.JumpAndLink, LENGTH) @@ -736,23 +687,21 @@ def visit(self,node): self.register_instruction(mips.CommentNode,"Allocating char array for new string") self.register_instruction(mips.LoadInmediate, v0, SYSCALL_SBRK) self.register_instruction(mips.SyscallNode) - if t0 in self.memo.used_reg: - reg2 = self.memo.get_unused_reg() - self.register_instruction(mips.MoveNode,reg2,t0) - self.register_instruction(mips.MoveNode, t0, v0) + + self.register_instruction(mips.MoveNode, t6, v0) reg3 = self.memo.get_unused_reg() self.register_instruction(mips.MoveNode, reg3, v0)#saving pointer to char array reg4 = self.memo.get_unused_reg() - self.register_instruction(mips.AddNode, a0, a0, -1) + #self.register_instruction(mips.AddNode, a0, a0, -1) self.register_instruction(mips.MoveNode, reg4, a0)#saving length self.register_instruction(mips.CommentNode,"Copying bytes from one char array to another") self.register_instruction(mips.JumpAndLink, COPY) self.register_instruction(mips.CommentNode,"Null-terminating the string") - self.register_instruction(mips.StoreByteNode, zero, 0, t0) + self.register_instruction(mips.StoreByteNode, zero, 0, t6) self.register_instruction(mips.CommentNode,"Allocating new String instance") _size = STRING_SIZE From c6c84a6b49106e3f573788d3affb50a8f34c5fae Mon Sep 17 00:00:00 2001 From: smartos99 Date: Tue, 8 Mar 2022 11:35:09 -0500 Subject: [PATCH 124/162] Testing mips --- customized_tests/code_gen/code_gen.py | 17 + customized_tests/code_gen/test_goto_if.cl | 13 + customized_tests/code_gen/test_goto_if.mips | 721 +++++++++++++++++ .../code_gen/test_goto_if_input.txt | 0 .../code_gen/test_goto_if_output.txt | 1 + customized_tests/code_gen/utils/__init__.py | 1 + customized_tests/code_gen/utils/utils.py | 91 +++ customized_tests/test_hello_world.cl | 161 +++- src/cmp/cil.py | 4 +- src/code_gen/mips_builder.py | 16 +- src/code_gen/mips_nodes.py | 8 + tests/code_gen.py | 18 + tests/code_gen/comparison.cl | 13 + tests/code_gen/comparison.mips | 684 ++++++++++++++++ tests/code_gen/comparison_input.txt | 0 tests/code_gen/comparison_output.txt | 1 + tests/code_gen/hello_world.cl | 5 + tests/code_gen/hello_world.mips | 646 +++++++++++++++ tests/code_gen/hello_world_input.txt | 0 tests/code_gen/hello_world_output.txt | 1 + tests/code_gen/point.cl | 15 + tests/code_gen/point.mips | 750 ++++++++++++++++++ tests/code_gen/point_input.txt | 0 tests/code_gen/point_output.txt | 1 + tests/code_gen/read_string.cl | 10 + tests/code_gen/read_string.mips | 674 ++++++++++++++++ tests/code_gen/read_string_input.txt | 1 + tests/code_gen/read_string_output.txt | 1 + tests/code_gen/test_goto_if.cl | 13 + tests/code_gen/test_goto_if.mips | 716 +++++++++++++++++ tests/code_gen/test_goto_if_input.txt | 0 tests/code_gen/test_goto_if_output.txt | 1 + tests/code_gen/utils/__init__.py | 1 + tests/code_gen/utils/utils.py | 91 +++ tests/test_1file.py | 4 +- 35 files changed, 4673 insertions(+), 6 deletions(-) create mode 100644 customized_tests/code_gen/code_gen.py create mode 100644 customized_tests/code_gen/test_goto_if.cl create mode 100644 customized_tests/code_gen/test_goto_if.mips create mode 100644 customized_tests/code_gen/test_goto_if_input.txt create mode 100644 customized_tests/code_gen/test_goto_if_output.txt create mode 100644 customized_tests/code_gen/utils/__init__.py create mode 100644 customized_tests/code_gen/utils/utils.py create mode 100644 tests/code_gen.py create mode 100644 tests/code_gen/comparison.cl create mode 100644 tests/code_gen/comparison.mips create mode 100644 tests/code_gen/comparison_input.txt create mode 100644 tests/code_gen/comparison_output.txt create mode 100644 tests/code_gen/hello_world.cl create mode 100644 tests/code_gen/hello_world.mips create mode 100644 tests/code_gen/hello_world_input.txt create mode 100644 tests/code_gen/hello_world_output.txt create mode 100644 tests/code_gen/point.cl create mode 100644 tests/code_gen/point.mips create mode 100644 tests/code_gen/point_input.txt create mode 100644 tests/code_gen/point_output.txt create mode 100644 tests/code_gen/read_string.cl create mode 100644 tests/code_gen/read_string.mips create mode 100644 tests/code_gen/read_string_input.txt create mode 100644 tests/code_gen/read_string_output.txt create mode 100644 tests/code_gen/test_goto_if.cl create mode 100644 tests/code_gen/test_goto_if.mips create mode 100644 tests/code_gen/test_goto_if_input.txt create mode 100644 tests/code_gen/test_goto_if_output.txt create mode 100644 tests/code_gen/utils/__init__.py create mode 100644 tests/code_gen/utils/utils.py diff --git a/customized_tests/code_gen/code_gen.py b/customized_tests/code_gen/code_gen.py new file mode 100644 index 000000000..a7eb0c3ca --- /dev/null +++ b/customized_tests/code_gen/code_gen.py @@ -0,0 +1,17 @@ +import pytest +import os +from utils.utils import compare_outputs + +tests_dir = __file__.rpartition('/')[0] + '/' +tests = [(file) for file in os.listdir(tests_dir) if file.endswith('.cl')] + +# @pytest.mark.lexer +# @pytest.mark.parser +# @pytest.mark.semantic +@pytest.mark.codegen +@pytest.mark.ok +@pytest.mark.run(order=4) +@pytest.mark.parametrize("cool_file", tests) +def test_codegen(compiler_path, cool_file): + compare_outputs(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_input.txt',\ + tests_dir + cool_file[:-3] + '_output.txt') \ No newline at end of file diff --git a/customized_tests/code_gen/test_goto_if.cl b/customized_tests/code_gen/test_goto_if.cl new file mode 100644 index 000000000..57e2f1f25 --- /dev/null +++ b/customized_tests/code_gen/test_goto_if.cl @@ -0,0 +1,13 @@ +class Main inherits IO{ + a : Int <- 1; + b : Int <- 2; + main (): Object { + { + a + b; + a - b; + a / b; + out_int(b * a); + } + + }; +}; \ No newline at end of file diff --git a/customized_tests/code_gen/test_goto_if.mips b/customized_tests/code_gen/test_goto_if.mips new file mode 100644 index 000000000..15b29bb0d --- /dev/null +++ b/customized_tests/code_gen/test_goto_if.mips @@ -0,0 +1,721 @@ +.data + +Object : .word, Object_abort, Object_copy, Object_type_name +Object_cname : .asciiz, "Object" +IO : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int +IO_cname : .asciiz, "IO" +String : .word, Object_abort, Object_copy, Object_type_name, String_length, String_concat, String_substr +String_cname : .asciiz, "String" +Int : .word, Object_abort, Object_copy, Object_type_name +Int_cname : .asciiz, "Int" +Bool : .word, Object_abort, Object_copy, Object_type_name +Bool_cname : .asciiz, "Bool" +Main : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int, Main_main, Main_constructor +Main_cname : .asciiz, "Main" +void : .word, -1 +empty_string : .asciiz, "" +input_str_buffer : .space, 1024 +abort_signal : .asciiz, "Program execution aborted" +case_missmatch : .asciiz, "Execution of a case statement without a matching branch" +case_on_void : .asciiz, "Case on void" +dispatch_on_void : .asciiz, "Dispatch on void" +division_by_zero : .asciiz, "Division by zero" +substr_out_of_range : .asciiz, "Substring out of range" +heap_overflow : .asciiz, "Heap overflow" + +.text +.globl main + +length: + li $t1, 0 + length_loop: + lb $t5, 0($a0) + beq $zero, $t5, length_end + add $t1, $t1, 1 + add $a0, $a0, 1 + j length_loop + length_end: + move $a0 $t1 + j $ra +copy: + copy_loop: + beq $zero, $a0, copy_end + lb $t7, 0($t1) + sb $t7, 0($t0) + addi $t0, $t0, 1 + addi $t1, $t1, 1 + addi $a0, $a0, -1 + j copy_loop + copy_end: + j $ra +Object_abort: + move $t6 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 0 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t6, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing RuntimeError + #Printing Abort Message + la $a0, abort_signal + li $v0, 4 + syscall + #Aborting execution + li $v0, 10 + syscall +Object_copy: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Object_type_name: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +IO_out_string: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 0 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #PrintStringNode + lw $a0, -4($fp) + lw $a0, 8($a0) + li $v0, 4 + syscall + #Executing Return + lw $a1, -8($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, 0 + #Return jump + jalr $ra +IO_out_int: + move $t8 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 0 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t8, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #PrintIntNode + lw $a0, -4($fp) + li $v0, 1 + syscall + #Executing Return + lw $a1, -8($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, 0 + #Return jump + jalr $ra +IO_in_string: + move $t3 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #ReadStrNode + #Reading String to buffer + la $a0, input_str_buffer + li $a1, 1024 + li $v0, 8 + syscall + #Saving reference to read string + move $t0 $t1 + move $t1 $a0 + #Calculating str length + jal length + #Allocating char array for new string + li $v0, 9 + syscall + move $t9 $t0 + move $t0 $v0 + move $t8 $v0 + add $a0, $a0, -1 + move $t3 $a0 + #Copying bytes from one char array to another + jal copy + #Null-terminating the string + sb $zero, 0($t0) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t4, String + sw $t4, 0($v0) + #Storing length and reference to char array + sw $t3, 4($v0) + sw $t8, 8($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +IO_in_int: + move $t8 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t8, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #ReadStrNode + #Reading String to buffer + la $a0, input_str_buffer + li $a1, 1024 + li $v0, 8 + syscall + #Saving reference to read string + move $t3 $t1 + move $t1 $a0 + #Calculating str length + jal length + #Allocating char array for new string + li $v0, 9 + syscall + move $t0 $v0 + move $t7 $v0 + add $a0, $a0, -1 + move $t9 $a0 + #Copying bytes from one char array to another + jal copy + #Null-terminating the string + sb $zero, 0($t0) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t6, String + sw $t6, 0($v0) + #Storing length and reference to char array + sw $t9, 4($v0) + sw $t7, 8($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_length: + move $t7 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t7, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Length + lw $t4, -4($fp) + lw $t4, 4($t4) + sw $t4, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_concat: + move $t7 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t7, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_substr: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Object_constructor: + move $t3 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t8, Object + sw $t8, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +IO_constructor: + move $t3 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t8, IO + sw $t8, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Int_constructor: + move $t7 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t7, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 8 + syscall + sw $v0, 0($fp) + la $t3, Int + sw $t3, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Bool_constructor: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 8 + syscall + sw $v0, 0($fp) + la $t3, Bool + sw $t3, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_constructor: + move $t6 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t6, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t8, String + sw $t8, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +main: + move $t6 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t6, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Static Call + jal Main_constructor + sw $a1, 0($fp) + addi $sp, $sp, 0 + #Receiving Arg local_main_internal_0 + lw $t6, 0($fp) + sw $t6, 0($sp) + addi $sp, $sp, 4 + #Executing Static Call + jal Main_main + sw $a1, 4($fp) + addi $sp, $sp, -4 + li $v0, 10 + syscall +Main_constructor: + move $t3 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 20 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t9, Main + sw $t9, 0($v0) + #Executing DefaultValue + li $t3, 0 + sw $t3, 4($fp) + #Executing SetAttr + lw $t7, 0($fp) + lw $t9, 4($fp) + sw $t9, 4($t7) + #Executing DefaultValue + li $t6, 0 + sw $t6, 8($fp) + #Executing SetAttr + lw $t8, 0($fp) + lw $t3, 8($fp) + sw $t3, 8($t8) + #Executing Assign + li $t7, 1 + sw $t7, 12($fp) + #Executing SetAttr + lw $t7, 0($fp) + lw $t8, 12($fp) + sw $t8, 4($t7) + #Executing Assign + li $t6, 2 + sw $t6, 16($fp) + #Executing SetAttr + lw $t7, 0($fp) + lw $t0, 16($fp) + sw $t0, 8($t7) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -20 + #Return jump + jalr $ra +Main_main: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 48 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing GetAttr + lw $t9, -4($fp) + lw $t0, 4($t9) + sw $t0, 4($fp) + #Executing GetAttr + lw $t3, -4($fp) + lw $t7, 8($t3) + sw $t7, 8($fp) + #Executing Plus Operation + lw $t6, 4($fp) + lw $t3, 8($fp) + add $t7, $t6, $t3 + sw $t7, 0($fp) + #Executing GetAttr + lw $t9, -4($fp) + lw $t7, 4($t9) + sw $t7, 12($fp) + #Executing GetAttr + lw $t8, -4($fp) + lw $t6, 8($t8) + sw $t6, 16($fp) + #Executing Minus Operation + lw $t6, 12($fp) + lw $t9, 16($fp) + sub $t7, $t6, $t9 + sw $t7, 0($fp) + #Executing GetAttr + lw $t8, -4($fp) + lw $t9, 4($t8) + sw $t9, 20($fp) + #Executing GetAttr + lw $t6, -4($fp) + lw $t0, 8($t6) + sw $t0, 24($fp) + #Executing Div Operation + lw $t7, 20($fp) + lw $t9, 24($fp) + div $t7, $t9 + mflo $t7 + sw $t7, 0($fp) + #Executing Assign + lw $t6, -4($fp) + sw $t6, 28($fp) + #Executing typeof + lw $t0, 28($fp) + lw $t0, 0($t0) + sw $t0, 32($fp) + #Executing GetAttr + lw $t3, -4($fp) + lw $t6, 8($t3) + sw $t6, 40($fp) + #Executing GetAttr + lw $t9, -4($fp) + lw $t3, 4($t9) + sw $t3, 44($fp) + #Executing Star Operation + lw $t9, 40($fp) + lw $t8, 44($fp) + mult $t9, $t8 + mflo $t9 + sw $t9, 36($fp) + #Receiving Arg local_Main_main_internal_7 + lw $t8, 28($fp) + sw $t8, 0($sp) + addi $sp, $sp, 4 + #Receiving Arg local_Main_main_internal_9 + lw $t8, 36($fp) + sw $t8, 0($sp) + addi $sp, $sp, 4 + #Executing Dynamic Call + lw $t3, 32($fp) + lw $t0, 16($t3) + jalr $t0 + sw $a1, 0($fp) + addi $sp, $sp, -8 + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -48 + #Return jump + jalr $ra diff --git a/customized_tests/code_gen/test_goto_if_input.txt b/customized_tests/code_gen/test_goto_if_input.txt new file mode 100644 index 000000000..e69de29bb diff --git a/customized_tests/code_gen/test_goto_if_output.txt b/customized_tests/code_gen/test_goto_if_output.txt new file mode 100644 index 000000000..d8263ee98 --- /dev/null +++ b/customized_tests/code_gen/test_goto_if_output.txt @@ -0,0 +1 @@ +2 \ No newline at end of file diff --git a/customized_tests/code_gen/utils/__init__.py b/customized_tests/code_gen/utils/__init__.py new file mode 100644 index 000000000..90f60fdd8 --- /dev/null +++ b/customized_tests/code_gen/utils/__init__.py @@ -0,0 +1 @@ +from .utils import * \ No newline at end of file diff --git a/customized_tests/code_gen/utils/utils.py b/customized_tests/code_gen/utils/utils.py new file mode 100644 index 000000000..961cf7cbc --- /dev/null +++ b/customized_tests/code_gen/utils/utils.py @@ -0,0 +1,91 @@ +import subprocess +import re + + +COMPILER_TIMEOUT = 'El compilador tarda mucho en responder.' +SPIM_TIMEOUT = 'El spim tarda mucho en responder.' +TEST_MUST_FAIL = 'El test %s debe fallar al compilar' +TEST_MUST_COMPILE = 'El test %s debe compilar' +BAD_ERROR_FORMAT = '''El error no esta en formato: (,) - : + o no se encuentra en la 3ra linea\n\n%s''' +UNEXPECTED_ERROR = 'Se esperaba un %s en (%d, %d). Su error fue un %s en (%d, %d)' +UNEXPECTED_OUTPUT = 'La salida de %s no es la esperada:\n%s\nEsperada:\n%s' + +ERROR_FORMAT = r'^\s*\(\s*(\d+)\s*,\s*(\d+)\s*\)\s*-\s*(\w+)\s*:(.*)$' + +def parse_error(error: str): + merror = re.fullmatch(ERROR_FORMAT, error) + assert merror, BAD_ERROR_FORMAT % error + + return (t(x) for t, x in zip([int, int, str, str], merror.groups())) + + +def first_error(compiler_output: list, errors: list): + line, column, error_type, _ = parse_error(errors[0]) + + oline, ocolumn, oerror_type, _ = parse_error(compiler_output[0]) + + assert line == oline and column == ocolumn and error_type == oerror_type,\ + UNEXPECTED_ERROR % (error_type, line, column, oerror_type, oline, ocolumn) + +def first_error_only_line(compiler_output: list, errors: list): + line, column, error_type, _ = parse_error(errors[0]) + + oline, ocolumn, oerror_type, _ = parse_error(compiler_output[0]) + + assert line == oline and error_type == oerror_type,\ + UNEXPECTED_ERROR % (error_type, line, column, oerror_type, oline, ocolumn) + + +def get_file_name(path: str): + try: + return path[path.rindex('/') + 1:] + except ValueError: + return path + +def compare_errors(compiler_path: str, cool_file_path: str, error_file_path: str, cmp=first_error, timeout=100): + try: + sp = subprocess.run(['bash', compiler_path, cool_file_path], capture_output=True, timeout=timeout) + return_code, output = sp.returncode, sp.stdout.decode() + except subprocess.TimeoutExpired: + assert False, COMPILER_TIMEOUT + + assert return_code == 1, TEST_MUST_FAIL % get_file_name(cool_file_path) + + fd = open(error_file_path, 'r') + errors = fd.read().split('\n') + fd.close() + + # checking the errors of compiler + compiler_output = output.split('\n') + cmp(compiler_output[2:], errors) + +SPIM_HEADER = r'''^SPIM Version .+ of .+ +Copyright .+\, James R\. Larus\. +All Rights Reserved\. +See the file README for a full copyright notice\. +(?:Loaded: .+\n)*''' +def compare_outputs(compiler_path: str, cool_file_path: str, input_file_path: str, output_file_path: str, timeout=100): + try: + sp = subprocess.run(['bash', compiler_path, cool_file_path], capture_output=True, timeout=timeout) + assert sp.returncode == 0, TEST_MUST_COMPILE % get_file_name(cool_file_path) + except subprocess.TimeoutExpired: + assert False, COMPILER_TIMEOUT + + spim_file = cool_file_path[:-2] + 'mips' + + try: + fd = open(input_file_path, 'rb') + sp = subprocess.run(['spim', '-file', spim_file], input=fd.read(), capture_output=True, timeout=timeout) + fd.close() + mo = re.match(SPIM_HEADER, sp.stdout.decode()) + if mo: + output = mo.string[mo.end():] + except subprocess.TimeoutExpired: + assert False, SPIM_TIMEOUT + + fd = open(output_file_path, 'r') + eoutput = fd.read() + fd.close() + + assert output == eoutput, UNEXPECTED_OUTPUT % (spim_file, repr(output), repr(eoutput)) diff --git a/customized_tests/test_hello_world.cl b/customized_tests/test_hello_world.cl index d0c285a71..ad1bd0fdf 100644 --- a/customized_tests/test_hello_world.cl +++ b/customized_tests/test_hello_world.cl @@ -1,3 +1,133 @@ + Class List inherits IO { + (* Since abort() returns Object, we need something of + type Bool at the end of the block to satisfy the typechecker. + This code is unreachable, since abort() halts the program. *) + isNil() : Bool { { abort(); true; } }; + + cons(hd : Int) : Cons { + (let new_cell : Cons <- new Cons in + new_cell.init(hd,self) + ) + }; + + (* + Since abort "returns" type Object, we have to add + an expression of type Int here to satisfy the typechecker. + This code is, of course, unreachable. + *) + car() : Int { { abort(); new Int; } }; + + cdr() : List { { abort(); new List; } }; + + rev() : List { cdr() }; + + sort() : List { cdr() }; + + insert(i : Int) : List { cdr() }; + + rcons(i : Int) : List { cdr() }; + + print_list() : Object { abort() }; +}; + +Class Cons inherits List { + xcar : Int; -- We keep the car in cdr in attributes. + xcdr : List; + + isNil() : Bool { false }; + + init(hd : Int, tl : List) : Cons { + { + xcar <- hd; + xcdr <- tl; + self; + } + }; + + car() : Int { xcar }; + + cdr() : List { xcdr }; + + rev() : List { (xcdr.rev()).rcons(xcar) }; + + sort() : List { (xcdr.sort()).insert(xcar) }; + + insert(i : Int) : List { + if i < xcar then + (new Cons).init(i,self) + else + (new Cons).init(xcar,xcdr.insert(i)) + fi + }; + + + rcons(i : Int) : List { (new Cons).init(xcar, xcdr.rcons(i)) }; + + print_list() : Object { + { + out_int(xcar); + out_string("\n"); + xcdr.print_list(); + } + }; +}; + +Class Nil inherits List { + isNil() : Bool { true }; + + rev() : List { self }; + + sort() : List { self }; + + insert(i : Int) : List { rcons(i) }; + + rcons(i : Int) : List { (new Cons).init(i,self) }; + + print_list() : Object { true }; + +}; + + +Class Main inherits IO { + + l : List; + + (* iota maps its integer argument n into the list 0..n-1 *) + iota(i : Int) : List { + { + l <- new Nil; + (let j : Int <- 0 in + while j < i + loop + { + l <- (new Cons).init(j,l); + j <- j + 1; + } + pool + ); + l; + } + }; + + main() : Object { + { + out_string("How many numbers to sort? "); + iota(in_int()).rev().sort().print_list(); + } + }; +}; + + + + +(* class Main inherits IO { + main(): IO { + out_string("Hello, World.\n") + }; +}; +*) + + (* class Main inherits IO { msg : String <- "Hello World"; @@ -5,13 +135,34 @@ self@IO.out_string(msg) }; }; + +*) + + + + + (* class Main inherits IO{ + main (): Object { + out_int((new Point).init(5, 6)) + + }; +}; + +class Point{ + x: Int; + y: Int; + + init(x0: AUTO_TYPE, y0: AUTO_TYPE): AUTO_TYPE { + x0 + y0 + }; +}; *) -class Main inherits IO{ + (* class Main inherits IO{ main (): Object { - self.out_int((new Point).init(5, 6)) + self@IO.out_int((new Point)@Point.init(5, 6)) }; }; @@ -24,4 +175,10 @@ class Point{ x0 + y0 }; }; +*) + + + + + diff --git a/src/cmp/cil.py b/src/cmp/cil.py index 4fc1301ba..4a0cd644b 100644 --- a/src/cmp/cil.py +++ b/src/cmp/cil.py @@ -104,7 +104,9 @@ class NotNode(UnaryNode): class IntComplementNode(UnaryNode): - pass + def __init__(self, dest, source): + self.source = source + self.dest = dest class GetAttribNode(InstructionNode): diff --git a/src/code_gen/mips_builder.py b/src/code_gen/mips_builder.py index 77ab44e53..f1a0abc80 100644 --- a/src/code_gen/mips_builder.py +++ b/src/code_gen/mips_builder.py @@ -657,7 +657,21 @@ def visit(self,node): self.memo.clean() - + @visitor.when(cil.IntComplementNode) + def visit(self,node): + self.memory_manager.save() + + source_offset = self.get_offset(node.source) + dest_offset = self.get_offset(node.dest) + + reg1 = self.memo.get_unused_register() + reg2 = self.memo.get_unused_register() + + self.register_instruction(mips.LoadWordNode,reg1,source_offset,fp) + self.register_instruction(mips.NotNode,reg2,reg1) + self.register_instruction(mips.AddiNode,reg2,reg2,1) + self.register_instruction(mips.StoreWordNode,reg2,dest_offset,fp) + self.memo.clean() #READSTRING diff --git a/src/code_gen/mips_nodes.py b/src/code_gen/mips_nodes.py index 3f07ffa59..22d36ac8c 100644 --- a/src/code_gen/mips_nodes.py +++ b/src/code_gen/mips_nodes.py @@ -100,6 +100,14 @@ def __str__(self): return f"{self.name} : {self.datatype}{values}" +class NotNode(InstructionNode): + def __init__(self, dest, source): + self.dest = dest + self.source = source + + def __str__(self): + return f"not {self.dest}, {self.source}" + class ArithAnfLogicNode(InstructionNode): def __init__(self, destination, left, right): self.destination = destination diff --git a/tests/code_gen.py b/tests/code_gen.py new file mode 100644 index 000000000..1fb167ad3 --- /dev/null +++ b/tests/code_gen.py @@ -0,0 +1,18 @@ +import pytest +import os +from utils import compare_outputs + + +tests_dir = __file__.rpartition('/')[0] + '/code_gen/' +tests = [(file) for file in os.listdir(tests_dir) if file.endswith('.cl')] + +# @pytest.mark.lexer +# @pytest.mark.parser +# @pytest.mark.semantic +@pytest.mark.codegen +@pytest.mark.ok +@pytest.mark.run(order=4) +@pytest.mark.parametrize("cool_file", tests) +def test_codegen(compiler_path, cool_file): + compare_outputs(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_input.txt',\ + tests_dir + cool_file[:-3] + '_output.txt') \ No newline at end of file diff --git a/tests/code_gen/comparison.cl b/tests/code_gen/comparison.cl new file mode 100644 index 000000000..0b8081562 --- /dev/null +++ b/tests/code_gen/comparison.cl @@ -0,0 +1,13 @@ + +class Main inherits IO{ + a : Int; + b : Int; + main (): Object { + { + a < b; + a <= b; + a = b; + out_string("Default value for Int should be 0"); + } + }; +}; diff --git a/tests/code_gen/comparison.mips b/tests/code_gen/comparison.mips new file mode 100644 index 000000000..52a87a0d3 --- /dev/null +++ b/tests/code_gen/comparison.mips @@ -0,0 +1,684 @@ +.data + +Object : .word, Object_abort, Object_copy, Object_type_name +Object_cname : .asciiz, "Object" +IO : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int +IO_cname : .asciiz, "IO" +String : .word, Object_abort, Object_copy, Object_type_name, String_length, String_concat, String_substr +String_cname : .asciiz, "String" +Int : .word, Object_abort, Object_copy, Object_type_name +Int_cname : .asciiz, "Int" +Bool : .word, Object_abort, Object_copy, Object_type_name +Bool_cname : .asciiz, "Bool" +Main : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int, Main_main, Main_constructor +Main_cname : .asciiz, "Main" +void : .word, -1 +empty_string : .asciiz, "" +input_str_buffer : .space, 1024 +abort_signal : .asciiz, "Program execution aborted" +case_missmatch : .asciiz, "Execution of a case statement without a matching branch" +case_on_void : .asciiz, "Case on void" +dispatch_on_void : .asciiz, "Dispatch on void" +division_by_zero : .asciiz, "Division by zero" +substr_out_of_range : .asciiz, "Substring out of range" +heap_overflow : .asciiz, "Heap overflow" +string_1 : .asciiz, "Default value for Int should be 0" + +.text +.globl main + +length: + li $t4, 0 + length_loop: + lb $t1, 0($a0) + beq $zero, $t1, length_end + add $t4, $t4, 1 + add $a0, $a0, 1 + j length_loop + length_end: + move $a0 $t4 + j $ra +copy: + copy_loop: + beq $zero, $a0, copy_end + lb $t8, 0($t7) + sb $t8, 0($t6) + addi $t6, $t6, 1 + addi $t7, $t7, 1 + addi $a0, $a0, -1 + j copy_loop + copy_end: + j $ra +Object_abort: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 0 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing RuntimeError + #Printing Abort Message + la $a0, abort_signal + li $v0, 4 + syscall + #Aborting execution + li $v0, 10 + syscall +Object_copy: + move $t2 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Object_type_name: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +IO_out_string: + move $t5 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 0 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #PrintStringNode + lw $a0, -4($fp) + lw $a0, 8($a0) + li $v0, 4 + syscall + #Executing Return + lw $a1, -8($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, 0 + #Return jump + jalr $ra +IO_out_int: + move $t2 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 0 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #PrintIntNode + lw $a0, -4($fp) + li $v0, 1 + syscall + #Executing Return + lw $a1, -8($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, 0 + #Return jump + jalr $ra +IO_in_string: + move $t2 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #ReadStrNode + #Reading String to buffer + la $a0, input_str_buffer + li $a1, 1024 + li $v0, 8 + syscall + #Saving reference to read string + move $t7 $a0 + #Calculating str length + jal length + #Allocating char array for new string + li $v0, 9 + syscall + move $t6 $v0 + move $t9 $v0 + move $t2 $a0 + #Copying bytes from one char array to another + jal copy + #Null-terminating the string + sb $zero, 0($t6) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t0, String + sw $t0, 0($v0) + #Storing length and reference to char array + sw $t2, 4($v0) + sw $t9, 8($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +IO_in_int: + move $t2 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #ReadStrNode + #Reading String to buffer + la $a0, input_str_buffer + li $a1, 1024 + li $v0, 8 + syscall + #Saving reference to read string + move $t7 $a0 + #Calculating str length + jal length + #Allocating char array for new string + li $v0, 9 + syscall + move $t6 $v0 + move $t5 $v0 + move $t9 $a0 + #Copying bytes from one char array to another + jal copy + #Null-terminating the string + sb $zero, 0($t6) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t3, String + sw $t3, 0($v0) + #Storing length and reference to char array + sw $t9, 4($v0) + sw $t5, 8($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_length: + move $t5 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Length + lw $t2, -4($fp) + lw $t2, 4($t2) + sw $t2, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_concat: + move $t3 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_substr: + move $t5 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Object_constructor: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t3, Object + sw $t3, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +IO_constructor: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t5, IO + sw $t5, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Int_constructor: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 8 + syscall + sw $v0, 0($fp) + la $t3, Int + sw $t3, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Bool_constructor: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 8 + syscall + sw $v0, 0($fp) + la $t9, Bool + sw $t9, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_constructor: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t5, String + sw $t5, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +main: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Static Call + jal Main_constructor + sw $a1, 0($fp) + addi $sp, $sp, 0 + #Receiving Arg local_main_internal_0 + lw $t9, 0($fp) + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing Static Call + jal Main_main + sw $a1, 4($fp) + addi $sp, $sp, -4 + li $v0, 10 + syscall +Main_constructor: + move $t3 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 12 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t9, Main + sw $t9, 0($v0) + #Executing DefaultValue + li $t3, 0 + sw $t3, 4($fp) + #Executing SetAttr + lw $t0, 0($fp) + lw $t5, 4($fp) + sw $t5, 4($t0) + #Executing DefaultValue + li $t5, 0 + sw $t5, 8($fp) + #Executing SetAttr + lw $t5, 0($fp) + lw $t9, 8($fp) + sw $t9, 8($t5) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -12 + #Return jump + jalr $ra +Main_main: + move $t5 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 40 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing GetAttr + lw $t5, -4($fp) + lw $t9, 4($t5) + sw $t9, 4($fp) + #Executing GetAttr + lw $t9, -4($fp) + lw $t3, 8($t9) + sw $t3, 8($fp) + #Executing GetAttr + lw $t5, -4($fp) + lw $t0, 4($t5) + sw $t0, 12($fp) + #Executing GetAttr + lw $t3, -4($fp) + lw $t9, 8($t3) + sw $t9, 16($fp) + #Executing GetAttr + lw $t5, -4($fp) + lw $t9, 4($t5) + sw $t9, 20($fp) + #Executing GetAttr + lw $t5, -4($fp) + lw $t0, 8($t5) + sw $t0, 24($fp) + #Executing Assign + lw $t0, -4($fp) + sw $t0, 28($fp) + #Executing typeof + lw $t0, 28($fp) + lw $t0, 0($t0) + sw $t0, 32($fp) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 36($fp) + la $t9, String + sw $t9, 0($v0) + li $t9, 33 + sw $t9, 4($v0) + la $t9, string_1 + sw $t9, 8($v0) + #Receiving Arg local_Main_main_internal_7 + lw $t9, 28($fp) + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Receiving Arg local_Main_main_internal_9 + lw $t5, 36($fp) + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing Dynamic Call + lw $t0, 32($fp) + lw $t9, 12($t0) + jalr $t9 + sw $a1, 0($fp) + addi $sp, $sp, -8 + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -40 + #Return jump + jalr $ra diff --git a/tests/code_gen/comparison_input.txt b/tests/code_gen/comparison_input.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/code_gen/comparison_output.txt b/tests/code_gen/comparison_output.txt new file mode 100644 index 000000000..37a6afb04 --- /dev/null +++ b/tests/code_gen/comparison_output.txt @@ -0,0 +1 @@ +Default value for Int should be 0 \ No newline at end of file diff --git a/tests/code_gen/hello_world.cl b/tests/code_gen/hello_world.cl new file mode 100644 index 000000000..b41b36c81 --- /dev/null +++ b/tests/code_gen/hello_world.cl @@ -0,0 +1,5 @@ +class Main inherits IO { + main(): IO { + out_string("Hello, World.\n") + }; +}; \ No newline at end of file diff --git a/tests/code_gen/hello_world.mips b/tests/code_gen/hello_world.mips new file mode 100644 index 000000000..d35d7c6ce --- /dev/null +++ b/tests/code_gen/hello_world.mips @@ -0,0 +1,646 @@ +.data + +Object : .word, Object_abort, Object_copy, Object_type_name +Object_cname : .asciiz, "Object" +IO : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int +IO_cname : .asciiz, "IO" +String : .word, Object_abort, Object_copy, Object_type_name, String_length, String_concat, String_substr +String_cname : .asciiz, "String" +Int : .word, Object_abort, Object_copy, Object_type_name +Int_cname : .asciiz, "Int" +Bool : .word, Object_abort, Object_copy, Object_type_name +Bool_cname : .asciiz, "Bool" +Main : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int, Main_main, Main_constructor +Main_cname : .asciiz, "Main" +void : .word, -1 +empty_string : .asciiz, "" +input_str_buffer : .space, 1024 +abort_signal : .asciiz, "Program execution aborted" +case_missmatch : .asciiz, "Execution of a case statement without a matching branch" +case_on_void : .asciiz, "Case on void" +dispatch_on_void : .asciiz, "Dispatch on void" +division_by_zero : .asciiz, "Division by zero" +substr_out_of_range : .asciiz, "Substring out of range" +heap_overflow : .asciiz, "Heap overflow" +string_1 : .asciiz, "Hello, World.\n" + +.text +.globl main + +length: + li $t0, 0 + length_loop: + lb $t2, 0($a0) + beq $zero, $t2, length_end + add $t0, $t0, 1 + add $a0, $a0, 1 + j length_loop + length_end: + move $a0 $t0 + j $ra +copy: + copy_loop: + beq $zero, $a0, copy_end + lb $t8, 0($t7) + sb $t8, 0($t6) + addi $t6, $t6, 1 + addi $t7, $t7, 1 + addi $a0, $a0, -1 + j copy_loop + copy_end: + j $ra +Object_abort: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 0 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing RuntimeError + #Printing Abort Message + la $a0, abort_signal + li $v0, 4 + syscall + #Aborting execution + li $v0, 10 + syscall +Object_copy: + move $t5 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Object_type_name: + move $t3 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +IO_out_string: + move $t3 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 0 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #PrintStringNode + lw $a0, -4($fp) + lw $a0, 8($a0) + li $v0, 4 + syscall + #Executing Return + lw $a1, -8($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, 0 + #Return jump + jalr $ra +IO_out_int: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 0 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #PrintIntNode + lw $a0, -4($fp) + li $v0, 1 + syscall + #Executing Return + lw $a1, -8($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, 0 + #Return jump + jalr $ra +IO_in_string: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #ReadStrNode + #Reading String to buffer + la $a0, input_str_buffer + li $a1, 1024 + li $v0, 8 + syscall + #Saving reference to read string + move $t7 $a0 + #Calculating str length + jal length + #Allocating char array for new string + li $v0, 9 + syscall + move $t6 $v0 + move $t5 $v0 + move $t1 $a0 + #Copying bytes from one char array to another + jal copy + #Null-terminating the string + sb $zero, 0($t6) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t3, String + sw $t3, 0($v0) + #Storing length and reference to char array + sw $t1, 4($v0) + sw $t5, 8($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +IO_in_int: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #ReadStrNode + #Reading String to buffer + la $a0, input_str_buffer + li $a1, 1024 + li $v0, 8 + syscall + #Saving reference to read string + move $t7 $a0 + #Calculating str length + jal length + #Allocating char array for new string + li $v0, 9 + syscall + move $t6 $v0 + move $t5 $v0 + move $t9 $a0 + #Copying bytes from one char array to another + jal copy + #Null-terminating the string + sb $zero, 0($t6) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t1, String + sw $t1, 0($v0) + #Storing length and reference to char array + sw $t9, 4($v0) + sw $t5, 8($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_length: + move $t4 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Length + lw $t4, -4($fp) + lw $t4, 4($t4) + sw $t4, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_concat: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_substr: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Object_constructor: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t3, Object + sw $t3, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +IO_constructor: + move $t5 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t9, IO + sw $t9, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Int_constructor: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 8 + syscall + sw $v0, 0($fp) + la $t9, Int + sw $t9, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Bool_constructor: + move $t3 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 8 + syscall + sw $v0, 0($fp) + la $t9, Bool + sw $t9, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_constructor: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t9, String + sw $t9, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +main: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Static Call + jal Main_constructor + sw $a1, 0($fp) + addi $sp, $sp, 0 + #Receiving Arg local_main_internal_0 + lw $t1, 0($fp) + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing Static Call + jal Main_main + sw $a1, 4($fp) + addi $sp, $sp, -4 + li $v0, 10 + syscall +Main_constructor: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t5, Main + sw $t5, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Main_main: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 16 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Assign + lw $t9, -4($fp) + sw $t9, 4($fp) + #Executing typeof + lw $t5, 4($fp) + lw $t5, 0($t5) + sw $t5, 8($fp) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 12($fp) + la $t9, String + sw $t9, 0($v0) + li $t9, 15 + sw $t9, 4($v0) + la $t9, string_1 + sw $t9, 8($v0) + #Receiving Arg local_Main_main_internal_1 + lw $t1, 4($fp) + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Receiving Arg local_Main_main_internal_3 + lw $t3, 12($fp) + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing Dynamic Call + lw $t9, 8($fp) + lw $t1, 12($t9) + jalr $t1 + sw $a1, 0($fp) + addi $sp, $sp, -8 + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -16 + #Return jump + jalr $ra diff --git a/tests/code_gen/hello_world_input.txt b/tests/code_gen/hello_world_input.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/code_gen/hello_world_output.txt b/tests/code_gen/hello_world_output.txt new file mode 100644 index 000000000..349db2bfe --- /dev/null +++ b/tests/code_gen/hello_world_output.txt @@ -0,0 +1 @@ +Hello, World. diff --git a/tests/code_gen/point.cl b/tests/code_gen/point.cl new file mode 100644 index 000000000..fb0e4f25b --- /dev/null +++ b/tests/code_gen/point.cl @@ -0,0 +1,15 @@ +class Main inherits IO{ + main (): Object { + out_int((new Point).init(5, 6)) + + }; +}; + +class Point{ + x: Int; + y: Int; + + init(x0: AUTO_TYPE, y0: AUTO_TYPE): AUTO_TYPE { + x0 + y0 + }; +}; diff --git a/tests/code_gen/point.mips b/tests/code_gen/point.mips new file mode 100644 index 000000000..6e810f088 --- /dev/null +++ b/tests/code_gen/point.mips @@ -0,0 +1,750 @@ +.data + +Object : .word, Object_abort, Object_copy, Object_type_name +Object_cname : .asciiz, "Object" +IO : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int +IO_cname : .asciiz, "IO" +String : .word, Object_abort, Object_copy, Object_type_name, String_length, String_concat, String_substr +String_cname : .asciiz, "String" +Int : .word, Object_abort, Object_copy, Object_type_name +Int_cname : .asciiz, "Int" +Bool : .word, Object_abort, Object_copy, Object_type_name +Bool_cname : .asciiz, "Bool" +Main : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int, Main_main, Main_constructor +Main_cname : .asciiz, "Main" +Point : .word, Object_abort, Object_copy, Object_type_name, Point_init, Point_constructor +Point_cname : .asciiz, "Point" +void : .word, -1 +empty_string : .asciiz, "" +input_str_buffer : .space, 1024 +abort_signal : .asciiz, "Program execution aborted" +case_missmatch : .asciiz, "Execution of a case statement without a matching branch" +case_on_void : .asciiz, "Case on void" +dispatch_on_void : .asciiz, "Dispatch on void" +division_by_zero : .asciiz, "Division by zero" +substr_out_of_range : .asciiz, "Substring out of range" +heap_overflow : .asciiz, "Heap overflow" + +.text +.globl main + +length: + li $t1, 0 + length_loop: + lb $t0, 0($a0) + beq $zero, $t0, length_end + add $t1, $t1, 1 + add $a0, $a0, 1 + j length_loop + length_end: + move $a0 $t1 + j $ra +copy: + copy_loop: + beq $zero, $a0, copy_end + lb $t8, 0($t7) + sb $t8, 0($t6) + addi $t6, $t6, 1 + addi $t7, $t7, 1 + addi $a0, $a0, -1 + j copy_loop + copy_end: + j $ra +Object_abort: + move $t3 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 0 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing RuntimeError + #Printing Abort Message + la $a0, abort_signal + li $v0, 4 + syscall + #Aborting execution + li $v0, 10 + syscall +Object_copy: + move $t3 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Object_type_name: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +IO_out_string: + move $t2 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 0 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #PrintStringNode + lw $a0, -4($fp) + lw $a0, 8($a0) + li $v0, 4 + syscall + #Executing Return + lw $a1, -8($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, 0 + #Return jump + jalr $ra +IO_out_int: + move $t5 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 0 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #PrintIntNode + lw $a0, -4($fp) + li $v0, 1 + syscall + #Executing Return + lw $a1, -8($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, 0 + #Return jump + jalr $ra +IO_in_string: + move $t4 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #ReadStrNode + #Reading String to buffer + la $a0, input_str_buffer + li $a1, 1024 + li $v0, 8 + syscall + #Saving reference to read string + move $t7 $a0 + #Calculating str length + jal length + #Allocating char array for new string + li $v0, 9 + syscall + move $t6 $v0 + move $t5 $v0 + move $t9 $a0 + #Copying bytes from one char array to another + jal copy + #Null-terminating the string + sb $zero, 0($t6) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t4, String + sw $t4, 0($v0) + #Storing length and reference to char array + sw $t9, 4($v0) + sw $t5, 8($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +IO_in_int: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #ReadStrNode + #Reading String to buffer + la $a0, input_str_buffer + li $a1, 1024 + li $v0, 8 + syscall + #Saving reference to read string + move $t7 $a0 + #Calculating str length + jal length + #Allocating char array for new string + li $v0, 9 + syscall + move $t6 $v0 + move $t9 $v0 + move $t5 $a0 + #Copying bytes from one char array to another + jal copy + #Null-terminating the string + sb $zero, 0($t6) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t2, String + sw $t2, 0($v0) + #Storing length and reference to char array + sw $t5, 4($v0) + sw $t9, 8($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_length: + move $t4 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Length + lw $t5, -4($fp) + lw $t5, 4($t5) + sw $t5, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_concat: + move $t3 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_substr: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Object_constructor: + move $t2 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t3, Object + sw $t3, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +IO_constructor: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t2, IO + sw $t2, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Int_constructor: + move $t3 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 8 + syscall + sw $v0, 0($fp) + la $t3, Int + sw $t3, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Bool_constructor: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 8 + syscall + sw $v0, 0($fp) + la $t4, Bool + sw $t4, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_constructor: + move $t2 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t2, String + sw $t2, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +main: + move $t4 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Static Call + jal Main_constructor + sw $a1, 0($fp) + addi $sp, $sp, 0 + #Receiving Arg local_main_internal_0 + lw $t9, 0($fp) + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing Static Call + jal Main_main + sw $a1, 4($fp) + addi $sp, $sp, -4 + li $v0, 10 + syscall +Main_constructor: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t3, Main + sw $t3, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Main_main: + move $t3 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 32 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Assign + lw $t4, -4($fp) + sw $t4, 4($fp) + #Executing typeof + lw $t4, 4($fp) + lw $t4, 0($t4) + sw $t4, 8($fp) + #Executing Static Call + jal Point_constructor + sw $a1, 16($fp) + addi $sp, $sp, 0 + #Executing typeof + lw $t3, 16($fp) + lw $t3, 0($t3) + sw $t3, 20($fp) + #Executing Assign + li $t4, 5 + sw $t4, 24($fp) + #Executing Assign + li $t3, 6 + sw $t3, 28($fp) + #Receiving Arg local_Main_main_internal_4 + lw $t9, 16($fp) + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Receiving Arg local_Main_main_internal_6 + lw $t4, 24($fp) + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Receiving Arg local_Main_main_internal_7 + lw $t2, 28($fp) + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Executing Dynamic Call + lw $t3, 20($fp) + lw $t4, 12($t3) + jalr $t4 + sw $a1, 12($fp) + addi $sp, $sp, -12 + #Receiving Arg local_Main_main_internal_1 + lw $t4, 4($fp) + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Receiving Arg local_Main_main_internal_3 + lw $t2, 12($fp) + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Executing Dynamic Call + lw $t2, 8($fp) + lw $t9, 16($t2) + jalr $t9 + sw $a1, 0($fp) + addi $sp, $sp, -8 + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -32 + #Return jump + jalr $ra +Point_constructor: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 12 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t4, Point + sw $t4, 0($v0) + #Executing DefaultValue + li $t4, 0 + sw $t4, 4($fp) + #Executing SetAttr + lw $t3, 0($fp) + lw $t9, 4($fp) + sw $t9, 4($t3) + #Executing DefaultValue + li $t3, 0 + sw $t3, 8($fp) + #Executing SetAttr + lw $t4, 0($fp) + lw $t2, 8($fp) + sw $t2, 8($t4) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -12 + #Return jump + jalr $ra +Point_init: + move $t3 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 12 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Assign + lw $t3, -8($fp) + sw $t3, 4($fp) + #Executing Assign + lw $t4, -4($fp) + sw $t4, 8($fp) + #Executing Plus Operation + lw $t4, 4($fp) + lw $t9, 8($fp) + add $t3, $t4, $t9 + sw $t3, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -12 + #Return jump + jalr $ra diff --git a/tests/code_gen/point_input.txt b/tests/code_gen/point_input.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/code_gen/point_output.txt b/tests/code_gen/point_output.txt new file mode 100644 index 000000000..9d607966b --- /dev/null +++ b/tests/code_gen/point_output.txt @@ -0,0 +1 @@ +11 \ No newline at end of file diff --git a/tests/code_gen/read_string.cl b/tests/code_gen/read_string.cl new file mode 100644 index 000000000..0d1bbe934 --- /dev/null +++ b/tests/code_gen/read_string.cl @@ -0,0 +1,10 @@ +class Main inherits IO{ + a : String; + main (): Object { + { + a <- in_string(); + out_string(a); + } + + }; +}; \ No newline at end of file diff --git a/tests/code_gen/read_string.mips b/tests/code_gen/read_string.mips new file mode 100644 index 000000000..22507cbd8 --- /dev/null +++ b/tests/code_gen/read_string.mips @@ -0,0 +1,674 @@ +.data + +Object : .word, Object_abort, Object_copy, Object_type_name +Object_cname : .asciiz, "Object" +IO : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int +IO_cname : .asciiz, "IO" +String : .word, Object_abort, Object_copy, Object_type_name, String_length, String_concat, String_substr +String_cname : .asciiz, "String" +Int : .word, Object_abort, Object_copy, Object_type_name +Int_cname : .asciiz, "Int" +Bool : .word, Object_abort, Object_copy, Object_type_name +Bool_cname : .asciiz, "Bool" +Main : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int, Main_main, Main_constructor +Main_cname : .asciiz, "Main" +void : .word, -1 +empty_string : .asciiz, "" +input_str_buffer : .space, 1024 +abort_signal : .asciiz, "Program execution aborted" +case_missmatch : .asciiz, "Execution of a case statement without a matching branch" +case_on_void : .asciiz, "Case on void" +dispatch_on_void : .asciiz, "Dispatch on void" +division_by_zero : .asciiz, "Division by zero" +substr_out_of_range : .asciiz, "Substring out of range" +heap_overflow : .asciiz, "Heap overflow" + +.text +.globl main + +length: + li $t0, 0 + length_loop: + lb $t4, 0($a0) + beq $zero, $t4, length_end + add $t0, $t0, 1 + add $a0, $a0, 1 + j length_loop + length_end: + move $a0 $t0 + j $ra +copy: + copy_loop: + beq $zero, $a0, copy_end + lb $t8, 0($t7) + sb $t8, 0($t6) + addi $t6, $t6, 1 + addi $t7, $t7, 1 + addi $a0, $a0, -1 + j copy_loop + copy_end: + j $ra +Object_abort: + move $t3 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 0 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing RuntimeError + #Printing Abort Message + la $a0, abort_signal + li $v0, 4 + syscall + #Aborting execution + li $v0, 10 + syscall +Object_copy: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Object_type_name: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +IO_out_string: + move $t2 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 0 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #PrintStringNode + lw $a0, -4($fp) + lw $a0, 8($a0) + li $v0, 4 + syscall + #Executing Return + lw $a1, -8($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, 0 + #Return jump + jalr $ra +IO_out_int: + move $t3 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 0 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #PrintIntNode + lw $a0, -4($fp) + li $v0, 1 + syscall + #Executing Return + lw $a1, -8($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, 0 + #Return jump + jalr $ra +IO_in_string: + move $t2 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #ReadStrNode + #Reading String to buffer + la $a0, input_str_buffer + li $a1, 1024 + li $v0, 8 + syscall + #Saving reference to read string + move $t7 $a0 + #Calculating str length + jal length + #Allocating char array for new string + li $v0, 9 + syscall + move $t6 $v0 + move $t2 $v0 + move $t1 $a0 + #Copying bytes from one char array to another + jal copy + #Null-terminating the string + sb $zero, 0($t6) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t9, String + sw $t9, 0($v0) + #Storing length and reference to char array + sw $t1, 4($v0) + sw $t2, 8($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +IO_in_int: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #ReadStrNode + #Reading String to buffer + la $a0, input_str_buffer + li $a1, 1024 + li $v0, 8 + syscall + #Saving reference to read string + move $t7 $a0 + #Calculating str length + jal length + #Allocating char array for new string + li $v0, 9 + syscall + move $t6 $v0 + move $t1 $v0 + move $t2 $a0 + #Copying bytes from one char array to another + jal copy + #Null-terminating the string + sb $zero, 0($t6) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t3, String + sw $t3, 0($v0) + #Storing length and reference to char array + sw $t2, 4($v0) + sw $t1, 8($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_length: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Length + lw $t3, -4($fp) + lw $t3, 4($t3) + sw $t3, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_concat: + move $t5 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_substr: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Object_constructor: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t5, Object + sw $t5, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +IO_constructor: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t5, IO + sw $t5, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Int_constructor: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 8 + syscall + sw $v0, 0($fp) + la $t2, Int + sw $t2, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Bool_constructor: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 8 + syscall + sw $v0, 0($fp) + la $t9, Bool + sw $t9, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_constructor: + move $t2 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t1, String + sw $t1, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +main: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Static Call + jal Main_constructor + sw $a1, 0($fp) + addi $sp, $sp, 0 + #Receiving Arg local_main_internal_0 + lw $t1, 0($fp) + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing Static Call + jal Main_main + sw $a1, 4($fp) + addi $sp, $sp, -4 + li $v0, 10 + syscall +Main_constructor: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 8 + syscall + sw $v0, 0($fp) + la $t9, Main + sw $t9, 0($v0) + #Executing DefaultValue + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t9, String + sw $t9, 0($v0) + li $t9, 0 + sw $t9, 4($v0) + la $t9, empty_string + sw $t9, 8($v0) + #Executing SetAttr + lw $t5, 0($fp) + lw $t1, 4($fp) + sw $t1, 4($t5) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra +Main_main: + move $t5 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 24 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Assign + lw $t1, -4($fp) + sw $t1, 4($fp) + #Executing typeof + lw $t2, 4($fp) + lw $t2, 0($t2) + sw $t2, 8($fp) + #Receiving Arg local_Main_main_internal_1 + lw $t5, 4($fp) + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing Dynamic Call + lw $t1, 8($fp) + lw $t9, 20($t1) + jalr $t9 + sw $a1, 0($fp) + addi $sp, $sp, -4 + #Executing SetAttr + lw $t2, -4($fp) + lw $t9, 0($fp) + sw $t9, 4($t2) + #Executing Assign + lw $t1, -4($fp) + sw $t1, 12($fp) + #Executing typeof + lw $t9, 12($fp) + lw $t9, 0($t9) + sw $t9, 16($fp) + #Executing GetAttr + lw $t5, -4($fp) + lw $t1, 4($t5) + sw $t1, 20($fp) + #Receiving Arg local_Main_main_internal_3 + lw $t2, 12($fp) + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Receiving Arg local_Main_main_internal_5 + lw $t5, 20($fp) + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing Dynamic Call + lw $t5, 16($fp) + lw $t9, 12($t5) + jalr $t9 + sw $a1, 0($fp) + addi $sp, $sp, -8 + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -24 + #Return jump + jalr $ra diff --git a/tests/code_gen/read_string_input.txt b/tests/code_gen/read_string_input.txt new file mode 100644 index 000000000..43e0c3c8b --- /dev/null +++ b/tests/code_gen/read_string_input.txt @@ -0,0 +1 @@ +Feliz dia de la mujer \ No newline at end of file diff --git a/tests/code_gen/read_string_output.txt b/tests/code_gen/read_string_output.txt new file mode 100644 index 000000000..43e0c3c8b --- /dev/null +++ b/tests/code_gen/read_string_output.txt @@ -0,0 +1 @@ +Feliz dia de la mujer \ No newline at end of file diff --git a/tests/code_gen/test_goto_if.cl b/tests/code_gen/test_goto_if.cl new file mode 100644 index 000000000..57e2f1f25 --- /dev/null +++ b/tests/code_gen/test_goto_if.cl @@ -0,0 +1,13 @@ +class Main inherits IO{ + a : Int <- 1; + b : Int <- 2; + main (): Object { + { + a + b; + a - b; + a / b; + out_int(b * a); + } + + }; +}; \ No newline at end of file diff --git a/tests/code_gen/test_goto_if.mips b/tests/code_gen/test_goto_if.mips new file mode 100644 index 000000000..0f3421dc1 --- /dev/null +++ b/tests/code_gen/test_goto_if.mips @@ -0,0 +1,716 @@ +.data + +Object : .word, Object_abort, Object_copy, Object_type_name +Object_cname : .asciiz, "Object" +IO : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int +IO_cname : .asciiz, "IO" +String : .word, Object_abort, Object_copy, Object_type_name, String_length, String_concat, String_substr +String_cname : .asciiz, "String" +Int : .word, Object_abort, Object_copy, Object_type_name +Int_cname : .asciiz, "Int" +Bool : .word, Object_abort, Object_copy, Object_type_name +Bool_cname : .asciiz, "Bool" +Main : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int, Main_main, Main_constructor +Main_cname : .asciiz, "Main" +void : .word, -1 +empty_string : .asciiz, "" +input_str_buffer : .space, 1024 +abort_signal : .asciiz, "Program execution aborted" +case_missmatch : .asciiz, "Execution of a case statement without a matching branch" +case_on_void : .asciiz, "Case on void" +dispatch_on_void : .asciiz, "Dispatch on void" +division_by_zero : .asciiz, "Division by zero" +substr_out_of_range : .asciiz, "Substring out of range" +heap_overflow : .asciiz, "Heap overflow" + +.text +.globl main + +length: + li $t3, 0 + length_loop: + lb $t1, 0($a0) + beq $zero, $t1, length_end + add $t3, $t3, 1 + add $a0, $a0, 1 + j length_loop + length_end: + move $a0 $t3 + j $ra +copy: + copy_loop: + beq $zero, $a0, copy_end + lb $t8, 0($t7) + sb $t8, 0($t6) + addi $t6, $t6, 1 + addi $t7, $t7, 1 + addi $a0, $a0, -1 + j copy_loop + copy_end: + j $ra +Object_abort: + move $t2 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 0 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing RuntimeError + #Printing Abort Message + la $a0, abort_signal + li $v0, 4 + syscall + #Aborting execution + li $v0, 10 + syscall +Object_copy: + move $t4 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Object_type_name: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +IO_out_string: + move $t2 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 0 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #PrintStringNode + lw $a0, -4($fp) + lw $a0, 8($a0) + li $v0, 4 + syscall + #Executing Return + lw $a1, -8($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, 0 + #Return jump + jalr $ra +IO_out_int: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 0 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #PrintIntNode + lw $a0, -4($fp) + li $v0, 1 + syscall + #Executing Return + lw $a1, -8($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, 0 + #Return jump + jalr $ra +IO_in_string: + move $t4 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #ReadStrNode + #Reading String to buffer + la $a0, input_str_buffer + li $a1, 1024 + li $v0, 8 + syscall + #Saving reference to read string + move $t7 $a0 + #Calculating str length + jal length + #Allocating char array for new string + li $v0, 9 + syscall + move $t6 $v0 + move $t5 $v0 + move $t9 $a0 + #Copying bytes from one char array to another + jal copy + #Null-terminating the string + sb $zero, 0($t6) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t4, String + sw $t4, 0($v0) + #Storing length and reference to char array + sw $t9, 4($v0) + sw $t5, 8($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +IO_in_int: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #ReadStrNode + #Reading String to buffer + la $a0, input_str_buffer + li $a1, 1024 + li $v0, 8 + syscall + #Saving reference to read string + move $t7 $a0 + #Calculating str length + jal length + #Allocating char array for new string + li $v0, 9 + syscall + move $t6 $v0 + move $t4 $v0 + move $t0 $a0 + #Copying bytes from one char array to another + jal copy + #Null-terminating the string + sb $zero, 0($t6) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t9, String + sw $t9, 0($v0) + #Storing length and reference to char array + sw $t0, 4($v0) + sw $t4, 8($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_length: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Length + lw $t9, -4($fp) + lw $t9, 4($t9) + sw $t9, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_concat: + move $t4 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_substr: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Object_constructor: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t5, Object + sw $t5, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +IO_constructor: + move $t4 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t0, IO + sw $t0, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Int_constructor: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 8 + syscall + sw $v0, 0($fp) + la $t4, Int + sw $t4, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Bool_constructor: + move $t2 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 8 + syscall + sw $v0, 0($fp) + la $t2, Bool + sw $t2, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_constructor: + move $t4 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t5, String + sw $t5, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +main: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Static Call + jal Main_constructor + sw $a1, 0($fp) + addi $sp, $sp, 0 + #Receiving Arg local_main_internal_0 + lw $t2, 0($fp) + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Executing Static Call + jal Main_main + sw $a1, 4($fp) + addi $sp, $sp, -4 + li $v0, 10 + syscall +Main_constructor: + move $t2 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 20 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t4, Main + sw $t4, 0($v0) + #Executing DefaultValue + li $t2, 0 + sw $t2, 4($fp) + #Executing SetAttr + lw $t0, 0($fp) + lw $t4, 4($fp) + sw $t4, 4($t0) + #Executing DefaultValue + li $t0, 0 + sw $t0, 8($fp) + #Executing SetAttr + lw $t5, 0($fp) + lw $t4, 8($fp) + sw $t4, 8($t5) + #Executing Assign + li $t2, 1 + sw $t2, 12($fp) + #Executing SetAttr + lw $t5, 0($fp) + lw $t2, 12($fp) + sw $t2, 4($t5) + #Executing Assign + li $t2, 2 + sw $t2, 16($fp) + #Executing SetAttr + lw $t0, 0($fp) + lw $t2, 16($fp) + sw $t2, 8($t0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -20 + #Return jump + jalr $ra +Main_main: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 48 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing GetAttr + lw $t2, -4($fp) + lw $t0, 4($t2) + sw $t0, 4($fp) + #Executing GetAttr + lw $t5, -4($fp) + lw $t4, 8($t5) + sw $t4, 8($fp) + #Executing Plus Operation + lw $t2, 4($fp) + lw $t0, 8($fp) + add $t4, $t2, $t0 + sw $t4, 0($fp) + #Executing GetAttr + lw $t4, -4($fp) + lw $t2, 4($t4) + sw $t2, 12($fp) + #Executing GetAttr + lw $t5, -4($fp) + lw $t2, 8($t5) + sw $t2, 16($fp) + #Executing Minus Operation + lw $t5, 12($fp) + lw $t0, 16($fp) + sub $t2, $t5, $t0 + sw $t2, 0($fp) + #Executing GetAttr + lw $t4, -4($fp) + lw $t0, 4($t4) + sw $t0, 20($fp) + #Executing GetAttr + lw $t5, -4($fp) + lw $t4, 8($t5) + sw $t4, 24($fp) + #Executing Div Operation + lw $t2, 20($fp) + lw $t5, 24($fp) + div $t2, $t5 + mflo $t2 + sw $t2, 0($fp) + #Executing Assign + lw $t4, -4($fp) + sw $t4, 28($fp) + #Executing typeof + lw $t4, 28($fp) + lw $t4, 0($t4) + sw $t4, 32($fp) + #Executing GetAttr + lw $t2, -4($fp) + lw $t4, 8($t2) + sw $t4, 40($fp) + #Executing GetAttr + lw $t2, -4($fp) + lw $t0, 4($t2) + sw $t0, 44($fp) + #Executing Star Operation + lw $t2, 40($fp) + lw $t5, 44($fp) + mult $t2, $t5 + mflo $t2 + sw $t2, 36($fp) + #Receiving Arg local_Main_main_internal_7 + lw $t4, 28($fp) + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Receiving Arg local_Main_main_internal_9 + lw $t2, 36($fp) + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Executing Dynamic Call + lw $t4, 32($fp) + lw $t5, 16($t4) + jalr $t5 + sw $a1, 0($fp) + addi $sp, $sp, -8 + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -48 + #Return jump + jalr $ra diff --git a/tests/code_gen/test_goto_if_input.txt b/tests/code_gen/test_goto_if_input.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/code_gen/test_goto_if_output.txt b/tests/code_gen/test_goto_if_output.txt new file mode 100644 index 000000000..d8263ee98 --- /dev/null +++ b/tests/code_gen/test_goto_if_output.txt @@ -0,0 +1 @@ +2 \ No newline at end of file diff --git a/tests/code_gen/utils/__init__.py b/tests/code_gen/utils/__init__.py new file mode 100644 index 000000000..90f60fdd8 --- /dev/null +++ b/tests/code_gen/utils/__init__.py @@ -0,0 +1 @@ +from .utils import * \ No newline at end of file diff --git a/tests/code_gen/utils/utils.py b/tests/code_gen/utils/utils.py new file mode 100644 index 000000000..961cf7cbc --- /dev/null +++ b/tests/code_gen/utils/utils.py @@ -0,0 +1,91 @@ +import subprocess +import re + + +COMPILER_TIMEOUT = 'El compilador tarda mucho en responder.' +SPIM_TIMEOUT = 'El spim tarda mucho en responder.' +TEST_MUST_FAIL = 'El test %s debe fallar al compilar' +TEST_MUST_COMPILE = 'El test %s debe compilar' +BAD_ERROR_FORMAT = '''El error no esta en formato: (,) - : + o no se encuentra en la 3ra linea\n\n%s''' +UNEXPECTED_ERROR = 'Se esperaba un %s en (%d, %d). Su error fue un %s en (%d, %d)' +UNEXPECTED_OUTPUT = 'La salida de %s no es la esperada:\n%s\nEsperada:\n%s' + +ERROR_FORMAT = r'^\s*\(\s*(\d+)\s*,\s*(\d+)\s*\)\s*-\s*(\w+)\s*:(.*)$' + +def parse_error(error: str): + merror = re.fullmatch(ERROR_FORMAT, error) + assert merror, BAD_ERROR_FORMAT % error + + return (t(x) for t, x in zip([int, int, str, str], merror.groups())) + + +def first_error(compiler_output: list, errors: list): + line, column, error_type, _ = parse_error(errors[0]) + + oline, ocolumn, oerror_type, _ = parse_error(compiler_output[0]) + + assert line == oline and column == ocolumn and error_type == oerror_type,\ + UNEXPECTED_ERROR % (error_type, line, column, oerror_type, oline, ocolumn) + +def first_error_only_line(compiler_output: list, errors: list): + line, column, error_type, _ = parse_error(errors[0]) + + oline, ocolumn, oerror_type, _ = parse_error(compiler_output[0]) + + assert line == oline and error_type == oerror_type,\ + UNEXPECTED_ERROR % (error_type, line, column, oerror_type, oline, ocolumn) + + +def get_file_name(path: str): + try: + return path[path.rindex('/') + 1:] + except ValueError: + return path + +def compare_errors(compiler_path: str, cool_file_path: str, error_file_path: str, cmp=first_error, timeout=100): + try: + sp = subprocess.run(['bash', compiler_path, cool_file_path], capture_output=True, timeout=timeout) + return_code, output = sp.returncode, sp.stdout.decode() + except subprocess.TimeoutExpired: + assert False, COMPILER_TIMEOUT + + assert return_code == 1, TEST_MUST_FAIL % get_file_name(cool_file_path) + + fd = open(error_file_path, 'r') + errors = fd.read().split('\n') + fd.close() + + # checking the errors of compiler + compiler_output = output.split('\n') + cmp(compiler_output[2:], errors) + +SPIM_HEADER = r'''^SPIM Version .+ of .+ +Copyright .+\, James R\. Larus\. +All Rights Reserved\. +See the file README for a full copyright notice\. +(?:Loaded: .+\n)*''' +def compare_outputs(compiler_path: str, cool_file_path: str, input_file_path: str, output_file_path: str, timeout=100): + try: + sp = subprocess.run(['bash', compiler_path, cool_file_path], capture_output=True, timeout=timeout) + assert sp.returncode == 0, TEST_MUST_COMPILE % get_file_name(cool_file_path) + except subprocess.TimeoutExpired: + assert False, COMPILER_TIMEOUT + + spim_file = cool_file_path[:-2] + 'mips' + + try: + fd = open(input_file_path, 'rb') + sp = subprocess.run(['spim', '-file', spim_file], input=fd.read(), capture_output=True, timeout=timeout) + fd.close() + mo = re.match(SPIM_HEADER, sp.stdout.decode()) + if mo: + output = mo.string[mo.end():] + except subprocess.TimeoutExpired: + assert False, SPIM_TIMEOUT + + fd = open(output_file_path, 'r') + eoutput = fd.read() + fd.close() + + assert output == eoutput, UNEXPECTED_OUTPUT % (spim_file, repr(output), repr(eoutput)) diff --git a/tests/test_1file.py b/tests/test_1file.py index c8c144a7f..ecaf7144c 100644 --- a/tests/test_1file.py +++ b/tests/test_1file.py @@ -5,8 +5,8 @@ # tests_dir = __file__.rpartition('/')[0] + '/semantic/' # tests = [(file) for file in os.listdir(tests_dir) if file.endswith('self4.cl')] -tests_dir = __file__.rpartition("/")[0] + "/parser/" -tests = [(file) for file in os.listdir(tests_dir) if file.endswith("block3.cl")] +tests_dir = __file__.rpartition("/")[0] + "/codegen/" +tests = [(file) for file in os.listdir(tests_dir) if file.endswith("hello_world.cl")] @pytest.mark.semantic From 8b13c65f897cd6c60acb1ed8b001fb62086131c8 Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Tue, 8 Mar 2022 15:00:18 -0500 Subject: [PATCH 125/162] fix: create Bool cosntant in NotNode --- src/code_gen/cil_builder.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index 40a4589d1..9113d892c 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -392,7 +392,7 @@ def visit(self, node, return_var=None): self.register_instruction(ArgNode(instance)) self.register_instruction(StaticCallNode(main_method_name, result)) - #self.register_instruction(ReturnNode(0)) + # self.register_instruction(ReturnNode(0)) self.register_instruction(ExitNode()) self.current_function = None @@ -478,15 +478,18 @@ def visit(self, node, return_var): if self.is_attribute(node.id): self.register_instruction( - SetAttribNode("self", self.to_attr_name(self.current_type.name, node.id), return_var, self.current_type.name) + SetAttribNode( + "self", + self.to_attr_name(self.current_type.name, node.id), + return_var, + self.current_type.name, + ) ) else: self.register_instruction(AssignNode(node.id, return_var)) @visitor.when(cool.CallNode) def visit(self, node, return_var): - # TODO: Pending test .id(,...,) - # TODO: Pending test @.id(,...,) obj_type = self.current_type.name instance = self.define_internal_local() if node.obj: @@ -733,7 +736,12 @@ def visit(self, node, return_var): def visit(self, node, return_var): value = self.define_internal_local() self.visit(node.expr, value) - self.register_instruction(NotNode(return_var, value)) + constant = self.define_internal_local() + self.register_instruction( + StaticCallNode(self.to_function_name("constructor", "Bool"), constant) + ) + self.register_instruction(AssignNode(constant, 1)) + self.register_instruction(MinusNode(return_var, constant, value)) @visitor.when(cool.NegNode) def visit(self, node, return_var): From 800f859ff84e364fc6065f1986f62186d5e78914 Mon Sep 17 00:00:00 2001 From: smartos99 Date: Tue, 8 Mar 2022 15:14:46 -0500 Subject: [PATCH 126/162] while and comparisons work --- src/code_gen/mips_builder.py | 111 ++++++++++++++++++++++++++++++----- src/code_gen/mips_nodes.py | 22 +++++-- 2 files changed, 114 insertions(+), 19 deletions(-) diff --git a/src/code_gen/mips_builder.py b/src/code_gen/mips_builder.py index f1a0abc80..92c65ff75 100644 --- a/src/code_gen/mips_builder.py +++ b/src/code_gen/mips_builder.py @@ -124,16 +124,6 @@ def __init__(self): self.attr_offset = {} self.memo = MemoryManager() self.pushed_args = 0 - - def print(self,x): - self.memo.save() - self.register_instruction(mips.CommentNode,"------------Printeooooo") - reg = self.memo.get_unused_reg() - self.register_instruction(mips.LoadInmediate,reg,x) - self.register_instruction(mips.MoveNode,a0,reg) - self.register_instruction(mips.LoadInmediate,v0,4) - self.register_instruction(mips.SyscallNode) - self.register_instruction(mips.CommentNode,"------------Fiiiin") def get_offset(self,x): @@ -205,6 +195,7 @@ def generate_str_length(self): self.register_instruction(mips.Jump, ra) self.text.append(self.current_procedure) + self.memo.clean() def generate_copy(self): #copies from t1 to t6 a0 bytes @@ -380,6 +371,7 @@ def visit(self, node): self.register_instruction(mips.LoadWordNode, reg, LENGTH_ATTR_OFFSET, reg) dest_offset = self.get_offset(node.dest) self.register_instruction(mips.StoreWordNode, reg,dest_offset, fp) + self.memo.clean() #All return value is saved in register a1 @@ -415,6 +407,19 @@ def visit(self,node): self.register_instruction(mips.CommentNode,"Executing Goto") self.register_instruction(mips.Jump,node.label) + @visitor.when(cil.GotoIfNode) + def visit(self,node): + self.memo.save() + + reg = self.memo.get_unused_reg() + cond_offset = self.get_offset(node.condition) + + self.register_instruction(mips.LoadWordNode,reg,cond_offset,fp) + + self.register_instruction(mips.BranchOnNotEqZero,reg,node.label) + self.memo.clean() + + @visitor.when(cil.AllocateNode) @@ -674,6 +679,84 @@ def visit(self,node): self.memo.clean() + @visitor.when(cil.LessNode) + def visit(self,node): + self.memo.save() + r_left = self.memo.get_unused_reg() + r_right = self.memo.get_unused_reg() + r_dest = self.memo.get_unused_reg() + + if isinstance(node.left,int): + self.register_instruction(mips.LoadInmediate,r_left,node.left) + else: + left_off = self.get_offset(node.left) + self.register_instruction(mips.LoadWordNode,r_left,left_off,fp) + + if isinstance(node.right,int): + self.register_instruction(mips.LoadInmediate,r_right,node.right) + else: + right_off = self.get_offset(node.right) + self.register_instruction(mips.LoadWordNode,r_right,right_off,fp) + + self.register_instruction(mips.SetOnLessThan,r_dest,r_left,r_right) + + dest_off = self.get_offset(node.dest) + self.register_instruction(mips.StoreWordNode,r_dest,dest_off,fp) + + self.memo.clean() + + @visitor.when(cil.LessEqualNode) + def visit(self,node): + self.memo.save() + r_left = self.memo.get_unused_reg() + r_right = self.memo.get_unused_reg() + r_dest = self.memo.get_unused_reg() + + if isinstance(node.left,int): + self.register_instruction(mips.LoadInmediate,r_left,node.left) + else: + left_off = self.get_offset(node.left) + self.register_instruction(mips.LoadWordNode,r_left,left_off,fp) + + if isinstance(node.right,int): + self.register_instruction(mips.LoadInmediate,r_right,node.right) + else: + right_off = self.get_offset(node.right) + self.register_instruction(mips.LoadWordNode,r_right,right_off,fp) + + self.register_instruction(mips.SetOnLessOrEq,r_dest,r_left,r_right) + + dest_off = self.get_offset(node.dest) + self.register_instruction(mips.StoreWordNode,r_dest,dest_off,fp) + + self.memo.clean() + + @visitor.when(cil.EqualNode) + def visit(self,node): + self.memo.save() + r_left = self.memo.get_unused_reg() + r_right = self.memo.get_unused_reg() + r_dest = self.memo.get_unused_reg() + + if isinstance(node.left,int): + self.register_instruction(mips.LoadInmediate,r_left,node.left) + else: + left_off = self.get_offset(node.left) + self.register_instruction(mips.LoadWordNode,r_left,left_off,fp) + + if isinstance(node.right,int): + self.register_instruction(mips.LoadInmediate,r_right,node.right) + else: + right_off = self.get_offset(node.right) + self.register_instruction(mips.LoadWordNode,r_right,right_off,fp) + + self.register_instruction(mips.SetEq,r_dest,r_left,r_right) + + dest_off = self.get_offset(node.dest) + self.register_instruction(mips.StoreWordNode,r_dest,dest_off,fp) + + self.memo.clean() + #READSTRING @visitor.when(cil.ReadNode) def visit(self,node): @@ -778,7 +861,9 @@ def visit(self,node): self.register_instruction(mips.LoadInmediate,v0,SYSCALL_EXIT) self.register_instruction(mips.SyscallNode) - + @visitor.when(cil.LabelNode) + def visit(self,node): + self.register_instruction(mips.Label,node.name) @visitor.when(cil.CopyNode) def visit(self,node): @@ -805,9 +890,7 @@ def visit(self,node): def visit(self,node): pass - @visitor.when(cil.GotoIfNode) - def visit(self,node): - pass + @visitor.when(cil.LocalNode) #No hace falta def visit(self,node): diff --git a/src/code_gen/mips_nodes.py b/src/code_gen/mips_nodes.py index 22d36ac8c..20217547a 100644 --- a/src/code_gen/mips_nodes.py +++ b/src/code_gen/mips_nodes.py @@ -198,9 +198,18 @@ class BranchOnLessOrEqNode(ConditionalBranch): def __str__(self): return f"ble {self.c1}, {self.c2}, {self.jump}" +class BranchOnNotEqZero(InstructionNode): + def __init__(self,reg,label): + self.reg = reg + self.label = label + + def __str__(self): + return f'bnez {self.reg}, {self.label}' + + class ComparisonNode(InstructionNode): - def __init__(self, m1, m2, dest): + def __init__(self, dest,m1, m2 ): self.m1 = m1 self.m2 = m2 self.destination = dest @@ -208,14 +217,17 @@ def __init__(self, m1, m2, dest): class SetOnLessThan(ComparisonNode): def __str__(self): - return f"slt {self.dest}, {self.m1}, {self.m2}" + return f"slt {self.destination}, {self.m1}, {self.m2}" -class SetOnLessThanInmediate(ComparisonNode): +class SetOnLessOrEq(ComparisonNode): def __str__(self): - return f"slt {self.dest}, {self.m1}, {self.m2}" - + return f"sle {self.destination}, {self.m1}, {self.m2}" +class SetEq(ComparisonNode): + def __str__(self): + return f"seq {self.destination}, {self.m1}, {self.m2}" + class UnconditionalJumpNode(InstructionNode): def __init__(self, jump): self.jump = jump From e1b86288e4f30d9647c893d0891808a154fed106 Mon Sep 17 00:00:00 2001 From: smartos99 Date: Tue, 8 Mar 2022 19:12:35 -0500 Subject: [PATCH 127/162] String Methods work --- src/cmp/cil.py | 8 +- src/code_gen/mips_builder.py | 162 ++++++++++++++++++++++++++++++----- 2 files changed, 146 insertions(+), 24 deletions(-) diff --git a/src/cmp/cil.py b/src/cmp/cil.py index f9f39727e..2b1723595 100644 --- a/src/cmp/cil.py +++ b/src/cmp/cil.py @@ -196,10 +196,10 @@ def __init__(self, dest, left, right): class SubstringNode(InstructionNode): - def __init__(self, dest, source, idx, length): + def __init__(self, dest, source, index, length): self.dest = dest self.source = source - self.id = idx + self.index = index self.length = length @@ -330,7 +330,7 @@ def visit(self, node): @visitor.when(IntComplementNode) def visit(self, node): - return f"{node.dest} = ~ {node.expr}" + return f"{node.dest} = ~ {node.source}" @visitor.when(LabelNode) def visit(self, node): @@ -418,7 +418,7 @@ def visit(self, node): @visitor.when(SubstringNode) def visit(self, node): - return f"{node.dest} = SUBSTRING {node.source} {node.id} {node.length}" + return f"{node.dest} = SUBSTRING {node.source} {node.index} {node.length}" @visitor.when(DefaultValueNode) def visit(self, node): diff --git a/src/code_gen/mips_builder.py b/src/code_gen/mips_builder.py index 92c65ff75..d9091d27c 100644 --- a/src/code_gen/mips_builder.py +++ b/src/code_gen/mips_builder.py @@ -664,13 +664,14 @@ def visit(self,node): @visitor.when(cil.IntComplementNode) def visit(self,node): - self.memory_manager.save() + self.register_instruction(mips.CommentNode,"Executing Int Complement") + self.memo.save() source_offset = self.get_offset(node.source) dest_offset = self.get_offset(node.dest) - reg1 = self.memo.get_unused_register() - reg2 = self.memo.get_unused_register() + reg1 = self.memo.get_unused_reg() + reg2 = self.memo.get_unused_reg() self.register_instruction(mips.LoadWordNode,reg1,source_offset,fp) self.register_instruction(mips.NotNode,reg2,reg1) @@ -681,6 +682,7 @@ def visit(self,node): @visitor.when(cil.LessNode) def visit(self,node): + self.register_instruction(mips.CommentNode,"Executing Less Operation") self.memo.save() r_left = self.memo.get_unused_reg() r_right = self.memo.get_unused_reg() @@ -707,6 +709,7 @@ def visit(self,node): @visitor.when(cil.LessEqualNode) def visit(self,node): + self.register_instruction(mips.CommentNode,"Executing Less Equal Operation") self.memo.save() r_left = self.memo.get_unused_reg() r_right = self.memo.get_unused_reg() @@ -733,6 +736,7 @@ def visit(self,node): @visitor.when(cil.EqualNode) def visit(self,node): + self.register_instruction(mips.CommentNode,"Executing Equal Operation") self.memo.save() r_left = self.memo.get_unused_reg() r_right = self.memo.get_unused_reg() @@ -757,6 +761,137 @@ def visit(self,node): self.memo.clean() + @visitor.when(cil.SubstringNode) + def visit(self, node): + self.register_instruction(mips.CommentNode,"Executing Substring") + + #self.detect_substring_out_of_range(node.idx.offset, node.length.offset, node.source.offset) + + #allocating new char array + if isinstance(node.length,int): + self.register_instruction(mips.LoadInmediate,s0,node.length) + else: + length_off = self.get_offset(node.length) + self.register_instruction(mips.LoadWordNode, s0, length_off, fp)#salvando el length del substr + self.register_instruction(mips.MoveNode, a0, s0) + self.register_instruction(mips.AddiNode, a0, a0, 1) + self.register_instruction(mips.LoadInmediate, v0, SYSCALL_SBRK) + self.register_instruction(mips.SyscallNode) + self.register_instruction(mips.MoveNode, t6, v0)#saving the dest char arr in t6 + + #loading ref to char array of source string + self.register_instruction(mips.CommentNode,"Loading reference to char array of source string") + + source_off = self.get_offset(node.source) + self.register_instruction(mips.LoadWordNode, t7, source_off, fp) + self.register_instruction(mips.LoadWordNode, t7, CHARS_ATTR_OFFSET, t7) + + if isinstance(node.index,int): + self.register_instruction(mips.LoadInmediate,s2,node.index) + else: + index_offset = self.get_offset(node.index) + self.register_instruction(mips.LoadWordNode,s2,index_offset,fp) + + self.register_instruction(mips.AddNode, t7, t7, s2)#saving the source char arr in t7 + + self.register_instruction(mips.MoveNode, s1, t6) + + #this copies from t7 to t6 a0 bytes + self.register_instruction(mips.CommentNode,"Copying bytes from one char array to another") + self.register_instruction(mips.MoveNode, a0, s0) + self.register_instruction(mips.JumpAndLink, COPY) + + self.register_instruction(mips.CommentNode,"Null-terminating the string") + self.register_instruction(mips.StoreByteNode, zero, 0, t0) + + self.register_instruction(mips.CommentNode,"Allocating new String instance") + dest_offset = self.get_offset(node.dest) + _size = STRING_SIZE + self.register_instruction(mips.LoadInmediate,v0,SYSCALL_SBRK) + self.register_instruction(mips.LoadInmediate,a0,_size) + self.register_instruction(mips.SyscallNode) + + self.register_instruction(mips.StoreWordNode,v0,dest_offset,fp) + reg = self.memo.get_unused_reg() + self.register_instruction(mips.LoadAddress,reg,STRING) + self.register_instruction(mips.StoreWordNode,reg,0,v0) + + + #storing string length + self.register_instruction(mips.CommentNode,"Storing length and reference to char array") + if isinstance(node.length,int): + self.register_instruction(mips.LoadInmediate,s0,node.length) + else: + length_off = self.get_offset(node.length) + self.register_instruction(mips.LoadWordNode, s0, length_off, fp) + self.register_instruction(mips.StoreWordNode, s0, LENGTH_ATTR_OFFSET, v0) + + #storing string chars ref + self.register_instruction(mips.StoreWordNode, s1, CHARS_ATTR_OFFSET, v0) + + @visitor.when(cil.ConcatNode) + def visit(self, node): + self.memo.save() + left_offset = self.get_offset(node.left) + right_offset = self.get_offset(node.right) + #cargar los length + self.register_instruction(mips.CommentNode,"Loading length") + self.register_instruction(mips.LoadWordNode, s1, left_offset, fp) + self.register_instruction(mips.LoadWordNode, s1, LENGTH_ATTR_OFFSET, s1) + self.register_instruction(mips.LoadWordNode, s2, right_offset, fp) + self.register_instruction(mips.LoadWordNode, s2, LENGTH_ATTR_OFFSET, s2) + + reg1 = self.memo.get_unused_reg() #sum of lengths + self.register_instruction(mips.AddNode, reg1, s1, s2) + + #crear el nuevo array de bytes + self.register_instruction(mips.CommentNode,"Allocating new char array") + self.register_instruction(mips.MoveNode, a0, reg1) + self.register_instruction(mips.AddiNode, a0, a0, 1) + self.register_instruction(mips.LoadInmediate, v0, SYSCALL_SBRK) + self.register_instruction(mips.SyscallNode) + self.register_instruction(mips.MoveNode, t6, v0)#saving the dest char arr in t6 + + reg2 = self.memo.get_unused_reg() + self.register_instruction(mips.MoveNode, reg2, v0) + + self.register_instruction(mips.CommentNode,"Copying bytes from first string") + self.register_instruction(mips.LoadWordNode, t7, left_offset, fp) + self.register_instruction(mips.LoadWordNode, t7, CHARS_ATTR_OFFSET, t7) + self.register_instruction(mips.MoveNode, a0, s1) + self.register_instruction(mips.JumpAndLink, COPY) + + self.register_instruction(mips.CommentNode,"Copying bytes from second string") + self.register_instruction(mips.LoadWordNode, t7, right_offset, fp) + self.register_instruction(mips.LoadWordNode, t7, CHARS_ATTR_OFFSET, t7) + self.register_instruction(mips.MoveNode, a0, s2) + self.register_instruction(mips.JumpAndLink, COPY) + + self.register_instruction(mips.CommentNode,"Null-terminating the string") + self.register_instruction(mips.StoreByteNode, zero, 0, t6) + + self.register_instruction(mips.CommentNode,"Allocating new String instance") + dest_offset = self.get_offset(node.dest) + _size = STRING_SIZE + self.register_instruction(mips.LoadInmediate,v0,SYSCALL_SBRK) + self.register_instruction(mips.LoadInmediate,a0,_size) + self.register_instruction(mips.SyscallNode) + + self.register_instruction(mips.StoreWordNode,v0,dest_offset,fp) + reg3 = self.memo.get_unused_reg() + self.register_instruction(mips.LoadAddress,reg3,STRING) + self.register_instruction(mips.StoreWordNode,reg3,0,v0) + + #storing string length + self.register_instruction(mips.CommentNode,"Storing length and reference to char array") + self.register_instruction(mips.StoreWordNode, reg1, LENGTH_ATTR_OFFSET, v0) + + #storing string chars ref + self.register_instruction(mips.StoreWordNode, reg2, CHARS_ATTR_OFFSET, v0) + + self.memo.clean() + + #READSTRING @visitor.when(cil.ReadNode) def visit(self,node): @@ -820,6 +955,10 @@ def visit(self,node): #storing string chars ref self.register_instruction(mips.StoreWordNode, reg3, CHARS_ATTR_OFFSET, v0) self.memo.clean() + + + + @visitor.when(cil.PrintStrNode) def visit(self,node): @@ -874,23 +1013,6 @@ def visit(self,node): pass - @visitor.when(cil.ToStrNode) - def visit(self,node): - pass - - - @visitor.when(cil.ConcatNode) - def visit(self,node): - pass - @visitor.when(cil.SubstringNode) - def visit(self,node): - pass - - @visitor.when(cil.PrefixNode) - def visit(self,node): - pass - - @visitor.when(cil.LocalNode) #No hace falta def visit(self,node): From f38a82f9c414f310214ce0f218fb50dd34314769 Mon Sep 17 00:00:00 2001 From: smartos99 Date: Tue, 8 Mar 2022 19:13:30 -0500 Subject: [PATCH 128/162] Add tests --- customized_tests/code_gen/code_gen.py | 17 - customized_tests/code_gen/test_goto_if.cl | 13 - .../code_gen/test_goto_if_output.txt | 1 - customized_tests/code_gen/utils/__init__.py | 1 - customized_tests/code_gen/utils/utils.py | 91 -- src/code_gen/cil_builder.py | 86 +- src/main.py | 27 +- tests/code_gen.py | 2 +- tests/code_gen/comparison.cl | 3 +- tests/code_gen/comparison.mips | 262 +++--- tests/code_gen/comparison_output.txt | 2 +- tests/code_gen/hello_world.mips | 138 +-- tests/code_gen/point.mips | 214 ++--- tests/code_gen/read_string.mips | 200 ++--- tests/code_gen/string_methods.cl | 13 + tests/code_gen/string_methods.mips | 807 ++++++++++++++++++ .../code_gen/string_methods_input.txt | 0 tests/code_gen/string_methods_output.txt | 1 + tests/code_gen/test_goto_if.mips | 278 +++--- tests/code_gen/unary_nodes.cl | 11 + tests/code_gen/unary_nodes.mips | 745 ++++++++++++++++ tests/code_gen/unary_nodes_input.txt | 0 tests/code_gen/unary_nodes_output.txt | 1 + tests/code_gen/while.cl | 14 + .../code_gen/while.mips | 340 ++++---- tests/code_gen/while_input.txt | 0 tests/code_gen/while_output.txt | 3 + 27 files changed, 2405 insertions(+), 865 deletions(-) delete mode 100644 customized_tests/code_gen/code_gen.py delete mode 100644 customized_tests/code_gen/test_goto_if.cl delete mode 100644 customized_tests/code_gen/test_goto_if_output.txt delete mode 100644 customized_tests/code_gen/utils/__init__.py delete mode 100644 customized_tests/code_gen/utils/utils.py create mode 100644 tests/code_gen/string_methods.cl create mode 100644 tests/code_gen/string_methods.mips rename customized_tests/code_gen/test_goto_if_input.txt => tests/code_gen/string_methods_input.txt (100%) create mode 100644 tests/code_gen/string_methods_output.txt create mode 100644 tests/code_gen/unary_nodes.cl create mode 100644 tests/code_gen/unary_nodes.mips create mode 100644 tests/code_gen/unary_nodes_input.txt create mode 100644 tests/code_gen/unary_nodes_output.txt create mode 100644 tests/code_gen/while.cl rename customized_tests/code_gen/test_goto_if.mips => tests/code_gen/while.mips (80%) create mode 100644 tests/code_gen/while_input.txt create mode 100644 tests/code_gen/while_output.txt diff --git a/customized_tests/code_gen/code_gen.py b/customized_tests/code_gen/code_gen.py deleted file mode 100644 index a7eb0c3ca..000000000 --- a/customized_tests/code_gen/code_gen.py +++ /dev/null @@ -1,17 +0,0 @@ -import pytest -import os -from utils.utils import compare_outputs - -tests_dir = __file__.rpartition('/')[0] + '/' -tests = [(file) for file in os.listdir(tests_dir) if file.endswith('.cl')] - -# @pytest.mark.lexer -# @pytest.mark.parser -# @pytest.mark.semantic -@pytest.mark.codegen -@pytest.mark.ok -@pytest.mark.run(order=4) -@pytest.mark.parametrize("cool_file", tests) -def test_codegen(compiler_path, cool_file): - compare_outputs(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_input.txt',\ - tests_dir + cool_file[:-3] + '_output.txt') \ No newline at end of file diff --git a/customized_tests/code_gen/test_goto_if.cl b/customized_tests/code_gen/test_goto_if.cl deleted file mode 100644 index 57e2f1f25..000000000 --- a/customized_tests/code_gen/test_goto_if.cl +++ /dev/null @@ -1,13 +0,0 @@ -class Main inherits IO{ - a : Int <- 1; - b : Int <- 2; - main (): Object { - { - a + b; - a - b; - a / b; - out_int(b * a); - } - - }; -}; \ No newline at end of file diff --git a/customized_tests/code_gen/test_goto_if_output.txt b/customized_tests/code_gen/test_goto_if_output.txt deleted file mode 100644 index d8263ee98..000000000 --- a/customized_tests/code_gen/test_goto_if_output.txt +++ /dev/null @@ -1 +0,0 @@ -2 \ No newline at end of file diff --git a/customized_tests/code_gen/utils/__init__.py b/customized_tests/code_gen/utils/__init__.py deleted file mode 100644 index 90f60fdd8..000000000 --- a/customized_tests/code_gen/utils/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .utils import * \ No newline at end of file diff --git a/customized_tests/code_gen/utils/utils.py b/customized_tests/code_gen/utils/utils.py deleted file mode 100644 index 961cf7cbc..000000000 --- a/customized_tests/code_gen/utils/utils.py +++ /dev/null @@ -1,91 +0,0 @@ -import subprocess -import re - - -COMPILER_TIMEOUT = 'El compilador tarda mucho en responder.' -SPIM_TIMEOUT = 'El spim tarda mucho en responder.' -TEST_MUST_FAIL = 'El test %s debe fallar al compilar' -TEST_MUST_COMPILE = 'El test %s debe compilar' -BAD_ERROR_FORMAT = '''El error no esta en formato: (,) - : - o no se encuentra en la 3ra linea\n\n%s''' -UNEXPECTED_ERROR = 'Se esperaba un %s en (%d, %d). Su error fue un %s en (%d, %d)' -UNEXPECTED_OUTPUT = 'La salida de %s no es la esperada:\n%s\nEsperada:\n%s' - -ERROR_FORMAT = r'^\s*\(\s*(\d+)\s*,\s*(\d+)\s*\)\s*-\s*(\w+)\s*:(.*)$' - -def parse_error(error: str): - merror = re.fullmatch(ERROR_FORMAT, error) - assert merror, BAD_ERROR_FORMAT % error - - return (t(x) for t, x in zip([int, int, str, str], merror.groups())) - - -def first_error(compiler_output: list, errors: list): - line, column, error_type, _ = parse_error(errors[0]) - - oline, ocolumn, oerror_type, _ = parse_error(compiler_output[0]) - - assert line == oline and column == ocolumn and error_type == oerror_type,\ - UNEXPECTED_ERROR % (error_type, line, column, oerror_type, oline, ocolumn) - -def first_error_only_line(compiler_output: list, errors: list): - line, column, error_type, _ = parse_error(errors[0]) - - oline, ocolumn, oerror_type, _ = parse_error(compiler_output[0]) - - assert line == oline and error_type == oerror_type,\ - UNEXPECTED_ERROR % (error_type, line, column, oerror_type, oline, ocolumn) - - -def get_file_name(path: str): - try: - return path[path.rindex('/') + 1:] - except ValueError: - return path - -def compare_errors(compiler_path: str, cool_file_path: str, error_file_path: str, cmp=first_error, timeout=100): - try: - sp = subprocess.run(['bash', compiler_path, cool_file_path], capture_output=True, timeout=timeout) - return_code, output = sp.returncode, sp.stdout.decode() - except subprocess.TimeoutExpired: - assert False, COMPILER_TIMEOUT - - assert return_code == 1, TEST_MUST_FAIL % get_file_name(cool_file_path) - - fd = open(error_file_path, 'r') - errors = fd.read().split('\n') - fd.close() - - # checking the errors of compiler - compiler_output = output.split('\n') - cmp(compiler_output[2:], errors) - -SPIM_HEADER = r'''^SPIM Version .+ of .+ -Copyright .+\, James R\. Larus\. -All Rights Reserved\. -See the file README for a full copyright notice\. -(?:Loaded: .+\n)*''' -def compare_outputs(compiler_path: str, cool_file_path: str, input_file_path: str, output_file_path: str, timeout=100): - try: - sp = subprocess.run(['bash', compiler_path, cool_file_path], capture_output=True, timeout=timeout) - assert sp.returncode == 0, TEST_MUST_COMPILE % get_file_name(cool_file_path) - except subprocess.TimeoutExpired: - assert False, COMPILER_TIMEOUT - - spim_file = cool_file_path[:-2] + 'mips' - - try: - fd = open(input_file_path, 'rb') - sp = subprocess.run(['spim', '-file', spim_file], input=fd.read(), capture_output=True, timeout=timeout) - fd.close() - mo = re.match(SPIM_HEADER, sp.stdout.decode()) - if mo: - output = mo.string[mo.end():] - except subprocess.TimeoutExpired: - assert False, SPIM_TIMEOUT - - fd = open(output_file_path, 'r') - eoutput = fd.read() - fd.close() - - assert output == eoutput, UNEXPECTED_OUTPUT % (spim_file, repr(output), repr(eoutput)) diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index 9113d892c..a2cb95feb 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -600,49 +600,49 @@ def visit(self, node, return_var=None): else: self.register_instruction(DefaultValueNode(local, node.type)) - @visitor.when(cool.CaseNode) - def visit(self, node, return_var=None): - def least_type(type_set): - solve = self.context.get_type(type_set[0]) - for item in type_set[1:]: - typex = self.context.get_type(item) - solve = find_least_type(solve, typex) - - while solve is not None: - if type_b.conforms_to(solve): - return solve - solve = solve.parent - - return None - return solve.name if not solve else "Object" - - expr_value = self.define_internal_local() - self.visit(node.expr, expr_value) - - types = [case_item.type for case_item in node.case_items] - types.append(node.expr.static_type.name) - - _least_type = least_type(types) - print("-----------Least TYpE:", _least_type) - asserted_item = None - for case_item in node.case_items: - if case_item.type == _least_type: - asserted_item = case_item - break - - if not asserted_item: - self.register_instruction( - StaticCallNode( - self.to_function_name("abort", "Object"), - return_var, - ) - ) - return - - self.localvars.append(LocalNode(asserted_item.id)) - self.register_instruction(AssignNode(asserted_item.id, expr_value)) - - self.visit(asserted_item.expr, return_var) + #@visitor.when(cool.CaseNode) + #def visit(self, node, return_var=None): + # def least_type(type_set): + # solve = self.context.get_type(type_set[0]) + # for item in type_set[1:]: + # typex = self.context.get_type(item) + # solve = find_least_type(solve, typex) + + # while solve is not None: + # if type_b.conforms_to(solve): + # return solve + # solve = solve.parent + + # return None + # return solve.name if not solve else "Object" + + # expr_value = self.define_internal_local() + # self.visit(node.expr, expr_value) + + # types = [case_item.type for case_item in node.case_items] + # types.append(node.expr.static_type.name) + + # _least_type = least_type(types) + # print("-----------Least TYpE:", _least_type) + # asserted_item = None + # for case_item in node.case_items: + # if case_item.type == _least_type: + # asserted_item = case_item + # break + + # if not asserted_item: + # self.register_instruction( + # StaticCallNode( + # self.to_function_name("abort", "Object"), + # return_var, + # ) + # ) + # return + + # self.localvars.append(LocalNode(asserted_item.id)) + # self.register_instruction(AssignNode(asserted_item.id, expr_value)) + + # self.visit(asserted_item.expr, return_var) @visitor.when(cool.CaseItemNode) def visit(self, node, return_var=None): diff --git a/src/main.py b/src/main.py index b6cf18fbf..d3190f10c 100644 --- a/src/main.py +++ b/src/main.py @@ -92,21 +92,28 @@ def pipeline(input_file: Path, output_file: Path = None): tree = formatter.visit(cil_ast) print(tree) - # cil_to_mips_visitor = MIPSBuilder() - # mips_ast = cil_to_mips_visitor.visit(cil_ast) + cil_to_mips_visitor = MIPSBuilder() + mips_ast = cil_to_mips_visitor.visit(cil_ast) - # mips_writer = MIPSWriter() - # output = mips_writer(mips_ast) + mips_writer = MIPSWriter() + output = mips_writer.visit(mips_ast) - # output = '\n'.join(mips_writer.output) + output = '\n'.join(mips_writer.output) - # if output_file is None: - # output_file = input.with_suffix(".mips") + if output_file is None: + output_file = input_file.with_suffix(".mips") - # output_file.write_text(output) + with output_file.open("w") as file: + print(output, file=file) + + #with open(f'{input_file[:-3]}.mips','w') as f: + # f.write(f'{output}') + #output_file.write_text(output) if __name__ == "__main__": - # input_file = Path("/home/sandra/Desktop/FinalProjects/Compiler/cool-compiler-2021/customized_tests/test_hello_world.cl") - # pipeline(input_file) + #input_file = Path("/home/sandra/Desktop/FinalProjects/Compiler/cool-compiler-2021/customized_tests/code_gen/test_goto_if.cl") + #output_file = Path("/home/sandra/Desktop/FinalProjects/Compiler/cool-compiler-2021/customized_tests/test_hello_world.mips") + + #pipeline() typer.run(pipeline) diff --git a/tests/code_gen.py b/tests/code_gen.py index 1fb167ad3..eee6e10e3 100644 --- a/tests/code_gen.py +++ b/tests/code_gen.py @@ -4,7 +4,7 @@ tests_dir = __file__.rpartition('/')[0] + '/code_gen/' -tests = [(file) for file in os.listdir(tests_dir) if file.endswith('.cl')] +tests = [(file) for file in os.listdir(tests_dir) if file.endswith('unary_nodes.cl')] # @pytest.mark.lexer # @pytest.mark.parser diff --git a/tests/code_gen/comparison.cl b/tests/code_gen/comparison.cl index 0b8081562..26635d9db 100644 --- a/tests/code_gen/comparison.cl +++ b/tests/code_gen/comparison.cl @@ -4,10 +4,11 @@ class Main inherits IO{ b : Int; main (): Object { { + a < b; a <= b; a = b; - out_string("Default value for Int should be 0"); + out_string(if a <= b then "a<=b" else "a>b" fi); } }; }; diff --git a/tests/code_gen/comparison.mips b/tests/code_gen/comparison.mips index 52a87a0d3..902e18b54 100644 --- a/tests/code_gen/comparison.mips +++ b/tests/code_gen/comparison.mips @@ -22,21 +22,22 @@ dispatch_on_void : .asciiz, "Dispatch on void" division_by_zero : .asciiz, "Division by zero" substr_out_of_range : .asciiz, "Substring out of range" heap_overflow : .asciiz, "Heap overflow" -string_1 : .asciiz, "Default value for Int should be 0" +string_1 : .asciiz, "a>b" +string_2 : .asciiz, "a<=b" .text .globl main length: - li $t4, 0 + li $t1, 0 length_loop: - lb $t1, 0($a0) - beq $zero, $t1, length_end - add $t4, $t4, 1 + lb $t3, 0($a0) + beq $zero, $t3, length_end + add $t1, $t1, 1 add $a0, $a0, 1 j length_loop length_end: - move $a0 $t4 + move $a0 $t1 j $ra copy: copy_loop: @@ -50,7 +51,7 @@ copy: copy_end: j $ra Object_abort: - move $t9 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -59,7 +60,7 @@ Object_abort: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing RuntimeError @@ -71,7 +72,7 @@ Object_abort: li $v0, 10 syscall Object_copy: - move $t2 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -80,7 +81,7 @@ Object_copy: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -96,7 +97,7 @@ Object_copy: #Return jump jalr $ra Object_type_name: - move $t0 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -105,7 +106,7 @@ Object_type_name: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -121,7 +122,7 @@ Object_type_name: #Return jump jalr $ra IO_out_string: - move $t5 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -130,7 +131,7 @@ IO_out_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t5, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintStringNode @@ -151,7 +152,7 @@ IO_out_string: #Return jump jalr $ra IO_out_int: - move $t2 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -160,7 +161,7 @@ IO_out_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintIntNode @@ -180,7 +181,7 @@ IO_out_int: #Return jump jalr $ra IO_in_string: - move $t2 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -189,7 +190,7 @@ IO_in_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #ReadStrNode @@ -206,8 +207,8 @@ IO_in_string: li $v0, 9 syscall move $t6 $v0 - move $t9 $v0 - move $t2 $a0 + move $t2 $v0 + move $t0 $a0 #Copying bytes from one char array to another jal copy #Null-terminating the string @@ -217,11 +218,11 @@ IO_in_string: li $a0, 12 syscall sw $v0, 0($fp) - la $t0, String - sw $t0, 0($v0) + la $t3, String + sw $t3, 0($v0) #Storing length and reference to char array - sw $t2, 4($v0) - sw $t9, 8($v0) + sw $t0, 4($v0) + sw $t2, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -235,7 +236,7 @@ IO_in_string: #Return jump jalr $ra IO_in_int: - move $t2 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -244,7 +245,7 @@ IO_in_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #ReadStrNode @@ -262,7 +263,7 @@ IO_in_int: syscall move $t6 $v0 move $t5 $v0 - move $t9 $a0 + move $t4 $a0 #Copying bytes from one char array to another jal copy #Null-terminating the string @@ -272,10 +273,10 @@ IO_in_int: li $a0, 12 syscall sw $v0, 0($fp) - la $t3, String - sw $t3, 0($v0) + la $t0, String + sw $t0, 0($v0) #Storing length and reference to char array - sw $t9, 4($v0) + sw $t4, 4($v0) sw $t5, 8($v0) #Executing Return lw $a1, 0($fp) @@ -290,7 +291,7 @@ IO_in_int: #Return jump jalr $ra String_length: - move $t5 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -299,13 +300,13 @@ String_length: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t5, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Length - lw $t2, -4($fp) - lw $t2, 4($t2) - sw $t2, 0($fp) + lw $t4, -4($fp) + lw $t4, 4($t4) + sw $t4, 0($fp) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -319,7 +320,7 @@ String_length: #Return jump jalr $ra String_concat: - move $t3 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -328,7 +329,7 @@ String_concat: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -344,7 +345,7 @@ String_concat: #Return jump jalr $ra String_substr: - move $t5 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -353,7 +354,7 @@ String_substr: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t5, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -369,7 +370,7 @@ String_substr: #Return jump jalr $ra Object_constructor: - move $t0 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -378,7 +379,7 @@ Object_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -386,8 +387,8 @@ Object_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t3, Object - sw $t3, 0($v0) + la $t5, Object + sw $t5, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -401,7 +402,7 @@ Object_constructor: #Return jump jalr $ra IO_constructor: - move $t9 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -410,7 +411,7 @@ IO_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -418,8 +419,8 @@ IO_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t5, IO - sw $t5, 0($v0) + la $t9, IO + sw $t9, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -433,7 +434,7 @@ IO_constructor: #Return jump jalr $ra Int_constructor: - move $t9 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -442,7 +443,7 @@ Int_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -450,8 +451,8 @@ Int_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t3, Int - sw $t3, 0($v0) + la $t1, Int + sw $t1, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -465,7 +466,7 @@ Int_constructor: #Return jump jalr $ra Bool_constructor: - move $t9 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -474,7 +475,7 @@ Bool_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -497,7 +498,7 @@ Bool_constructor: #Return jump jalr $ra String_constructor: - move $t9 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -506,7 +507,7 @@ String_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -514,8 +515,8 @@ String_constructor: li $a0, 12 syscall sw $v0, 0($fp) - la $t5, String - sw $t5, 0($v0) + la $t1, String + sw $t1, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -529,7 +530,7 @@ String_constructor: #Return jump jalr $ra main: - move $t0 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -538,7 +539,7 @@ main: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Static Call @@ -546,8 +547,8 @@ main: sw $a1, 0($fp) addi $sp, $sp, 0 #Receiving Arg local_main_internal_0 - lw $t9, 0($fp) - sw $t9, 0($sp) + lw $t3, 0($fp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing Static Call jal Main_main @@ -556,7 +557,7 @@ main: li $v0, 10 syscall Main_constructor: - move $t3 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -565,7 +566,7 @@ Main_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -576,19 +577,19 @@ Main_constructor: la $t9, Main sw $t9, 0($v0) #Executing DefaultValue - li $t3, 0 - sw $t3, 4($fp) + li $t2, 0 + sw $t2, 4($fp) #Executing SetAttr - lw $t0, 0($fp) - lw $t5, 4($fp) - sw $t5, 4($t0) + lw $t9, 0($fp) + lw $t3, 4($fp) + sw $t3, 4($t9) #Executing DefaultValue li $t5, 0 sw $t5, 8($fp) #Executing SetAttr - lw $t5, 0($fp) - lw $t9, 8($fp) - sw $t9, 8($t5) + lw $t2, 0($fp) + lw $t3, 8($fp) + sw $t3, 8($t2) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -602,72 +603,113 @@ Main_constructor: #Return jump jalr $ra Main_main: - move $t5 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals - addi $sp, $sp, 40 + addi $sp, $sp, 52 #Pushing $ra sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t5, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing GetAttr - lw $t5, -4($fp) - lw $t9, 4($t5) - sw $t9, 4($fp) + lw $t1, -4($fp) + lw $t5, 4($t1) + sw $t5, 4($fp) #Executing GetAttr lw $t9, -4($fp) - lw $t3, 8($t9) - sw $t3, 8($fp) + lw $t4, 8($t9) + sw $t4, 8($fp) + lw $t2, 4($fp) + lw $t4, 8($fp) + slt $t0, $t2, $t4 + sw $t0, 0($fp) #Executing GetAttr - lw $t5, -4($fp) - lw $t0, 4($t5) - sw $t0, 12($fp) + lw $t9, -4($fp) + lw $t2, 4($t9) + sw $t2, 12($fp) #Executing GetAttr - lw $t3, -4($fp) - lw $t9, 8($t3) - sw $t9, 16($fp) + lw $t4, -4($fp) + lw $t1, 8($t4) + sw $t1, 16($fp) + lw $t0, 12($fp) + lw $t3, 16($fp) + sle $t2, $t0, $t3 + sw $t2, 0($fp) #Executing GetAttr - lw $t5, -4($fp) - lw $t9, 4($t5) - sw $t9, 20($fp) + lw $t9, -4($fp) + lw $t1, 4($t9) + sw $t1, 20($fp) #Executing GetAttr - lw $t5, -4($fp) - lw $t0, 8($t5) - sw $t0, 24($fp) - #Executing Assign lw $t0, -4($fp) - sw $t0, 28($fp) + lw $t3, 8($t0) + sw $t3, 24($fp) + lw $t9, 20($fp) + lw $t1, 24($fp) + seq $t3, $t9, $t1 + sw $t3, 0($fp) + #Executing Assign + lw $t5, -4($fp) + sw $t5, 28($fp) #Executing typeof - lw $t0, 28($fp) - lw $t0, 0($t0) - sw $t0, 32($fp) + lw $t1, 28($fp) + lw $t1, 0($t1) + sw $t1, 32($fp) + #Executing GetAttr + lw $t9, -4($fp) + lw $t4, 4($t9) + sw $t4, 44($fp) + #Executing GetAttr + lw $t2, -4($fp) + lw $t1, 8($t2) + sw $t1, 48($fp) + lw $t5, 44($fp) + lw $t4, 48($fp) + sle $t0, $t5, $t4 + sw $t0, 40($fp) + lw $t1, 40($fp) + bnez $t1, THEN_1 #Executing Load li $v0, 9 li $a0, 12 syscall sw $v0, 36($fp) - la $t9, String - sw $t9, 0($v0) - li $t9, 33 - sw $t9, 4($v0) - la $t9, string_1 - sw $t9, 8($v0) + la $t1, String + sw $t1, 0($v0) + li $t1, 3 + sw $t1, 4($v0) + la $t1, string_1 + sw $t1, 8($v0) + #Executing Goto + j END_IF_2 + THEN_1: + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 36($fp) + la $t0, String + sw $t0, 0($v0) + li $t0, 4 + sw $t0, 4($v0) + la $t0, string_2 + sw $t0, 8($v0) + END_IF_2: #Receiving Arg local_Main_main_internal_7 - lw $t9, 28($fp) - sw $t9, 0($sp) + lw $t3, 28($fp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Receiving Arg local_Main_main_internal_9 - lw $t5, 36($fp) - sw $t5, 0($sp) + lw $t3, 36($fp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing Dynamic Call - lw $t0, 32($fp) - lw $t9, 12($t0) - jalr $t9 + lw $t9, 32($fp) + lw $t5, 12($t9) + jalr $t5 sw $a1, 0($fp) addi $sp, $sp, -8 #Executing Return @@ -679,6 +721,6 @@ Main_main: addi $sp, $sp, -4 lw $ra, 0($sp) #Cleaning stack after call - addi $sp, $sp, -40 + addi $sp, $sp, -52 #Return jump jalr $ra diff --git a/tests/code_gen/comparison_output.txt b/tests/code_gen/comparison_output.txt index 37a6afb04..80ac762d5 100644 --- a/tests/code_gen/comparison_output.txt +++ b/tests/code_gen/comparison_output.txt @@ -1 +1 @@ -Default value for Int should be 0 \ No newline at end of file +a<=b \ No newline at end of file diff --git a/tests/code_gen/hello_world.mips b/tests/code_gen/hello_world.mips index d35d7c6ce..96e71fc6e 100644 --- a/tests/code_gen/hello_world.mips +++ b/tests/code_gen/hello_world.mips @@ -28,15 +28,15 @@ string_1 : .asciiz, "Hello, World.\n" .globl main length: - li $t0, 0 + li $t9, 0 length_loop: - lb $t2, 0($a0) - beq $zero, $t2, length_end - add $t0, $t0, 1 + lb $t5, 0($a0) + beq $zero, $t5, length_end + add $t9, $t9, 1 add $a0, $a0, 1 j length_loop length_end: - move $a0 $t0 + move $a0 $t9 j $ra copy: copy_loop: @@ -50,7 +50,7 @@ copy: copy_end: j $ra Object_abort: - move $t1 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -59,7 +59,7 @@ Object_abort: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing RuntimeError @@ -71,7 +71,7 @@ Object_abort: li $v0, 10 syscall Object_copy: - move $t5 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -80,7 +80,7 @@ Object_copy: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t5, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -96,7 +96,7 @@ Object_copy: #Return jump jalr $ra Object_type_name: - move $t3 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -105,7 +105,7 @@ Object_type_name: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -121,7 +121,7 @@ Object_type_name: #Return jump jalr $ra IO_out_string: - move $t3 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -130,7 +130,7 @@ IO_out_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintStringNode @@ -151,7 +151,7 @@ IO_out_string: #Return jump jalr $ra IO_out_int: - move $t1 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -160,7 +160,7 @@ IO_out_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintIntNode @@ -180,7 +180,7 @@ IO_out_int: #Return jump jalr $ra IO_in_string: - move $t9 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -189,7 +189,7 @@ IO_in_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #ReadStrNode @@ -206,8 +206,8 @@ IO_in_string: li $v0, 9 syscall move $t6 $v0 - move $t5 $v0 - move $t1 $a0 + move $t2 $v0 + move $t0 $a0 #Copying bytes from one char array to another jal copy #Null-terminating the string @@ -217,11 +217,11 @@ IO_in_string: li $a0, 12 syscall sw $v0, 0($fp) - la $t3, String - sw $t3, 0($v0) + la $t9, String + sw $t9, 0($v0) #Storing length and reference to char array - sw $t1, 4($v0) - sw $t5, 8($v0) + sw $t0, 4($v0) + sw $t2, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -235,7 +235,7 @@ IO_in_string: #Return jump jalr $ra IO_in_int: - move $t1 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -244,7 +244,7 @@ IO_in_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #ReadStrNode @@ -261,7 +261,7 @@ IO_in_int: li $v0, 9 syscall move $t6 $v0 - move $t5 $v0 + move $t3 $v0 move $t9 $a0 #Copying bytes from one char array to another jal copy @@ -272,11 +272,11 @@ IO_in_int: li $a0, 12 syscall sw $v0, 0($fp) - la $t1, String - sw $t1, 0($v0) + la $t0, String + sw $t0, 0($v0) #Storing length and reference to char array sw $t9, 4($v0) - sw $t5, 8($v0) + sw $t3, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -290,7 +290,7 @@ IO_in_int: #Return jump jalr $ra String_length: - move $t4 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -299,13 +299,13 @@ String_length: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Length - lw $t4, -4($fp) - lw $t4, 4($t4) - sw $t4, 0($fp) + lw $t5, -4($fp) + lw $t5, 4($t5) + sw $t5, 0($fp) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -344,7 +344,7 @@ String_concat: #Return jump jalr $ra String_substr: - move $t9 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -353,7 +353,7 @@ String_substr: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -369,7 +369,7 @@ String_substr: #Return jump jalr $ra Object_constructor: - move $t1 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -378,7 +378,7 @@ Object_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -386,8 +386,8 @@ Object_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t3, Object - sw $t3, 0($v0) + la $t4, Object + sw $t4, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -401,7 +401,7 @@ Object_constructor: #Return jump jalr $ra IO_constructor: - move $t5 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -410,7 +410,7 @@ IO_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t5, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -418,8 +418,8 @@ IO_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t9, IO - sw $t9, 0($v0) + la $t2, IO + sw $t2, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -433,7 +433,7 @@ IO_constructor: #Return jump jalr $ra Int_constructor: - move $t9 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -442,7 +442,7 @@ Int_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -465,7 +465,7 @@ Int_constructor: #Return jump jalr $ra Bool_constructor: - move $t3 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -474,7 +474,7 @@ Bool_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -482,8 +482,8 @@ Bool_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t9, Bool - sw $t9, 0($v0) + la $t5, Bool + sw $t5, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -497,7 +497,7 @@ Bool_constructor: #Return jump jalr $ra String_constructor: - move $t1 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -506,7 +506,7 @@ String_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -546,8 +546,8 @@ main: sw $a1, 0($fp) addi $sp, $sp, 0 #Receiving Arg local_main_internal_0 - lw $t1, 0($fp) - sw $t1, 0($sp) + lw $t0, 0($fp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing Static Call jal Main_main @@ -556,7 +556,7 @@ main: li $v0, 10 syscall Main_constructor: - move $t9 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -565,7 +565,7 @@ Main_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -573,8 +573,8 @@ Main_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t5, Main - sw $t5, 0($v0) + la $t3, Main + sw $t3, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -604,23 +604,23 @@ Main_main: lw $t9, -4($fp) sw $t9, 4($fp) #Executing typeof - lw $t5, 4($fp) - lw $t5, 0($t5) - sw $t5, 8($fp) + lw $t9, 4($fp) + lw $t9, 0($t9) + sw $t9, 8($fp) #Executing Load li $v0, 9 li $a0, 12 syscall sw $v0, 12($fp) - la $t9, String - sw $t9, 0($v0) - li $t9, 15 - sw $t9, 4($v0) - la $t9, string_1 - sw $t9, 8($v0) + la $t0, String + sw $t0, 0($v0) + li $t0, 15 + sw $t0, 4($v0) + la $t0, string_1 + sw $t0, 8($v0) #Receiving Arg local_Main_main_internal_1 - lw $t1, 4($fp) - sw $t1, 0($sp) + lw $t3, 4($fp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Receiving Arg local_Main_main_internal_3 lw $t3, 12($fp) diff --git a/tests/code_gen/point.mips b/tests/code_gen/point.mips index 6e810f088..950c9a7a0 100644 --- a/tests/code_gen/point.mips +++ b/tests/code_gen/point.mips @@ -29,15 +29,15 @@ heap_overflow : .asciiz, "Heap overflow" .globl main length: - li $t1, 0 + li $t4, 0 length_loop: - lb $t0, 0($a0) - beq $zero, $t0, length_end - add $t1, $t1, 1 + lb $t5, 0($a0) + beq $zero, $t5, length_end + add $t4, $t4, 1 add $a0, $a0, 1 j length_loop length_end: - move $a0 $t1 + move $a0 $t4 j $ra copy: copy_loop: @@ -51,7 +51,7 @@ copy: copy_end: j $ra Object_abort: - move $t3 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -60,7 +60,7 @@ Object_abort: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing RuntimeError @@ -72,7 +72,7 @@ Object_abort: li $v0, 10 syscall Object_copy: - move $t3 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -81,7 +81,7 @@ Object_copy: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -122,7 +122,7 @@ Object_type_name: #Return jump jalr $ra IO_out_string: - move $t2 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -131,7 +131,7 @@ IO_out_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintStringNode @@ -152,7 +152,7 @@ IO_out_string: #Return jump jalr $ra IO_out_int: - move $t5 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -161,7 +161,7 @@ IO_out_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t5, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintIntNode @@ -181,7 +181,7 @@ IO_out_int: #Return jump jalr $ra IO_in_string: - move $t4 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -190,7 +190,7 @@ IO_in_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #ReadStrNode @@ -207,8 +207,8 @@ IO_in_string: li $v0, 9 syscall move $t6 $v0 - move $t5 $v0 - move $t9 $a0 + move $t2 $v0 + move $t0 $a0 #Copying bytes from one char array to another jal copy #Null-terminating the string @@ -218,11 +218,11 @@ IO_in_string: li $a0, 12 syscall sw $v0, 0($fp) - la $t4, String - sw $t4, 0($v0) + la $t1, String + sw $t1, 0($v0) #Storing length and reference to char array - sw $t9, 4($v0) - sw $t5, 8($v0) + sw $t0, 4($v0) + sw $t2, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -236,7 +236,7 @@ IO_in_string: #Return jump jalr $ra IO_in_int: - move $t9 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -245,7 +245,7 @@ IO_in_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #ReadStrNode @@ -262,8 +262,8 @@ IO_in_int: li $v0, 9 syscall move $t6 $v0 - move $t9 $v0 - move $t5 $a0 + move $t0 $v0 + move $t2 $a0 #Copying bytes from one char array to another jal copy #Null-terminating the string @@ -273,11 +273,11 @@ IO_in_int: li $a0, 12 syscall sw $v0, 0($fp) - la $t2, String - sw $t2, 0($v0) + la $t5, String + sw $t5, 0($v0) #Storing length and reference to char array - sw $t5, 4($v0) - sw $t9, 8($v0) + sw $t2, 4($v0) + sw $t0, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -291,7 +291,7 @@ IO_in_int: #Return jump jalr $ra String_length: - move $t4 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -300,13 +300,13 @@ String_length: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Length - lw $t5, -4($fp) - lw $t5, 4($t5) - sw $t5, 0($fp) + lw $t4, -4($fp) + lw $t4, 4($t4) + sw $t4, 0($fp) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -320,7 +320,7 @@ String_length: #Return jump jalr $ra String_concat: - move $t3 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -329,7 +329,7 @@ String_concat: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -370,7 +370,7 @@ String_substr: #Return jump jalr $ra Object_constructor: - move $t2 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -379,7 +379,7 @@ Object_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -387,8 +387,8 @@ Object_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t3, Object - sw $t3, 0($v0) + la $t2, Object + sw $t2, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -402,7 +402,7 @@ Object_constructor: #Return jump jalr $ra IO_constructor: - move $t9 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -411,7 +411,7 @@ IO_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -419,8 +419,8 @@ IO_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t2, IO - sw $t2, 0($v0) + la $t4, IO + sw $t4, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -434,7 +434,7 @@ IO_constructor: #Return jump jalr $ra Int_constructor: - move $t3 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -443,7 +443,7 @@ Int_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -451,8 +451,8 @@ Int_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t3, Int - sw $t3, 0($v0) + la $t2, Int + sw $t2, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -483,8 +483,8 @@ Bool_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t4, Bool - sw $t4, 0($v0) + la $t5, Bool + sw $t5, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -498,7 +498,7 @@ Bool_constructor: #Return jump jalr $ra String_constructor: - move $t2 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -507,7 +507,7 @@ String_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -515,8 +515,8 @@ String_constructor: li $a0, 12 syscall sw $v0, 0($fp) - la $t2, String - sw $t2, 0($v0) + la $t9, String + sw $t9, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -530,7 +530,7 @@ String_constructor: #Return jump jalr $ra main: - move $t4 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -539,7 +539,7 @@ main: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Static Call @@ -547,8 +547,8 @@ main: sw $a1, 0($fp) addi $sp, $sp, 0 #Receiving Arg local_main_internal_0 - lw $t9, 0($fp) - sw $t9, 0($sp) + lw $t3, 0($fp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing Static Call jal Main_main @@ -574,8 +574,8 @@ Main_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t3, Main - sw $t3, 0($v0) + la $t2, Main + sw $t2, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -589,7 +589,7 @@ Main_constructor: #Return jump jalr $ra Main_main: - move $t3 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -598,16 +598,16 @@ Main_main: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Assign lw $t4, -4($fp) sw $t4, 4($fp) #Executing typeof - lw $t4, 4($fp) - lw $t4, 0($t4) - sw $t4, 8($fp) + lw $t5, 4($fp) + lw $t5, 0($t5) + sw $t5, 8($fp) #Executing Static Call jal Point_constructor sw $a1, 16($fp) @@ -617,41 +617,41 @@ Main_main: lw $t3, 0($t3) sw $t3, 20($fp) #Executing Assign - li $t4, 5 - sw $t4, 24($fp) + li $t9, 5 + sw $t9, 24($fp) #Executing Assign - li $t3, 6 - sw $t3, 28($fp) + li $t4, 6 + sw $t4, 28($fp) #Receiving Arg local_Main_main_internal_4 - lw $t9, 16($fp) - sw $t9, 0($sp) + lw $t1, 16($fp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Receiving Arg local_Main_main_internal_6 lw $t4, 24($fp) sw $t4, 0($sp) addi $sp, $sp, 4 #Receiving Arg local_Main_main_internal_7 - lw $t2, 28($fp) - sw $t2, 0($sp) + lw $t1, 28($fp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing Dynamic Call - lw $t3, 20($fp) - lw $t4, 12($t3) - jalr $t4 + lw $t5, 20($fp) + lw $t0, 12($t5) + jalr $t0 sw $a1, 12($fp) addi $sp, $sp, -12 #Receiving Arg local_Main_main_internal_1 - lw $t4, 4($fp) - sw $t4, 0($sp) + lw $t3, 4($fp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Receiving Arg local_Main_main_internal_3 - lw $t2, 12($fp) - sw $t2, 0($sp) + lw $t0, 12($fp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing Dynamic Call - lw $t2, 8($fp) - lw $t9, 16($t2) - jalr $t9 + lw $t3, 8($fp) + lw $t4, 16($t3) + jalr $t4 sw $a1, 0($fp) addi $sp, $sp, -8 #Executing Return @@ -667,7 +667,7 @@ Main_main: #Return jump jalr $ra Point_constructor: - move $t9 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -676,7 +676,7 @@ Point_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -684,22 +684,22 @@ Point_constructor: li $a0, 12 syscall sw $v0, 0($fp) - la $t4, Point - sw $t4, 0($v0) - #Executing DefaultValue - li $t4, 0 - sw $t4, 4($fp) - #Executing SetAttr - lw $t3, 0($fp) - lw $t9, 4($fp) - sw $t9, 4($t3) + la $t1, Point + sw $t1, 0($v0) #Executing DefaultValue li $t3, 0 - sw $t3, 8($fp) + sw $t3, 4($fp) #Executing SetAttr lw $t4, 0($fp) - lw $t2, 8($fp) - sw $t2, 8($t4) + lw $t0, 4($fp) + sw $t0, 4($t4) + #Executing DefaultValue + li $t0, 0 + sw $t0, 8($fp) + #Executing SetAttr + lw $t1, 0($fp) + lw $t4, 8($fp) + sw $t4, 8($t1) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -713,7 +713,7 @@ Point_constructor: #Return jump jalr $ra Point_init: - move $t3 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -722,20 +722,20 @@ Point_init: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Assign - lw $t3, -8($fp) - sw $t3, 4($fp) + lw $t1, -8($fp) + sw $t1, 4($fp) #Executing Assign - lw $t4, -4($fp) - sw $t4, 8($fp) + lw $t3, -4($fp) + sw $t3, 8($fp) #Executing Plus Operation - lw $t4, 4($fp) - lw $t9, 8($fp) - add $t3, $t4, $t9 - sw $t3, 0($fp) + lw $t0, 4($fp) + lw $t5, 8($fp) + add $t4, $t0, $t5 + sw $t4, 0($fp) #Executing Return lw $a1, 0($fp) #Restoring saved $fp diff --git a/tests/code_gen/read_string.mips b/tests/code_gen/read_string.mips index 22507cbd8..a122d05d9 100644 --- a/tests/code_gen/read_string.mips +++ b/tests/code_gen/read_string.mips @@ -27,15 +27,15 @@ heap_overflow : .asciiz, "Heap overflow" .globl main length: - li $t0, 0 + li $t1, 0 length_loop: - lb $t4, 0($a0) - beq $zero, $t4, length_end - add $t0, $t0, 1 + lb $t5, 0($a0) + beq $zero, $t5, length_end + add $t1, $t1, 1 add $a0, $a0, 1 j length_loop length_end: - move $a0 $t0 + move $a0 $t1 j $ra copy: copy_loop: @@ -49,7 +49,7 @@ copy: copy_end: j $ra Object_abort: - move $t3 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -58,7 +58,7 @@ Object_abort: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing RuntimeError @@ -70,7 +70,7 @@ Object_abort: li $v0, 10 syscall Object_copy: - move $t9 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -79,7 +79,7 @@ Object_copy: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -120,7 +120,7 @@ Object_type_name: #Return jump jalr $ra IO_out_string: - move $t2 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -129,7 +129,7 @@ IO_out_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintStringNode @@ -150,7 +150,7 @@ IO_out_string: #Return jump jalr $ra IO_out_int: - move $t3 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -159,7 +159,7 @@ IO_out_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintIntNode @@ -179,7 +179,7 @@ IO_out_int: #Return jump jalr $ra IO_in_string: - move $t2 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -188,7 +188,7 @@ IO_in_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #ReadStrNode @@ -205,8 +205,8 @@ IO_in_string: li $v0, 9 syscall move $t6 $v0 - move $t2 $v0 - move $t1 $a0 + move $t3 $v0 + move $t0 $a0 #Copying bytes from one char array to another jal copy #Null-terminating the string @@ -216,11 +216,11 @@ IO_in_string: li $a0, 12 syscall sw $v0, 0($fp) - la $t9, String - sw $t9, 0($v0) + la $t1, String + sw $t1, 0($v0) #Storing length and reference to char array - sw $t1, 4($v0) - sw $t2, 8($v0) + sw $t0, 4($v0) + sw $t3, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -234,7 +234,7 @@ IO_in_string: #Return jump jalr $ra IO_in_int: - move $t9 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -243,7 +243,7 @@ IO_in_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #ReadStrNode @@ -260,8 +260,8 @@ IO_in_int: li $v0, 9 syscall move $t6 $v0 - move $t1 $v0 - move $t2 $a0 + move $t3 $v0 + move $t5 $a0 #Copying bytes from one char array to another jal copy #Null-terminating the string @@ -271,11 +271,11 @@ IO_in_int: li $a0, 12 syscall sw $v0, 0($fp) - la $t3, String - sw $t3, 0($v0) + la $t9, String + sw $t9, 0($v0) #Storing length and reference to char array - sw $t2, 4($v0) - sw $t1, 8($v0) + sw $t5, 4($v0) + sw $t3, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -289,7 +289,7 @@ IO_in_int: #Return jump jalr $ra String_length: - move $t1 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -298,13 +298,13 @@ String_length: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Length - lw $t3, -4($fp) - lw $t3, 4($t3) - sw $t3, 0($fp) + lw $t4, -4($fp) + lw $t4, 4($t4) + sw $t4, 0($fp) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -318,7 +318,7 @@ String_length: #Return jump jalr $ra String_concat: - move $t5 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -327,7 +327,7 @@ String_concat: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t5, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -343,7 +343,7 @@ String_concat: #Return jump jalr $ra String_substr: - move $t1 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -352,7 +352,7 @@ String_substr: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -368,7 +368,7 @@ String_substr: #Return jump jalr $ra Object_constructor: - move $t9 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -377,7 +377,7 @@ Object_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -385,8 +385,8 @@ Object_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t5, Object - sw $t5, 0($v0) + la $t3, Object + sw $t3, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -400,7 +400,7 @@ Object_constructor: #Return jump jalr $ra IO_constructor: - move $t9 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -409,7 +409,7 @@ IO_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -417,8 +417,8 @@ IO_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t5, IO - sw $t5, 0($v0) + la $t1, IO + sw $t1, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -449,8 +449,8 @@ Int_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t2, Int - sw $t2, 0($v0) + la $t4, Int + sw $t4, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -464,7 +464,7 @@ Int_constructor: #Return jump jalr $ra Bool_constructor: - move $t9 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -473,7 +473,7 @@ Bool_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -481,8 +481,8 @@ Bool_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t9, Bool - sw $t9, 0($v0) + la $t0, Bool + sw $t0, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -496,7 +496,7 @@ Bool_constructor: #Return jump jalr $ra String_constructor: - move $t2 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -505,7 +505,7 @@ String_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -513,8 +513,8 @@ String_constructor: li $a0, 12 syscall sw $v0, 0($fp) - la $t1, String - sw $t1, 0($v0) + la $t4, String + sw $t4, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -528,7 +528,7 @@ String_constructor: #Return jump jalr $ra main: - move $t1 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -537,7 +537,7 @@ main: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Static Call @@ -545,8 +545,8 @@ main: sw $a1, 0($fp) addi $sp, $sp, 0 #Receiving Arg local_main_internal_0 - lw $t1, 0($fp) - sw $t1, 0($sp) + lw $t4, 0($fp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing Static Call jal Main_main @@ -555,7 +555,7 @@ main: li $v0, 10 syscall Main_constructor: - move $t1 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -564,7 +564,7 @@ Main_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -572,23 +572,23 @@ Main_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t9, Main - sw $t9, 0($v0) + la $t1, Main + sw $t1, 0($v0) #Executing DefaultValue li $v0, 9 li $a0, 12 syscall sw $v0, 4($fp) - la $t9, String - sw $t9, 0($v0) - li $t9, 0 - sw $t9, 4($v0) - la $t9, empty_string - sw $t9, 8($v0) + la $t5, String + sw $t5, 0($v0) + li $t5, 0 + sw $t5, 4($v0) + la $t5, empty_string + sw $t5, 8($v0) #Executing SetAttr - lw $t5, 0($fp) - lw $t1, 4($fp) - sw $t1, 4($t5) + lw $t2, 0($fp) + lw $t0, 4($fp) + sw $t0, 4($t2) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -602,7 +602,7 @@ Main_constructor: #Return jump jalr $ra Main_main: - move $t5 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -611,53 +611,53 @@ Main_main: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t5, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Assign lw $t1, -4($fp) sw $t1, 4($fp) #Executing typeof - lw $t2, 4($fp) - lw $t2, 0($t2) - sw $t2, 8($fp) + lw $t1, 4($fp) + lw $t1, 0($t1) + sw $t1, 8($fp) #Receiving Arg local_Main_main_internal_1 - lw $t5, 4($fp) - sw $t5, 0($sp) + lw $t4, 4($fp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing Dynamic Call - lw $t1, 8($fp) - lw $t9, 20($t1) - jalr $t9 + lw $t3, 8($fp) + lw $t5, 20($t3) + jalr $t5 sw $a1, 0($fp) addi $sp, $sp, -4 #Executing SetAttr - lw $t2, -4($fp) - lw $t9, 0($fp) - sw $t9, 4($t2) + lw $t3, -4($fp) + lw $t1, 0($fp) + sw $t1, 4($t3) #Executing Assign - lw $t1, -4($fp) - sw $t1, 12($fp) + lw $t5, -4($fp) + sw $t5, 12($fp) #Executing typeof - lw $t9, 12($fp) - lw $t9, 0($t9) - sw $t9, 16($fp) + lw $t1, 12($fp) + lw $t1, 0($t1) + sw $t1, 16($fp) #Executing GetAttr - lw $t5, -4($fp) - lw $t1, 4($t5) + lw $t0, -4($fp) + lw $t1, 4($t0) sw $t1, 20($fp) #Receiving Arg local_Main_main_internal_3 - lw $t2, 12($fp) - sw $t2, 0($sp) + lw $t0, 12($fp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Receiving Arg local_Main_main_internal_5 - lw $t5, 20($fp) - sw $t5, 0($sp) + lw $t9, 20($fp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing Dynamic Call - lw $t5, 16($fp) - lw $t9, 12($t5) - jalr $t9 + lw $t2, 16($fp) + lw $t3, 12($t2) + jalr $t3 sw $a1, 0($fp) addi $sp, $sp, -8 #Executing Return diff --git a/tests/code_gen/string_methods.cl b/tests/code_gen/string_methods.cl new file mode 100644 index 000000000..caeea757d --- /dev/null +++ b/tests/code_gen/string_methods.cl @@ -0,0 +1,13 @@ +class Main inherits IO{ + (* a : Int; + b : Int; + *) + c : String <- "First sentence."; + d : String <- "Second sentence."; + main (): Object { + { + (* out_string(c.concat(d)); *) + out_string(c.substr(0, c.length())); + } + }; +}; \ No newline at end of file diff --git a/tests/code_gen/string_methods.mips b/tests/code_gen/string_methods.mips new file mode 100644 index 000000000..681dd9a1b --- /dev/null +++ b/tests/code_gen/string_methods.mips @@ -0,0 +1,807 @@ +.data + +Object : .word, Object_abort, Object_copy, Object_type_name +Object_cname : .asciiz, "Object" +IO : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int +IO_cname : .asciiz, "IO" +String : .word, Object_abort, Object_copy, Object_type_name, String_length, String_concat, String_substr +String_cname : .asciiz, "String" +Int : .word, Object_abort, Object_copy, Object_type_name +Int_cname : .asciiz, "Int" +Bool : .word, Object_abort, Object_copy, Object_type_name +Bool_cname : .asciiz, "Bool" +Main : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int, Main_main, Main_constructor +Main_cname : .asciiz, "Main" +void : .word, -1 +empty_string : .asciiz, "" +input_str_buffer : .space, 1024 +abort_signal : .asciiz, "Program execution aborted" +case_missmatch : .asciiz, "Execution of a case statement without a matching branch" +case_on_void : .asciiz, "Case on void" +dispatch_on_void : .asciiz, "Dispatch on void" +division_by_zero : .asciiz, "Division by zero" +substr_out_of_range : .asciiz, "Substring out of range" +heap_overflow : .asciiz, "Heap overflow" +string_1 : .asciiz, "First sentence." +string_2 : .asciiz, "Second sentence." + +.text +.globl main + +length: + li $t2, 0 + length_loop: + lb $t1, 0($a0) + beq $zero, $t1, length_end + add $t2, $t2, 1 + add $a0, $a0, 1 + j length_loop + length_end: + move $a0 $t2 + j $ra +copy: + copy_loop: + beq $zero, $a0, copy_end + lb $t8, 0($t7) + sb $t8, 0($t6) + addi $t6, $t6, 1 + addi $t7, $t7, 1 + addi $a0, $a0, -1 + j copy_loop + copy_end: + j $ra +Object_abort: + move $t2 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 0 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing RuntimeError + #Printing Abort Message + la $a0, abort_signal + li $v0, 4 + syscall + #Aborting execution + li $v0, 10 + syscall +Object_copy: + move $t4 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Object_type_name: + move $t3 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +IO_out_string: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 0 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #PrintStringNode + lw $a0, -4($fp) + lw $a0, 8($a0) + li $v0, 4 + syscall + #Executing Return + lw $a1, -8($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, 0 + #Return jump + jalr $ra +IO_out_int: + move $t4 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 0 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #PrintIntNode + lw $a0, -4($fp) + li $v0, 1 + syscall + #Executing Return + lw $a1, -8($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, 0 + #Return jump + jalr $ra +IO_in_string: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #ReadStrNode + #Reading String to buffer + la $a0, input_str_buffer + li $a1, 1024 + li $v0, 8 + syscall + #Saving reference to read string + move $t7 $a0 + #Calculating str length + jal length + #Allocating char array for new string + li $v0, 9 + syscall + move $t6 $v0 + move $t5 $v0 + move $t2 $a0 + #Copying bytes from one char array to another + jal copy + #Null-terminating the string + sb $zero, 0($t6) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t4, String + sw $t4, 0($v0) + #Storing length and reference to char array + sw $t2, 4($v0) + sw $t5, 8($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +IO_in_int: + move $t5 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #ReadStrNode + #Reading String to buffer + la $a0, input_str_buffer + li $a1, 1024 + li $v0, 8 + syscall + #Saving reference to read string + move $t7 $a0 + #Calculating str length + jal length + #Allocating char array for new string + li $v0, 9 + syscall + move $t6 $v0 + move $t0 $v0 + move $t1 $a0 + #Copying bytes from one char array to another + jal copy + #Null-terminating the string + sb $zero, 0($t6) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t2, String + sw $t2, 0($v0) + #Storing length and reference to char array + sw $t1, 4($v0) + sw $t0, 8($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_length: + move $t4 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Length + lw $t3, -4($fp) + lw $t3, 4($t3) + sw $t3, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_concat: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Loading length + lw $s1, -8($fp) + lw $s1, 4($s1) + lw $s2, -4($fp) + lw $s2, 4($s2) + add $t9, $s1, $s2 + #Allocating new char array + move $a0 $t9 + addi $a0, $a0, 1 + li $v0, 9 + syscall + move $t6 $v0 + move $t5 $v0 + #Copying bytes from first string + lw $t7, -8($fp) + lw $t7, 8($t7) + move $a0 $s1 + jal copy + #Copying bytes from second string + lw $t7, -4($fp) + lw $t7, 8($t7) + move $a0 $s2 + jal copy + #Null-terminating the string + sb $zero, 0($t6) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t4, String + sw $t4, 0($v0) + #Storing length and reference to char array + sw $t9, 4($v0) + sw $t5, 8($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_substr: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Substring + lw $s0, -4($fp) + move $a0 $s0 + addi $a0, $a0, 1 + li $v0, 9 + syscall + move $t6 $v0 + #Loading reference to char array of source string + lw $t7, -12($fp) + lw $t7, 8($t7) + lw $s2, -8($fp) + add $t7, $t7, $s2 + move $s1 $t6 + #Copying bytes from one char array to another + move $a0 $s0 + jal copy + #Null-terminating the string + sb $zero, 0($t0) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t5, String + sw $t5, 0($v0) + #Storing length and reference to char array + lw $s0, -4($fp) + sw $s0, 4($v0) + sw $s1, 8($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Object_constructor: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t1, Object + sw $t1, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +IO_constructor: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t0, IO + sw $t0, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Int_constructor: + move $t4 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 8 + syscall + sw $v0, 0($fp) + la $t3, Int + sw $t3, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Bool_constructor: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 8 + syscall + sw $v0, 0($fp) + la $t1, Bool + sw $t1, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_constructor: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t3, String + sw $t3, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +main: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Static Call + jal Main_constructor + sw $a1, 0($fp) + addi $sp, $sp, 0 + #Receiving Arg local_main_internal_0 + lw $t0, 0($fp) + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing Static Call + jal Main_main + sw $a1, 4($fp) + addi $sp, $sp, -4 + li $v0, 10 + syscall +Main_constructor: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 20 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t3, Main + sw $t3, 0($v0) + #Executing DefaultValue + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t1, String + sw $t1, 0($v0) + li $t1, 0 + sw $t1, 4($v0) + la $t1, empty_string + sw $t1, 8($v0) + #Executing SetAttr + lw $t2, 0($fp) + lw $t3, 4($fp) + sw $t3, 4($t2) + #Executing DefaultValue + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 8($fp) + la $t4, String + sw $t4, 0($v0) + li $t4, 0 + sw $t4, 4($v0) + la $t4, empty_string + sw $t4, 8($v0) + #Executing SetAttr + lw $t9, 0($fp) + lw $t0, 8($fp) + sw $t0, 8($t9) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 12($fp) + la $t1, String + sw $t1, 0($v0) + li $t1, 15 + sw $t1, 4($v0) + la $t1, string_1 + sw $t1, 8($v0) + #Executing SetAttr + lw $t9, 0($fp) + lw $t1, 12($fp) + sw $t1, 4($t9) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 16($fp) + la $t3, String + sw $t3, 0($v0) + li $t3, 16 + sw $t3, 4($v0) + la $t3, string_2 + sw $t3, 8($v0) + #Executing SetAttr + lw $t1, 0($fp) + lw $t4, 16($fp) + sw $t4, 8($t1) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -20 + #Return jump + jalr $ra +Main_main: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 40 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Assign + lw $t0, -4($fp) + sw $t0, 4($fp) + #Executing typeof + lw $t3, 4($fp) + lw $t3, 0($t3) + sw $t3, 8($fp) + #Executing GetAttr + lw $t0, -4($fp) + lw $t3, 4($t0) + sw $t3, 16($fp) + #Executing typeof + lw $t9, 16($fp) + lw $t9, 0($t9) + sw $t9, 20($fp) + #Executing Assign + li $t0, 0 + sw $t0, 24($fp) + #Executing GetAttr + lw $t4, -4($fp) + lw $t3, 4($t4) + sw $t3, 32($fp) + #Executing typeof + lw $t2, 32($fp) + lw $t2, 0($t2) + sw $t2, 36($fp) + #Receiving Arg local_Main_main_internal_8 + lw $t1, 32($fp) + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing Dynamic Call + lw $t9, 36($fp) + lw $t1, 12($t9) + jalr $t1 + sw $a1, 28($fp) + addi $sp, $sp, -4 + #Receiving Arg local_Main_main_internal_4 + lw $t9, 16($fp) + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Receiving Arg local_Main_main_internal_6 + lw $t0, 24($fp) + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Receiving Arg local_Main_main_internal_7 + lw $t3, 28($fp) + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing Dynamic Call + lw $t0, 20($fp) + lw $t3, 20($t0) + jalr $t3 + sw $a1, 12($fp) + addi $sp, $sp, -12 + #Receiving Arg local_Main_main_internal_1 + lw $t3, 4($fp) + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Receiving Arg local_Main_main_internal_3 + lw $t3, 12($fp) + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing Dynamic Call + lw $t9, 8($fp) + lw $t0, 12($t9) + jalr $t0 + sw $a1, 0($fp) + addi $sp, $sp, -8 + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -40 + #Return jump + jalr $ra diff --git a/customized_tests/code_gen/test_goto_if_input.txt b/tests/code_gen/string_methods_input.txt similarity index 100% rename from customized_tests/code_gen/test_goto_if_input.txt rename to tests/code_gen/string_methods_input.txt diff --git a/tests/code_gen/string_methods_output.txt b/tests/code_gen/string_methods_output.txt new file mode 100644 index 000000000..42bc7029f --- /dev/null +++ b/tests/code_gen/string_methods_output.txt @@ -0,0 +1 @@ +First sentence.Second sentence.First sentence. \ No newline at end of file diff --git a/tests/code_gen/test_goto_if.mips b/tests/code_gen/test_goto_if.mips index 0f3421dc1..f35dc73de 100644 --- a/tests/code_gen/test_goto_if.mips +++ b/tests/code_gen/test_goto_if.mips @@ -27,15 +27,15 @@ heap_overflow : .asciiz, "Heap overflow" .globl main length: - li $t3, 0 + li $t9, 0 length_loop: - lb $t1, 0($a0) - beq $zero, $t1, length_end - add $t3, $t3, 1 + lb $t0, 0($a0) + beq $zero, $t0, length_end + add $t9, $t9, 1 add $a0, $a0, 1 j length_loop length_end: - move $a0 $t3 + move $a0 $t9 j $ra copy: copy_loop: @@ -49,7 +49,7 @@ copy: copy_end: j $ra Object_abort: - move $t2 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -58,7 +58,7 @@ Object_abort: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing RuntimeError @@ -70,7 +70,7 @@ Object_abort: li $v0, 10 syscall Object_copy: - move $t4 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -79,7 +79,7 @@ Object_copy: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -95,7 +95,7 @@ Object_copy: #Return jump jalr $ra Object_type_name: - move $t0 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -104,7 +104,7 @@ Object_type_name: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -150,7 +150,7 @@ IO_out_string: #Return jump jalr $ra IO_out_int: - move $t9 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -159,7 +159,7 @@ IO_out_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintIntNode @@ -179,7 +179,7 @@ IO_out_int: #Return jump jalr $ra IO_in_string: - move $t4 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -188,7 +188,7 @@ IO_in_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #ReadStrNode @@ -205,8 +205,8 @@ IO_in_string: li $v0, 9 syscall move $t6 $v0 - move $t5 $v0 - move $t9 $a0 + move $t4 $v0 + move $t5 $a0 #Copying bytes from one char array to another jal copy #Null-terminating the string @@ -216,11 +216,11 @@ IO_in_string: li $a0, 12 syscall sw $v0, 0($fp) - la $t4, String - sw $t4, 0($v0) + la $t9, String + sw $t9, 0($v0) #Storing length and reference to char array - sw $t9, 4($v0) - sw $t5, 8($v0) + sw $t5, 4($v0) + sw $t4, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -234,7 +234,7 @@ IO_in_string: #Return jump jalr $ra IO_in_int: - move $t0 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -243,7 +243,7 @@ IO_in_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #ReadStrNode @@ -260,8 +260,8 @@ IO_in_int: li $v0, 9 syscall move $t6 $v0 - move $t4 $v0 - move $t0 $a0 + move $t3 $v0 + move $t4 $a0 #Copying bytes from one char array to another jal copy #Null-terminating the string @@ -271,11 +271,11 @@ IO_in_int: li $a0, 12 syscall sw $v0, 0($fp) - la $t9, String - sw $t9, 0($v0) + la $t0, String + sw $t0, 0($v0) #Storing length and reference to char array - sw $t0, 4($v0) - sw $t4, 8($v0) + sw $t4, 4($v0) + sw $t3, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -289,7 +289,7 @@ IO_in_int: #Return jump jalr $ra String_length: - move $t0 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -298,13 +298,13 @@ String_length: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Length - lw $t9, -4($fp) - lw $t9, 4($t9) - sw $t9, 0($fp) + lw $t4, -4($fp) + lw $t4, 4($t4) + sw $t4, 0($fp) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -318,7 +318,7 @@ String_length: #Return jump jalr $ra String_concat: - move $t4 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -327,7 +327,7 @@ String_concat: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -343,7 +343,7 @@ String_concat: #Return jump jalr $ra String_substr: - move $t0 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -352,7 +352,7 @@ String_substr: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -368,7 +368,7 @@ String_substr: #Return jump jalr $ra Object_constructor: - move $t0 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -377,7 +377,7 @@ Object_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -385,8 +385,8 @@ Object_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t5, Object - sw $t5, 0($v0) + la $t4, Object + sw $t4, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -400,7 +400,7 @@ Object_constructor: #Return jump jalr $ra IO_constructor: - move $t4 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -409,7 +409,7 @@ IO_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -417,8 +417,8 @@ IO_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t0, IO - sw $t0, 0($v0) + la $t2, IO + sw $t2, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -432,7 +432,7 @@ IO_constructor: #Return jump jalr $ra Int_constructor: - move $t0 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -441,7 +441,7 @@ Int_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -449,8 +449,8 @@ Int_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t4, Int - sw $t4, 0($v0) + la $t5, Int + sw $t5, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -464,7 +464,7 @@ Int_constructor: #Return jump jalr $ra Bool_constructor: - move $t2 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -473,7 +473,7 @@ Bool_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -481,8 +481,8 @@ Bool_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t2, Bool - sw $t2, 0($v0) + la $t0, Bool + sw $t0, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -496,7 +496,7 @@ Bool_constructor: #Return jump jalr $ra String_constructor: - move $t4 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -505,7 +505,7 @@ String_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -513,8 +513,8 @@ String_constructor: li $a0, 12 syscall sw $v0, 0($fp) - la $t5, String - sw $t5, 0($v0) + la $t1, String + sw $t1, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -528,7 +528,7 @@ String_constructor: #Return jump jalr $ra main: - move $t0 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -537,7 +537,7 @@ main: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Static Call @@ -545,8 +545,8 @@ main: sw $a1, 0($fp) addi $sp, $sp, 0 #Receiving Arg local_main_internal_0 - lw $t2, 0($fp) - sw $t2, 0($sp) + lw $t0, 0($fp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing Static Call jal Main_main @@ -555,7 +555,7 @@ main: li $v0, 10 syscall Main_constructor: - move $t2 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -564,7 +564,7 @@ Main_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -572,36 +572,36 @@ Main_constructor: li $a0, 12 syscall sw $v0, 0($fp) - la $t4, Main - sw $t4, 0($v0) + la $t2, Main + sw $t2, 0($v0) #Executing DefaultValue - li $t2, 0 - sw $t2, 4($fp) + li $t3, 0 + sw $t3, 4($fp) #Executing SetAttr - lw $t0, 0($fp) - lw $t4, 4($fp) - sw $t4, 4($t0) + lw $t1, 0($fp) + lw $t3, 4($fp) + sw $t3, 4($t1) #Executing DefaultValue - li $t0, 0 - sw $t0, 8($fp) + li $t3, 0 + sw $t3, 8($fp) #Executing SetAttr - lw $t5, 0($fp) - lw $t4, 8($fp) - sw $t4, 8($t5) + lw $t0, 0($fp) + lw $t1, 8($fp) + sw $t1, 8($t0) #Executing Assign - li $t2, 1 - sw $t2, 12($fp) + li $t5, 1 + sw $t5, 12($fp) #Executing SetAttr lw $t5, 0($fp) - lw $t2, 12($fp) - sw $t2, 4($t5) + lw $t0, 12($fp) + sw $t0, 4($t5) #Executing Assign - li $t2, 2 - sw $t2, 16($fp) + li $t3, 2 + sw $t3, 16($fp) #Executing SetAttr - lw $t0, 0($fp) - lw $t2, 16($fp) - sw $t2, 8($t0) + lw $t9, 0($fp) + lw $t5, 16($fp) + sw $t5, 8($t9) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -615,7 +615,7 @@ Main_constructor: #Return jump jalr $ra Main_main: - move $t0 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -624,82 +624,82 @@ Main_main: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing GetAttr - lw $t2, -4($fp) - lw $t0, 4($t2) - sw $t0, 4($fp) + lw $t4, -4($fp) + lw $t3, 4($t4) + sw $t3, 4($fp) #Executing GetAttr - lw $t5, -4($fp) - lw $t4, 8($t5) - sw $t4, 8($fp) + lw $t9, -4($fp) + lw $t0, 8($t9) + sw $t0, 8($fp) #Executing Plus Operation - lw $t2, 4($fp) - lw $t0, 8($fp) - add $t4, $t2, $t0 + lw $t9, 4($fp) + lw $t1, 8($fp) + add $t4, $t9, $t1 sw $t4, 0($fp) #Executing GetAttr - lw $t4, -4($fp) - lw $t2, 4($t4) - sw $t2, 12($fp) + lw $t2, -4($fp) + lw $t1, 4($t2) + sw $t1, 12($fp) #Executing GetAttr - lw $t5, -4($fp) - lw $t2, 8($t5) - sw $t2, 16($fp) + lw $t0, -4($fp) + lw $t3, 8($t0) + sw $t3, 16($fp) #Executing Minus Operation - lw $t5, 12($fp) - lw $t0, 16($fp) - sub $t2, $t5, $t0 - sw $t2, 0($fp) + lw $t3, 12($fp) + lw $t9, 16($fp) + sub $t1, $t3, $t9 + sw $t1, 0($fp) #Executing GetAttr - lw $t4, -4($fp) - lw $t0, 4($t4) - sw $t0, 20($fp) + lw $t3, -4($fp) + lw $t5, 4($t3) + sw $t5, 20($fp) #Executing GetAttr - lw $t5, -4($fp) - lw $t4, 8($t5) + lw $t0, -4($fp) + lw $t4, 8($t0) sw $t4, 24($fp) #Executing Div Operation - lw $t2, 20($fp) - lw $t5, 24($fp) - div $t2, $t5 - mflo $t2 - sw $t2, 0($fp) + lw $t5, 20($fp) + lw $t1, 24($fp) + div $t5, $t1 + mflo $t5 + sw $t5, 0($fp) #Executing Assign - lw $t4, -4($fp) - sw $t4, 28($fp) + lw $t9, -4($fp) + sw $t9, 28($fp) #Executing typeof - lw $t4, 28($fp) - lw $t4, 0($t4) - sw $t4, 32($fp) + lw $t3, 28($fp) + lw $t3, 0($t3) + sw $t3, 32($fp) #Executing GetAttr - lw $t2, -4($fp) - lw $t4, 8($t2) - sw $t4, 40($fp) + lw $t9, -4($fp) + lw $t1, 8($t9) + sw $t1, 40($fp) #Executing GetAttr - lw $t2, -4($fp) - lw $t0, 4($t2) - sw $t0, 44($fp) + lw $t3, -4($fp) + lw $t5, 4($t3) + sw $t5, 44($fp) #Executing Star Operation - lw $t2, 40($fp) - lw $t5, 44($fp) - mult $t2, $t5 - mflo $t2 - sw $t2, 36($fp) + lw $t4, 40($fp) + lw $t0, 44($fp) + mult $t4, $t0 + mflo $t4 + sw $t4, 36($fp) #Receiving Arg local_Main_main_internal_7 - lw $t4, 28($fp) - sw $t4, 0($sp) + lw $t3, 28($fp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Receiving Arg local_Main_main_internal_9 - lw $t2, 36($fp) - sw $t2, 0($sp) + lw $t1, 36($fp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing Dynamic Call - lw $t4, 32($fp) - lw $t5, 16($t4) - jalr $t5 + lw $t1, 32($fp) + lw $t3, 16($t1) + jalr $t3 sw $a1, 0($fp) addi $sp, $sp, -8 #Executing Return diff --git a/tests/code_gen/unary_nodes.cl b/tests/code_gen/unary_nodes.cl new file mode 100644 index 000000000..d9bc9e3b6 --- /dev/null +++ b/tests/code_gen/unary_nodes.cl @@ -0,0 +1,11 @@ +class Main inherits IO{ + a : Int <- 4; + b : Int; + c: Bool; + main (): Object { + { + out_string(if not a <= b then "True \n" else "False \n" fi); + out_int(~a); + } + }; +}; diff --git a/tests/code_gen/unary_nodes.mips b/tests/code_gen/unary_nodes.mips new file mode 100644 index 000000000..5a39678e0 --- /dev/null +++ b/tests/code_gen/unary_nodes.mips @@ -0,0 +1,745 @@ +.data + +Object : .word, Object_abort, Object_copy, Object_type_name +Object_cname : .asciiz, "Object" +IO : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int +IO_cname : .asciiz, "IO" +String : .word, Object_abort, Object_copy, Object_type_name, String_length, String_concat, String_substr +String_cname : .asciiz, "String" +Int : .word, Object_abort, Object_copy, Object_type_name +Int_cname : .asciiz, "Int" +Bool : .word, Object_abort, Object_copy, Object_type_name +Bool_cname : .asciiz, "Bool" +Main : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int, Main_main, Main_constructor +Main_cname : .asciiz, "Main" +void : .word, -1 +empty_string : .asciiz, "" +input_str_buffer : .space, 1024 +abort_signal : .asciiz, "Program execution aborted" +case_missmatch : .asciiz, "Execution of a case statement without a matching branch" +case_on_void : .asciiz, "Case on void" +dispatch_on_void : .asciiz, "Dispatch on void" +division_by_zero : .asciiz, "Division by zero" +substr_out_of_range : .asciiz, "Substring out of range" +heap_overflow : .asciiz, "Heap overflow" +string_1 : .asciiz, "False \n" +string_2 : .asciiz, "True \n" + +.text +.globl main + +length: + li $t5, 0 + length_loop: + lb $t2, 0($a0) + beq $zero, $t2, length_end + add $t5, $t5, 1 + add $a0, $a0, 1 + j length_loop + length_end: + move $a0 $t5 + j $ra +copy: + copy_loop: + beq $zero, $a0, copy_end + lb $t8, 0($t7) + sb $t8, 0($t6) + addi $t6, $t6, 1 + addi $t7, $t7, 1 + addi $a0, $a0, -1 + j copy_loop + copy_end: + j $ra +Object_abort: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 0 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing RuntimeError + #Printing Abort Message + la $a0, abort_signal + li $v0, 4 + syscall + #Aborting execution + li $v0, 10 + syscall +Object_copy: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Object_type_name: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +IO_out_string: + move $t3 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 0 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #PrintStringNode + lw $a0, -4($fp) + lw $a0, 8($a0) + li $v0, 4 + syscall + #Executing Return + lw $a1, -8($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, 0 + #Return jump + jalr $ra +IO_out_int: + move $t4 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 0 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #PrintIntNode + lw $a0, -4($fp) + li $v0, 1 + syscall + #Executing Return + lw $a1, -8($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, 0 + #Return jump + jalr $ra +IO_in_string: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #ReadStrNode + #Reading String to buffer + la $a0, input_str_buffer + li $a1, 1024 + li $v0, 8 + syscall + #Saving reference to read string + move $t7 $a0 + #Calculating str length + jal length + #Allocating char array for new string + li $v0, 9 + syscall + move $t6 $v0 + move $t1 $v0 + move $t0 $a0 + #Copying bytes from one char array to another + jal copy + #Null-terminating the string + sb $zero, 0($t6) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t4, String + sw $t4, 0($v0) + #Storing length and reference to char array + sw $t0, 4($v0) + sw $t1, 8($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +IO_in_int: + move $t5 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #ReadStrNode + #Reading String to buffer + la $a0, input_str_buffer + li $a1, 1024 + li $v0, 8 + syscall + #Saving reference to read string + move $t7 $a0 + #Calculating str length + jal length + #Allocating char array for new string + li $v0, 9 + syscall + move $t6 $v0 + move $t9 $v0 + move $t5 $a0 + #Copying bytes from one char array to another + jal copy + #Null-terminating the string + sb $zero, 0($t6) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t0, String + sw $t0, 0($v0) + #Storing length and reference to char array + sw $t5, 4($v0) + sw $t9, 8($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_length: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Length + lw $t3, -4($fp) + lw $t3, 4($t3) + sw $t3, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_concat: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_substr: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Object_constructor: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t1, Object + sw $t1, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +IO_constructor: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t5, IO + sw $t5, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Int_constructor: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 8 + syscall + sw $v0, 0($fp) + la $t5, Int + sw $t5, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Bool_constructor: + move $t3 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 8 + syscall + sw $v0, 0($fp) + la $t4, Bool + sw $t4, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_constructor: + move $t4 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t3, String + sw $t3, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +main: + move $t2 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Static Call + jal Main_constructor + sw $a1, 0($fp) + addi $sp, $sp, 0 + #Receiving Arg local_main_internal_0 + lw $t4, 0($fp) + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing Static Call + jal Main_main + sw $a1, 4($fp) + addi $sp, $sp, -4 + li $v0, 10 + syscall +Main_constructor: + move $t3 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 20 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 16 + syscall + sw $v0, 0($fp) + la $t2, Main + sw $t2, 0($v0) + #Executing DefaultValue + li $t0, 0 + sw $t0, 4($fp) + #Executing SetAttr + lw $t4, 0($fp) + lw $t0, 4($fp) + sw $t0, 4($t4) + #Executing DefaultValue + li $t5, 0 + sw $t5, 8($fp) + #Executing SetAttr + lw $t0, 0($fp) + lw $t5, 8($fp) + sw $t5, 8($t0) + #Executing DefaultValue + li $t5, 0 + sw $t5, 12($fp) + #Executing SetAttr + lw $t2, 0($fp) + lw $t9, 12($fp) + sw $t9, 12($t2) + #Executing Assign + li $t1, 4 + sw $t1, 16($fp) + #Executing SetAttr + lw $t9, 0($fp) + lw $t4, 16($fp) + sw $t4, 4($t9) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -20 + #Return jump + jalr $ra +Main_main: + move $t4 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 52 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Assign + lw $t5, -4($fp) + sw $t5, 4($fp) + #Executing typeof + lw $t4, 4($fp) + lw $t4, 0($t4) + sw $t4, 8($fp) + #Executing GetAttr + lw $t3, -4($fp) + lw $t1, 4($t3) + sw $t1, 24($fp) + #Executing GetAttr + lw $t9, -4($fp) + lw $t5, 8($t9) + sw $t5, 28($fp) + lw $t1, 24($fp) + lw $t0, 28($fp) + sle $t5, $t1, $t0 + sw $t5, 20($fp) + #Executing Static Call + jal Bool_constructor + sw $a1, 32($fp) + addi $sp, $sp, 0 + #Executing Assign + li $t1, 1 + sw $t1, 32($fp) + #Executing Minus Operation + lw $t1, 32($fp) + lw $t2, 20($fp) + sub $t0, $t1, $t2 + sw $t0, 16($fp) + lw $t4, 16($fp) + bnez $t4, THEN_1 + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 12($fp) + la $t1, String + sw $t1, 0($v0) + li $t1, 8 + sw $t1, 4($v0) + la $t1, string_1 + sw $t1, 8($v0) + #Executing Goto + j END_IF_2 + THEN_1: + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 12($fp) + la $t2, String + sw $t2, 0($v0) + li $t2, 7 + sw $t2, 4($v0) + la $t2, string_2 + sw $t2, 8($v0) + END_IF_2: + #Receiving Arg local_Main_main_internal_1 + lw $t2, 4($fp) + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Receiving Arg local_Main_main_internal_3 + lw $t9, 12($fp) + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing Dynamic Call + lw $t2, 8($fp) + lw $t5, 12($t2) + jalr $t5 + sw $a1, 0($fp) + addi $sp, $sp, -8 + #Executing Assign + lw $t9, -4($fp) + sw $t9, 36($fp) + #Executing typeof + lw $t1, 36($fp) + lw $t1, 0($t1) + sw $t1, 40($fp) + #Executing GetAttr + lw $t4, -4($fp) + lw $t3, 4($t4) + sw $t3, 48($fp) + lw $t9, 48($fp) + not $t5, $t9 + addi $t5, $t5, 1 + sw $t5, 44($fp) + #Receiving Arg local_Main_main_internal_9 + lw $t4, 36($fp) + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Receiving Arg local_Main_main_internal_11 + lw $t5, 44($fp) + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing Dynamic Call + lw $t3, 40($fp) + lw $t4, 16($t3) + jalr $t4 + sw $a1, 0($fp) + addi $sp, $sp, -8 + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -52 + #Return jump + jalr $ra diff --git a/tests/code_gen/unary_nodes_input.txt b/tests/code_gen/unary_nodes_input.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/code_gen/unary_nodes_output.txt b/tests/code_gen/unary_nodes_output.txt new file mode 100644 index 000000000..c22708346 --- /dev/null +++ b/tests/code_gen/unary_nodes_output.txt @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/tests/code_gen/while.cl b/tests/code_gen/while.cl new file mode 100644 index 000000000..69bbbcc14 --- /dev/null +++ b/tests/code_gen/while.cl @@ -0,0 +1,14 @@ +class Main inherits IO{ + a : Int <- 0; + b : Int <- 3; + main (): Object { + { + while a < b loop { + out_int(a); + out_string("iteration \n"); + a <- a + 1; + } + pool; + } + }; +}; \ No newline at end of file diff --git a/customized_tests/code_gen/test_goto_if.mips b/tests/code_gen/while.mips similarity index 80% rename from customized_tests/code_gen/test_goto_if.mips rename to tests/code_gen/while.mips index 15b29bb0d..082ae61b1 100644 --- a/customized_tests/code_gen/test_goto_if.mips +++ b/tests/code_gen/while.mips @@ -22,34 +22,35 @@ dispatch_on_void : .asciiz, "Dispatch on void" division_by_zero : .asciiz, "Division by zero" substr_out_of_range : .asciiz, "Substring out of range" heap_overflow : .asciiz, "Heap overflow" +string_1 : .asciiz, "iteration \n" .text .globl main length: - li $t1, 0 + li $t5, 0 length_loop: - lb $t5, 0($a0) - beq $zero, $t5, length_end - add $t1, $t1, 1 + lb $t4, 0($a0) + beq $zero, $t4, length_end + add $t5, $t5, 1 add $a0, $a0, 1 j length_loop length_end: - move $a0 $t1 + move $a0 $t5 j $ra copy: copy_loop: beq $zero, $a0, copy_end - lb $t7, 0($t1) - sb $t7, 0($t0) - addi $t0, $t0, 1 - addi $t1, $t1, 1 + lb $t8, 0($t7) + sb $t8, 0($t6) + addi $t6, $t6, 1 + addi $t7, $t7, 1 addi $a0, $a0, -1 j copy_loop copy_end: j $ra Object_abort: - move $t6 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -58,7 +59,7 @@ Object_abort: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t6, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing RuntimeError @@ -70,7 +71,7 @@ Object_abort: li $v0, 10 syscall Object_copy: - move $t9 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -79,7 +80,7 @@ Object_copy: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -95,7 +96,7 @@ Object_copy: #Return jump jalr $ra Object_type_name: - move $t9 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -104,7 +105,7 @@ Object_type_name: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -120,7 +121,7 @@ Object_type_name: #Return jump jalr $ra IO_out_string: - move $t0 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -129,7 +130,7 @@ IO_out_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintStringNode @@ -150,7 +151,7 @@ IO_out_string: #Return jump jalr $ra IO_out_int: - move $t8 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -159,7 +160,7 @@ IO_out_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t8, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintIntNode @@ -198,22 +199,19 @@ IO_in_string: li $v0, 8 syscall #Saving reference to read string - move $t0 $t1 - move $t1 $a0 + move $t7 $a0 #Calculating str length jal length #Allocating char array for new string li $v0, 9 syscall - move $t9 $t0 - move $t0 $v0 - move $t8 $v0 - add $a0, $a0, -1 - move $t3 $a0 + move $t6 $v0 + move $t1 $v0 + move $t2 $a0 #Copying bytes from one char array to another jal copy #Null-terminating the string - sb $zero, 0($t0) + sb $zero, 0($t6) #Allocating new String instance li $v0, 9 li $a0, 12 @@ -222,8 +220,8 @@ IO_in_string: la $t4, String sw $t4, 0($v0) #Storing length and reference to char array - sw $t3, 4($v0) - sw $t8, 8($v0) + sw $t2, 4($v0) + sw $t1, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -237,7 +235,7 @@ IO_in_string: #Return jump jalr $ra IO_in_int: - move $t8 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -246,7 +244,7 @@ IO_in_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t8, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #ReadStrNode @@ -256,31 +254,29 @@ IO_in_int: li $v0, 8 syscall #Saving reference to read string - move $t3 $t1 - move $t1 $a0 + move $t7 $a0 #Calculating str length jal length #Allocating char array for new string li $v0, 9 syscall + move $t6 $v0 move $t0 $v0 - move $t7 $v0 - add $a0, $a0, -1 - move $t9 $a0 + move $t1 $a0 #Copying bytes from one char array to another jal copy #Null-terminating the string - sb $zero, 0($t0) + sb $zero, 0($t6) #Allocating new String instance li $v0, 9 li $a0, 12 syscall sw $v0, 0($fp) - la $t6, String - sw $t6, 0($v0) + la $t3, String + sw $t3, 0($v0) #Storing length and reference to char array - sw $t9, 4($v0) - sw $t7, 8($v0) + sw $t1, 4($v0) + sw $t0, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -294,7 +290,7 @@ IO_in_int: #Return jump jalr $ra String_length: - move $t7 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -303,7 +299,7 @@ String_length: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t7, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Length @@ -323,7 +319,7 @@ String_length: #Return jump jalr $ra String_concat: - move $t7 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -332,7 +328,7 @@ String_concat: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t7, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -348,7 +344,7 @@ String_concat: #Return jump jalr $ra String_substr: - move $t0 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -357,7 +353,7 @@ String_substr: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -373,7 +369,7 @@ String_substr: #Return jump jalr $ra Object_constructor: - move $t3 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -382,7 +378,7 @@ Object_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -390,8 +386,8 @@ Object_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t8, Object - sw $t8, 0($v0) + la $t3, Object + sw $t3, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -405,7 +401,7 @@ Object_constructor: #Return jump jalr $ra IO_constructor: - move $t3 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -414,7 +410,7 @@ IO_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -422,8 +418,8 @@ IO_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t8, IO - sw $t8, 0($v0) + la $t2, IO + sw $t2, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -437,7 +433,7 @@ IO_constructor: #Return jump jalr $ra Int_constructor: - move $t7 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -446,7 +442,7 @@ Int_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t7, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -454,8 +450,8 @@ Int_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t3, Int - sw $t3, 0($v0) + la $t0, Int + sw $t0, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -486,8 +482,8 @@ Bool_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t3, Bool - sw $t3, 0($v0) + la $t4, Bool + sw $t4, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -501,7 +497,7 @@ Bool_constructor: #Return jump jalr $ra String_constructor: - move $t6 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -510,7 +506,7 @@ String_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t6, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -518,8 +514,8 @@ String_constructor: li $a0, 12 syscall sw $v0, 0($fp) - la $t8, String - sw $t8, 0($v0) + la $t3, String + sw $t3, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -533,7 +529,7 @@ String_constructor: #Return jump jalr $ra main: - move $t6 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -542,7 +538,7 @@ main: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t6, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Static Call @@ -550,8 +546,8 @@ main: sw $a1, 0($fp) addi $sp, $sp, 0 #Receiving Arg local_main_internal_0 - lw $t6, 0($fp) - sw $t6, 0($sp) + lw $t4, 0($fp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing Static Call jal Main_main @@ -560,7 +556,7 @@ main: li $v0, 10 syscall Main_constructor: - move $t3 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -569,7 +565,7 @@ Main_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -577,36 +573,36 @@ Main_constructor: li $a0, 12 syscall sw $v0, 0($fp) - la $t9, Main - sw $t9, 0($v0) + la $t4, Main + sw $t4, 0($v0) #Executing DefaultValue - li $t3, 0 - sw $t3, 4($fp) + li $t1, 0 + sw $t1, 4($fp) #Executing SetAttr - lw $t7, 0($fp) - lw $t9, 4($fp) - sw $t9, 4($t7) + lw $t4, 0($fp) + lw $t2, 4($fp) + sw $t2, 4($t4) #Executing DefaultValue - li $t6, 0 - sw $t6, 8($fp) + li $t5, 0 + sw $t5, 8($fp) #Executing SetAttr - lw $t8, 0($fp) - lw $t3, 8($fp) - sw $t3, 8($t8) + lw $t4, 0($fp) + lw $t5, 8($fp) + sw $t5, 8($t4) #Executing Assign - li $t7, 1 - sw $t7, 12($fp) + li $t9, 0 + sw $t9, 12($fp) #Executing SetAttr - lw $t7, 0($fp) - lw $t8, 12($fp) - sw $t8, 4($t7) + lw $t3, 0($fp) + lw $t4, 12($fp) + sw $t4, 4($t3) #Executing Assign - li $t6, 2 - sw $t6, 16($fp) + li $t0, 3 + sw $t0, 16($fp) #Executing SetAttr - lw $t7, 0($fp) - lw $t0, 16($fp) - sw $t0, 8($t7) + lw $t1, 0($fp) + lw $t5, 16($fp) + sw $t5, 8($t1) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -620,93 +616,115 @@ Main_constructor: #Return jump jalr $ra Main_main: - move $t0 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals - addi $sp, $sp, 48 + addi $sp, $sp, 52 #Pushing $ra sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions + WHILE_1: #Executing GetAttr - lw $t9, -4($fp) - lw $t0, 4($t9) - sw $t0, 4($fp) + lw $t2, -4($fp) + lw $t9, 4($t2) + sw $t9, 8($fp) #Executing GetAttr - lw $t3, -4($fp) - lw $t7, 8($t3) - sw $t7, 8($fp) - #Executing Plus Operation - lw $t6, 4($fp) + lw $t4, -4($fp) + lw $t0, 8($t4) + sw $t0, 12($fp) lw $t3, 8($fp) - add $t7, $t6, $t3 - sw $t7, 0($fp) - #Executing GetAttr - lw $t9, -4($fp) - lw $t7, 4($t9) - sw $t7, 12($fp) - #Executing GetAttr - lw $t8, -4($fp) - lw $t6, 8($t8) - sw $t6, 16($fp) - #Executing Minus Operation - lw $t6, 12($fp) - lw $t9, 16($fp) - sub $t7, $t6, $t9 - sw $t7, 0($fp) - #Executing GetAttr - lw $t8, -4($fp) - lw $t9, 4($t8) - sw $t9, 20($fp) - #Executing GetAttr - lw $t6, -4($fp) - lw $t0, 8($t6) - sw $t0, 24($fp) - #Executing Div Operation - lw $t7, 20($fp) - lw $t9, 24($fp) - div $t7, $t9 - mflo $t7 - sw $t7, 0($fp) + lw $t1, 12($fp) + slt $t4, $t3, $t1 + sw $t4, 4($fp) + lw $t2, 4($fp) + bnez $t2, BODY_2 + #Executing Goto + j END_WHILE_3 + BODY_2: #Executing Assign - lw $t6, -4($fp) - sw $t6, 28($fp) + lw $t5, -4($fp) + sw $t5, 20($fp) #Executing typeof - lw $t0, 28($fp) - lw $t0, 0($t0) - sw $t0, 32($fp) - #Executing GetAttr - lw $t3, -4($fp) - lw $t6, 8($t3) - sw $t6, 40($fp) + lw $t3, 20($fp) + lw $t3, 0($t3) + sw $t3, 24($fp) #Executing GetAttr - lw $t9, -4($fp) - lw $t3, 4($t9) - sw $t3, 44($fp) - #Executing Star Operation - lw $t9, 40($fp) - lw $t8, 44($fp) - mult $t9, $t8 - mflo $t9 - sw $t9, 36($fp) - #Receiving Arg local_Main_main_internal_7 - lw $t8, 28($fp) - sw $t8, 0($sp) + lw $t0, -4($fp) + lw $t5, 4($t0) + sw $t5, 28($fp) + #Receiving Arg local_Main_main_internal_5 + lw $t4, 20($fp) + sw $t4, 0($sp) addi $sp, $sp, 4 - #Receiving Arg local_Main_main_internal_9 - lw $t8, 36($fp) - sw $t8, 0($sp) + #Receiving Arg local_Main_main_internal_7 + lw $t2, 28($fp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing Dynamic Call - lw $t3, 32($fp) - lw $t0, 16($t3) + lw $t5, 24($fp) + lw $t0, 16($t5) jalr $t0 - sw $a1, 0($fp) + sw $a1, 16($fp) addi $sp, $sp, -8 + #Executing Assign + lw $t2, -4($fp) + sw $t2, 32($fp) + #Executing typeof + lw $t3, 32($fp) + lw $t3, 0($t3) + sw $t3, 36($fp) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 40($fp) + la $t2, String + sw $t2, 0($v0) + li $t2, 12 + sw $t2, 4($v0) + la $t2, string_1 + sw $t2, 8($v0) + #Receiving Arg local_Main_main_internal_8 + lw $t2, 32($fp) + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Receiving Arg local_Main_main_internal_10 + lw $t5, 40($fp) + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing Dynamic Call + lw $t3, 36($fp) + lw $t5, 12($t3) + jalr $t5 + sw $a1, 16($fp) + addi $sp, $sp, -8 + #Executing GetAttr + lw $t3, -4($fp) + lw $t2, 4($t3) + sw $t2, 44($fp) + #Executing Assign + li $t5, 1 + sw $t5, 48($fp) + #Executing Plus Operation + lw $t0, 44($fp) + lw $t9, 48($fp) + add $t4, $t0, $t9 + sw $t4, 16($fp) + #Executing SetAttr + lw $t5, -4($fp) + lw $t3, 16($fp) + sw $t3, 4($t5) + #Executing Goto + j WHILE_1 + END_WHILE_3: + #Executing DefaultValue + la $t3, void + sw $t3, 0($fp) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -716,6 +734,6 @@ Main_main: addi $sp, $sp, -4 lw $ra, 0($sp) #Cleaning stack after call - addi $sp, $sp, -48 + addi $sp, $sp, -52 #Return jump jalr $ra diff --git a/tests/code_gen/while_input.txt b/tests/code_gen/while_input.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/code_gen/while_output.txt b/tests/code_gen/while_output.txt new file mode 100644 index 000000000..de2cad9cc --- /dev/null +++ b/tests/code_gen/while_output.txt @@ -0,0 +1,3 @@ +0iteration +1iteration +2iteration From 438a09375c7ef66dab95208fe9a388bca73d012a Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Tue, 8 Mar 2022 22:35:33 -0500 Subject: [PATCH 129/162] feat: override type_name and copy methods --- src/cmp/cil.py | 12 +- src/code_gen/cil_builder.py | 109 ++++- src/code_gen/mips_builder.py | 784 +++++++++++++++++------------------ 3 files changed, 481 insertions(+), 424 deletions(-) diff --git a/src/cmp/cil.py b/src/cmp/cil.py index f9f39727e..87246cb75 100644 --- a/src/cmp/cil.py +++ b/src/cmp/cil.py @@ -245,11 +245,11 @@ class IsVoidNode(InstructionNode): def __init__(self, dest, value): self.dest = dest self.value = value - + + class ExitNode(InstructionNode): def __init__(self): pass - class PrintVisitor(object): @@ -350,11 +350,11 @@ def visit(self, node): @visitor.when(SetAttribNode) def visit(self, node): - return f" SETATTR {node.type} {node.attr} {node.value}" + return f" SETATTR {node.instance} {node.attr} {node.value}" @visitor.when(GetAttribNode) def visit(self, node): - return f" {node.dest} = GETATTR {node.type} {node.attr}" + return f" {node.dest} = GETATTR {node.instance} {node.attr}" @visitor.when(TypeOfNode) def visit(self, node): @@ -410,7 +410,7 @@ def visit(self, node): @visitor.when(LoadNode) def visit(self, node): - return f"{node.dest} = LOAD {node.msg.name}" + return f"{node.dest} = LOAD {node.msg}" @visitor.when(ConcatNode) def visit(self, node): @@ -431,5 +431,7 @@ def visit(self, node): @visitor.when(ExitNode) def visit(self, node): return f"EXIT" + + # printer = PrintVisitor() # return lambda ast: printer.visit(ast) diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index 9113d892c..86edc95a0 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -198,17 +198,21 @@ def build_constructor(self, node): def add_builtin_functions(self): # Object - obj_functions = [ - self.cil_predef_method("abort", "Object", self.object_abort), - self.cil_predef_method("copy", "Object", self.object_copy), - self.cil_predef_method("type_name", "Object", self.object_type_name), - ] + obj_functions = [self.cil_predef_method("abort", "Object", self.object_abort)] object_type = TypeNode("Object") object_type.attributes = [] - object_type.methods = obj_functions + object_type.methods = obj_functions.copy() + object_type.methods.append( + self.cil_predef_method("copy", "Object", self.object_copy) + ) + object_type.methods.append( + self.cil_predef_method("type_name", "Object", self.object_type_name) + ) # "IO" functions = [ + self.cil_predef_method("copy", "IO", self.object_copy), + self.cil_predef_method("type_name", "IO", self.object_type_name), self.cil_predef_method("out_string", "IO", self.io_outstring), self.cil_predef_method("out_int", "IO", self.io_outint), self.cil_predef_method("in_string", "IO", self.io_instring), @@ -220,6 +224,8 @@ def add_builtin_functions(self): # String functions = [ + self.cil_predef_method("copy", "String", self.object_copy), + self.cil_predef_method("type_name", "String", self.object_type_name), self.cil_predef_method("length", "String", self.string_length), self.cil_predef_method("concat", "String", self.string_concat), self.cil_predef_method("substr", "String", self.string_substr), @@ -234,12 +240,18 @@ def add_builtin_functions(self): # Int int_type = TypeNode("Int") int_type.attributes = [VariableInfo("value", is_attr=True).name] - int_type.methods = obj_functions + int_type.methods = obj_functions + [ + self.cil_predef_method("copy", "Int", self.object_copy), + self.cil_predef_method("type_name", "Int", self.object_type_name), + ] # Bool bool_type = TypeNode("Bool") bool_type.attributes = [VariableInfo("value", is_attr=True).name] - bool_type.methods = obj_functions + bool_type.methods = obj_functions + [ + self.cil_predef_method("copy", "Bool", self.object_copy), + self.cil_predef_method("type_name", "Bool", self.object_type_name), + ] for typex in [object_type, io_type, string_type, int_type, bool_type]: self.types.append(typex) @@ -260,6 +272,22 @@ def cil_predef_method(self, mname, cname, specif_code): return (mname, self.to_function_name(mname, cname)) + def register_copy(self): + self.current_function = FunctionNode( + self.to_function_name("copy", self.current_type.name), [], [], [] + ) + self.object_copy() + self.code.append(self.current_function) + self.current_function = None + + def register_type_name(self): + self.current_function = FunctionNode( + self.to_function_name("type_name", self.current_type.name), [], [], [] + ) + self.object_type_name() + self.code.append(self.current_function) + self.current_function = None + def string_length(self): self.params.append(ParamNode("self")) @@ -297,15 +325,43 @@ def object_abort(self): def object_copy(self): self.params.append(ParamNode("self")) - ret_vinfo = self.define_internal_local() - self.register_instruction(CopyNode(ret_vinfo, "self")) - self.register_instruction(ReturnNode(ret_vinfo)) + copy_local = self.define_internal_local() + self.register_instruction(AllocateNode(self.current_type.name, copy_local)) + + for attr in self.attrs[self.current_type.name].keys(): + attr_copy_local = self.define_internal_local() + self.register_instruction( + GetAttribNode( + attr_copy_local, + "self", + self.to_attr_name(self.current_type.name, attr), + self.current_type.name, + ) + ) + self.register_instruction( + SetAttribNode( + copy_local, + self.to_attr_name(self.current_type.name, attr), + attr_copy_local, + self.current_type.name, + ) + ) + + self.register_instruction(ReturnNode(copy_local)) def object_type_name(self): self.params.append(ParamNode("self")) - ret_vinfo = self.define_internal_local() - self.register_instruction(TypeNameNode(ret_vinfo, "self")) - self.register_instruction(ReturnNode(ret_vinfo)) + solve = self.define_internal_local() + self.data.append( + DataNode(f"type_name_{self.current_type.name}", f"{self.current_type.name}") + ) + self.register_instruction(AllocateNode("String", solve)) + type_name = self.define_internal_local() + self.register_instruction( + LoadNode(type_name, f"type_name_{self.current_type.name}") + ) + self.register_instruction(AssignNode(solve, type_name)) + self.register_instruction(ReturnNode(solve)) def io_outstring(self): self.params.append(ParamNode("self")) @@ -351,9 +407,6 @@ def visit(self, node=None, return_var=None): def visit(self, node, return_var=None): self.context = node.context - self.add_builtin_functions() - self.add_builtin_constructors() - for type in self.context.types.values(): self.attrs[type.name] = { attr.name: (i, htype.name) @@ -397,6 +450,9 @@ def visit(self, node, return_var=None): self.current_function = None + self.add_builtin_functions() + self.add_builtin_constructors() + for declaration in node.declarations: self.visit(declaration) @@ -410,8 +466,10 @@ def visit(self, node, return_var=None): def visit(self, node, return_var=None): self.current_type = self.context.get_type(node.id) - type_node = self.register_type(self.current_type.name) + self.register_copy() + self.register_type_name() + type_node = self.register_type(self.current_type.name) self.build_constructor(node) visited_func = [] @@ -438,6 +496,21 @@ def visit(self, node, return_var=None): type_node.attributes.reverse() type_node.methods.reverse() + index = type_node.methods.index( + ("copy", self.to_function_name("copy", "Object")) + ) + type_node.methods[index] = ( + "copy", + self.to_function_name("copy", self.current_type.name), + ) + + index = type_node.methods.index( + ("type_name", self.to_function_name("type_name", "Object")) + ) + type_node.methods[index] = ( + "type_name", + self.to_function_name("type_name", self.current_type.name), + ) for feature in node.features: self.visit(feature) diff --git a/src/code_gen/mips_builder.py b/src/code_gen/mips_builder.py index f1a0abc80..69d4fe3b8 100644 --- a/src/code_gen/mips_builder.py +++ b/src/code_gen/mips_builder.py @@ -1,8 +1,8 @@ -#from atexit import register -#from email.quoprimime import body_length -#from operator import le -#from tkinter.tix import Select -#from soupsieve import select +# from atexit import register +# from email.quoprimime import body_length +# from operator import le +# from tkinter.tix import Select +# from soupsieve import select import cmp.visitor as visitor import cmp.cil as cil import random @@ -10,28 +10,26 @@ from code_gen import mips_nodes as mips - - -#type_info offsets +# type_info offsets TYPENAME_OFFSET = 0 FUNCTION_OFFSET = 4 RA_OFFSET = 8 OLD_FP_OFFSET = 4 TYPEINFO_ATTR_OFFSET = 0 -#str attributes offsets +# str attributes offsets LENGTH_ATTR_OFFSET = 4 CHARS_ATTR_OFFSET = 8 -FP_ARGS_DISTANCE = 3 # how far finishes $fp from arguments in method call -FP_LOCALS_DISTANCE = 0 # how far finishes $fp from localvars in method call +FP_ARGS_DISTANCE = 3 # how far finishes $fp from arguments in method call +FP_LOCALS_DISTANCE = 0 # how far finishes $fp from localvars in method call -ABORT_SIGNAL = "abort_signal"#CIL -CASE_MISSMATCH = "case_missmatch"#CIL -CASE_VOID = "case_on_void"#MIPS -DISPATCH_VOID = "dispatch_on_void"#MIPS -ZERO_DIVISION = "division_by_zero"#MIPS -SUBSTR_OUT_RANGE = "substr_out_of_range"#MIPS +ABORT_SIGNAL = "abort_signal" # CIL +CASE_MISSMATCH = "case_missmatch" # CIL +CASE_VOID = "case_on_void" # MIPS +DISPATCH_VOID = "dispatch_on_void" # MIPS +ZERO_DIVISION = "division_by_zero" # MIPS +SUBSTR_OUT_RANGE = "substr_out_of_range" # MIPS HEAP_OVERFLOW = "heap_overflow" STRING_SIZE = 12 VOID = "void" @@ -42,27 +40,27 @@ INPUT_STR_BUFFER = "input_str_buffer" BUFFER_SIZE = 1024 -#temporary registers +# temporary registers t0 = "$t0" t1 = "$t1" t2 = "$t2" t3 = "$t3" t4 = "$t4" t5 = "$t5" -t6 = "$t6" # convenios -t7 = "$t7" # convenios -t8 = "$t8" -t9 = "$t9" +t6 = "$t6" # convenios +t7 = "$t7" # convenios +t8 = "$t8" +t9 = "$t9" -#Arguments Registers +# Arguments Registers a0 = "$a0" a1 = "$a1" a2 = "$a2" a3 = "$a3" -#frame pointer +# frame pointer fp = "$fp" -#stack pointer +# stack pointer sp = "$sp" ra = "$ra" @@ -89,27 +87,29 @@ OBJECT = "Object" IO = "IO" + class MemoryManager: def __init__(self): - #self.all_reg = [t0,t1,t2,t3,t4,t5,t6,t7,t8,t9] - self.all_reg = [t0,t1,t2,t3,t4,t5,t9] - + # self.all_reg = [t0,t1,t2,t3,t4,t5,t6,t7,t8,t9] + self.all_reg = [t0, t1, t2, t3, t4, t5, t9] + self.used_reg = [] self.stored = [] - + def get_unused_reg(self): - unused = list(set(self.all_reg) - set(self.used_reg)) + list(set(self.used_reg) - set(self.all_reg)) - reg = random.choice(unused) + unused = list(set(self.all_reg) - set(self.used_reg)) + list( + set(self.used_reg) - set(self.all_reg) + ) + reg = random.choice(unused) self.used_reg.append(reg) return reg - + def clean(self): self.used_reg = self.stored self.stored = [] - + def save(self): self.stored = self.used_reg.copy() - class MIPSBuilder: @@ -124,70 +124,82 @@ def __init__(self): self.attr_offset = {} self.memo = MemoryManager() self.pushed_args = 0 - - def print(self,x): + + def print(self, x): self.memo.save() - self.register_instruction(mips.CommentNode,"------------Printeooooo") + self.register_instruction(mips.CommentNode, "------------Printeooooo") reg = self.memo.get_unused_reg() - self.register_instruction(mips.LoadInmediate,reg,x) - self.register_instruction(mips.MoveNode,a0,reg) - self.register_instruction(mips.LoadInmediate,v0,4) + self.register_instruction(mips.LoadInmediate, reg, x) + self.register_instruction(mips.MoveNode, a0, reg) + self.register_instruction(mips.LoadInmediate, v0, 4) self.register_instruction(mips.SyscallNode) - self.register_instruction(mips.CommentNode,"------------Fiiiin") - - - def get_offset(self,x): + self.register_instruction(mips.CommentNode, "------------Fiiiin") + + def get_offset(self, x): if x in self.locals: index = self.locals.index(x) - return 4*index + return 4 * index elif x in self.params: index = self.params.index(x) - return (4 * (-len(self.params)+index)) - + return 4 * (-len(self.params) + index) + def register_instruction(self, instruction_type, *args): instruction = instruction_type(*args) - self.current_procedure.instructions.append(instruction) - - def register_data(self,data_type,*args): + self.current_procedure.instructions.append(instruction) + + def register_data(self, data_type, *args): data = data_type(*args) self.data.append(data) - - + def register_push(self, reg): self.register_instruction(mips.StoreWordNode, reg, 0, sp) self.register_instruction(mips.AddiNode, sp, sp, 4) def register_pop(self, reg): self.register_instruction(mips.LoadWordNode, reg, 4, sp) - self.register_instruction(mips.AddiNode, sp, sp, 4) - + self.register_instruction(mips.AddiNode, sp, sp, 4) + def generate_exception_messages(self): - self.register_data(mips.DataTypeNode, '.asciiz',ABORT_SIGNAL, ['"Program execution aborted"']) - self.register_data(mips.DataTypeNode,'.asciiz', CASE_MISSMATCH, ['"Execution of a case statement without a matching branch"']) - self.register_data(mips.DataTypeNode,'.asciiz', CASE_VOID, ['"Case on void"']) - self.register_data(mips.DataTypeNode,'.asciiz', DISPATCH_VOID, ['"Dispatch on void"']) - self.register_data(mips.DataTypeNode,'.asciiz', ZERO_DIVISION, ['"Division by zero"']) - self.register_data(mips.DataTypeNode,'.asciiz', SUBSTR_OUT_RANGE, ['"Substring out of range"']) - self.register_data(mips.DataTypeNode,'.asciiz', HEAP_OVERFLOW, ['"Heap overflow"']) - + self.register_data( + mips.DataTypeNode, ".asciiz", ABORT_SIGNAL, ['"Program execution aborted"'] + ) + self.register_data( + mips.DataTypeNode, + ".asciiz", + CASE_MISSMATCH, + ['"Execution of a case statement without a matching branch"'], + ) + self.register_data(mips.DataTypeNode, ".asciiz", CASE_VOID, ['"Case on void"']) + self.register_data( + mips.DataTypeNode, ".asciiz", DISPATCH_VOID, ['"Dispatch on void"'] + ) + self.register_data( + mips.DataTypeNode, ".asciiz", ZERO_DIVISION, ['"Division by zero"'] + ) + self.register_data( + mips.DataTypeNode, ".asciiz", SUBSTR_OUT_RANGE, ['"Substring out of range"'] + ) + self.register_data( + mips.DataTypeNode, ".asciiz", HEAP_OVERFLOW, ['"Heap overflow"'] + ) + def generate_extra_static_labels(self): - self.register_data(mips.DataTypeNode, '.word',VOID, [-1]) - self.register_data(mips.DataTypeNode,'.asciiz', EMPTY_STRING, ['""']) - self.register_data(mips.DataTypeNode, '.space',INPUT_STR_BUFFER, [BUFFER_SIZE]) - - - def generate_attr_offset(self,type): + self.register_data(mips.DataTypeNode, ".word", VOID, [-1]) + self.register_data(mips.DataTypeNode, ".asciiz", EMPTY_STRING, ['""']) + self.register_data(mips.DataTypeNode, ".space", INPUT_STR_BUFFER, [BUFFER_SIZE]) + + def generate_attr_offset(self, type): attributes = self.types[type].attributes - self.attr_offset[type]={} - for i,attr in enumerate(attributes): - self.attr_offset[type][attr] = 4*(i+1) - + self.attr_offset[type] = {} + for i, attr in enumerate(attributes): + self.attr_offset[type][attr] = 4 * (i + 1) + def generate_str_length(self): - #calculates the length of the null-terminated char array referenced by $a0 and stores it in $a0 + # calculates the length of the null-terminated char array referenced by $a0 and stores it in $a0 self.memo.save() reg1 = self.memo.get_unused_reg() reg2 = self.memo.get_unused_reg() - + self.current_procedure = mips.ProcedureNode(LENGTH) self.register_instruction(mips.LoadInmediate, reg1, 0) @@ -205,9 +217,9 @@ def generate_str_length(self): self.register_instruction(mips.Jump, ra) self.text.append(self.current_procedure) - + def generate_copy(self): - #copies from t1 to t6 a0 bytes + # copies from t1 to t6 a0 bytes self.memo.save() self.current_procedure = mips.ProcedureNode(COPY) @@ -224,441 +236,415 @@ def generate_copy(self): self.register_instruction(mips.Jump, ra) self.text.append(self.current_procedure) - + def generate_auxiliar_procedures(self): self.generate_str_length() self.generate_copy() - - - - - + @visitor.on("node") def visit(self, node=None): pass - + @visitor.when(cil.ProgramNode) def visit(self, node): for type in node.dottypes: self.visit(type) self.generate_attr_offset(type.name) - + self.generate_extra_static_labels() self.generate_exception_messages() - + self.generate_auxiliar_procedures() - + for str_data in node.dotdata: self.visit(str_data) - + for instruction in node.dotcode: self.visit(instruction) - - - return mips.ProgramNode(self.data,self.text) - + + return mips.ProgramNode(self.data, self.text) @visitor.when(cil.TypeNode) def visit(self, node): self.types[node.name] = node if node.name == "Main": - self.main_size = (len(node.attributes)+1)*4 + self.main_size = (len(node.attributes) + 1) * 4 values = [] for func in node.methods: values.append(func[1]) - - self.register_data(mips.DataTypeNode,'.word',node.name,values) - self.register_data(mips.DataTypeNode, '.asciiz',f'{node.name}_cname', [f'"{node.name}"']) - - + + self.register_data(mips.DataTypeNode, ".word", node.name, values) + self.register_data( + mips.DataTypeNode, ".asciiz", f"{node.name}_cname", [f'"{node.name}"'] + ) + @visitor.when(cil.DataNode) def visit(self, node): - self.register_data(mips.DataTypeNode,'.asciiz',node.name,[f'"{node.value}"']) + self.register_data(mips.DataTypeNode, ".asciiz", node.name, [f'"{node.value}"']) - - @visitor.when(cil.ParamNode) - def visit(self,node): + def visit(self, node): self.memo.save() reg = self.memo.get_unused_reg() - + self.params.append(node.name) - - self.register_instruction(mips.LoadInmediate,reg,node.name) - self.register_instruction(mips.StoreWordNode,reg,len(self.params)*4,fp) - + + self.register_instruction(mips.LoadInmediate, reg, node.name) + self.register_instruction(mips.StoreWordNode, reg, len(self.params) * 4, fp) + self.memo.clean() - - - @visitor.when(cil.ArgNode) - def visit(self,node): + + @visitor.when(cil.ArgNode) + def visit(self, node): self.memo.save() - self.register_instruction(mips.CommentNode,f"Receiving Arg {node.name}") + self.register_instruction(mips.CommentNode, f"Receiving Arg {node.name}") reg = self.memo.get_unused_reg() - + offset = self.get_offset(node.name) - self.register_instruction(mips.LoadWordNode,reg,offset,fp) + self.register_instruction(mips.LoadWordNode, reg, offset, fp) self.register_push(reg) self.pushed_args += 1 - + self.memo.clean() - - - + @visitor.when(cil.FunctionNode) - def visit(self,node): + def visit(self, node): self.memo.save() locals_save = self.locals params_save = self.params self.locals, self.params = [], [] self.current_procedure = mips.ProcedureNode(node.name) - + saved_fp = self.memo.get_unused_reg() self.register_instruction(mips.MoveNode, saved_fp, fp) - - self.register_instruction(mips.CommentNode,"New $fp") + + self.register_instruction(mips.CommentNode, "New $fp") self.register_instruction(mips.MoveNode, fp, sp) - - self.register_instruction(mips.CommentNode,"Reserving space for locals") - self.register_instruction(mips.AddiNode, sp, sp, 4*len(node.localvars)) - self.register_instruction(mips.CommentNode,"Pushing $ra") + self.register_instruction(mips.CommentNode, "Reserving space for locals") + self.register_instruction(mips.AddiNode, sp, sp, 4 * len(node.localvars)) + + self.register_instruction(mips.CommentNode, "Pushing $ra") self.register_push(ra) - self.register_instruction(mips.CommentNode,"Saving $fp") + self.register_instruction(mips.CommentNode, "Saving $fp") self.register_push(saved_fp) - self.memo.clean() + self.memo.clean() for local in node.localvars: self.locals.append(local.name) - + for param in node.params: self.params.append(param.name) - self.register_instruction(mips.CommentNode,"Executing instructions") + self.register_instruction(mips.CommentNode, "Executing instructions") for inst in node.instructions: self.visit(inst) - - self.text.append(self.current_procedure) self.locals = locals_save - self.params = params_save - + self.params = params_save + @visitor.when(cil.LoadNode) def visit(self, node: cil.LoadNode): self.memo.save() - self.register_instruction(mips.CommentNode,"Executing Load") + self.register_instruction(mips.CommentNode, "Executing Load") _size = STRING_SIZE - self.register_instruction(mips.LoadInmediate,v0,SYSCALL_SBRK) - self.register_instruction(mips.LoadInmediate,a0,_size) + self.register_instruction(mips.LoadInmediate, v0, SYSCALL_SBRK) + self.register_instruction(mips.LoadInmediate, a0, _size) self.register_instruction(mips.SyscallNode) - + dest_offset = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode,v0,dest_offset,fp) + self.register_instruction(mips.StoreWordNode, v0, dest_offset, fp) reg = self.memo.get_unused_reg() - self.register_instruction(mips.LoadAddress,reg,STRING) - self.register_instruction(mips.StoreWordNode,reg,0,v0) + self.register_instruction(mips.LoadAddress, reg, STRING) + self.register_instruction(mips.StoreWordNode, reg, 0, v0) - #storing string length + # storing string length self.register_instruction(mips.LoadInmediate, reg, len(node.msg.data)) self.register_instruction(mips.StoreWordNode, reg, LENGTH_ATTR_OFFSET, v0) - #storing string chars ref + # storing string chars ref self.register_instruction(mips.LoadAddress, reg, node.msg.name) self.register_instruction(mips.StoreWordNode, reg, CHARS_ATTR_OFFSET, v0) self.memo.clean() - + @visitor.when(cil.LengthNode) def visit(self, node): - self.register_instruction(mips.CommentNode,"Executing Length") + self.register_instruction(mips.CommentNode, "Executing Length") self.memo.save() reg = self.memo.get_unused_reg() source_offset = self.get_offset(node.source) - self.register_instruction(mips.LoadWordNode, reg,source_offset,fp) + self.register_instruction(mips.LoadWordNode, reg, source_offset, fp) self.register_instruction(mips.LoadWordNode, reg, LENGTH_ATTR_OFFSET, reg) dest_offset = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode, reg,dest_offset, fp) - - - #All return value is saved in register a1 + self.register_instruction(mips.StoreWordNode, reg, dest_offset, fp) + + # All return value is saved in register a1 @visitor.when(cil.ReturnNode) - def visit(self,node): - self.register_instruction(mips.CommentNode,"Executing Return") - if isinstance(node.value,int): - self.register_instruction(mips.LoadInmediate,a1,node.value) - else: + def visit(self, node): + self.register_instruction(mips.CommentNode, "Executing Return") + if isinstance(node.value, int): + self.register_instruction(mips.LoadInmediate, a1, node.value) + else: offset = self.get_offset(node.value) - self.register_instruction(mips.LoadWordNode,a1,offset,fp) - - self.register_instruction(mips.CommentNode,"Restoring saved $fp") - self.register_instruction(mips.AddiNode,sp,sp,-4) - self.register_instruction(mips.LoadWordNode,fp,0,sp) - - self.register_instruction(mips.CommentNode,"Restoring saved $ra") - self.register_instruction(mips.AddiNode,sp,sp,-4) - self.register_instruction(mips.LoadWordNode,ra,0,sp) - - - AR = -4*(len(self.locals)) - - self.register_instruction(mips.CommentNode,"Cleaning stack after call") + self.register_instruction(mips.LoadWordNode, a1, offset, fp) + + self.register_instruction(mips.CommentNode, "Restoring saved $fp") + self.register_instruction(mips.AddiNode, sp, sp, -4) + self.register_instruction(mips.LoadWordNode, fp, 0, sp) + + self.register_instruction(mips.CommentNode, "Restoring saved $ra") + self.register_instruction(mips.AddiNode, sp, sp, -4) + self.register_instruction(mips.LoadWordNode, ra, 0, sp) + + AR = -4 * (len(self.locals)) + + self.register_instruction(mips.CommentNode, "Cleaning stack after call") self.register_instruction(mips.AddiNode, sp, sp, AR) - - self.register_instruction(mips.CommentNode,"Return jump") - self.register_instruction(mips.JumpRegister, ra) - - + + self.register_instruction(mips.CommentNode, "Return jump") + self.register_instruction(mips.JumpRegister, ra) + @visitor.when(cil.GotoNode) - def visit(self,node): - self.register_instruction(mips.CommentNode,"Executing Goto") - self.register_instruction(mips.Jump,node.label) - - - + def visit(self, node): + self.register_instruction(mips.CommentNode, "Executing Goto") + self.register_instruction(mips.Jump, node.label) + @visitor.when(cil.AllocateNode) - def visit(self,node): - self.register_instruction(mips.CommentNode,"Executing Allocate") + def visit(self, node): + self.register_instruction(mips.CommentNode, "Executing Allocate") self.memo.save() - _size = (len(self.types[node.type].attributes)+1)*4 - self.register_instruction(mips.LoadInmediate,v0,SYSCALL_SBRK) - self.register_instruction(mips.LoadInmediate,a0,_size) + _size = (len(self.types[node.type].attributes) + 1) * 4 + self.register_instruction(mips.LoadInmediate, v0, SYSCALL_SBRK) + self.register_instruction(mips.LoadInmediate, a0, _size) self.register_instruction(mips.SyscallNode) - + dest_offset = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode,v0,dest_offset,fp) - + self.register_instruction(mips.StoreWordNode, v0, dest_offset, fp) + reg = self.memo.get_unused_reg() - self.register_instruction(mips.LoadAddress,reg,node.type) - self.register_instruction(mips.StoreWordNode,reg,0,v0) + self.register_instruction(mips.LoadAddress, reg, node.type) + self.register_instruction(mips.StoreWordNode, reg, 0, v0) self.memo.clean() - + @visitor.when(cil.AssignNode) - def visit(self,node): - self.register_instruction(mips.CommentNode,"Executing Assign") + def visit(self, node): + self.register_instruction(mips.CommentNode, "Executing Assign") self.memo.save() - + reg = self.memo.get_unused_reg() - - if isinstance(node.source,int): - self.register_instruction(mips.LoadInmediate,reg,node.source) + + if isinstance(node.source, int): + self.register_instruction(mips.LoadInmediate, reg, node.source) else: source_offset = self.get_offset(node.source) - self.register_instruction(mips.LoadWordNode,reg,source_offset,fp) - + self.register_instruction(mips.LoadWordNode, reg, source_offset, fp) + dest_offset = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode,reg,dest_offset,fp) + self.register_instruction(mips.StoreWordNode, reg, dest_offset, fp) + + self.memo.clean() - self.memo.clean() - - @visitor.when(cil.RuntimeErrorNode) - def visit(self,node): - self.register_instruction(mips.CommentNode,"Executing RuntimeError") - self.register_instruction(mips.CommentNode,"Printing Abort Message") - self.register_instruction(mips.LoadAddress,a0,ABORT_SIGNAL) - self.register_instruction(mips.LoadInmediate,v0,SYSCALL_PRINT_STR) + def visit(self, node): + self.register_instruction(mips.CommentNode, "Executing RuntimeError") + self.register_instruction(mips.CommentNode, "Printing Abort Message") + self.register_instruction(mips.LoadAddress, a0, ABORT_SIGNAL) + self.register_instruction(mips.LoadInmediate, v0, SYSCALL_PRINT_STR) self.register_instruction(mips.SyscallNode) - - self.register_instruction(mips.CommentNode,"Aborting execution") - self.register_instruction(mips.LoadInmediate,v0,SYSCALL_EXIT) + + self.register_instruction(mips.CommentNode, "Aborting execution") + self.register_instruction(mips.LoadInmediate, v0, SYSCALL_EXIT) self.register_instruction(mips.SyscallNode) - - + @visitor.when(cil.StaticCallNode) - def visit(self,node): - self.register_instruction(mips.CommentNode,"Executing Static Call") - self.register_instruction(mips.JumpAndLink,node.function) - + def visit(self, node): + self.register_instruction(mips.CommentNode, "Executing Static Call") + self.register_instruction(mips.JumpAndLink, node.function) + dest_offset = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode,a1,dest_offset,fp) - self.register_instruction(mips.AddiNode,sp,sp,self.pushed_args * -4) + self.register_instruction(mips.StoreWordNode, a1, dest_offset, fp) + self.register_instruction(mips.AddiNode, sp, sp, self.pushed_args * -4) self.pushed_args = 0 - - + @visitor.when(cil.DynamicCallNode) - def visit(self,node): - #self.print(node.instance_type) + def visit(self, node): + # self.print(node.instance_type) self.memo.save() - self.register_instruction(mips.CommentNode,"Executing Dynamic Call") - + self.register_instruction(mips.CommentNode, "Executing Dynamic Call") + reg1 = self.memo.get_unused_reg() inst_offset = self.get_offset(node.instance_type) - self.register_instruction(mips.LoadWordNode,reg1,inst_offset,fp) - - #getting function + self.register_instruction(mips.LoadWordNode, reg1, inst_offset, fp) + + # getting function reg2 = self.memo.get_unused_reg() - self.register_instruction(mips.LoadWordNode,reg2,node.method_index*4,reg1) + self.register_instruction(mips.LoadWordNode, reg2, node.method_index * 4, reg1) + + self.register_instruction(mips.JumpRegister, reg2) - self.register_instruction(mips.JumpRegister,reg2) - - #putting the return vslue in destination + # putting the return vslue in destination dest_offset = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode,a1,dest_offset,fp) - self.register_instruction(mips.AddiNode,sp,sp,self.pushed_args * -4) + self.register_instruction(mips.StoreWordNode, a1, dest_offset, fp) + self.register_instruction(mips.AddiNode, sp, sp, self.pushed_args * -4) self.pushed_args = 0 self.memo.clean() - - - - - - + @visitor.when(cil.GetAttribNode) def visit(self, node): - self.register_instruction(mips.CommentNode,"Executing GetAttr") + self.register_instruction(mips.CommentNode, "Executing GetAttr") self.memo.save() reg1 = self.memo.get_unused_reg() reg2 = self.memo.get_unused_reg() - + instance_offset = self.get_offset(node.instance) - self.register_instruction(mips.LoadWordNode,reg1,instance_offset,fp) - + self.register_instruction(mips.LoadWordNode, reg1, instance_offset, fp) + attr_offs = self.attr_offset[node.type][node.attr] - self.register_instruction(mips.LoadWordNode,reg2,attr_offs,reg1) - + self.register_instruction(mips.LoadWordNode, reg2, attr_offs, reg1) + dest_offs = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode,reg2,dest_offs,fp) + self.register_instruction(mips.StoreWordNode, reg2, dest_offs, fp) self.memo.clean() - + @visitor.when(cil.SetAttribNode) def visit(self, node): - self.register_instruction(mips.CommentNode,"Executing SetAttr") + self.register_instruction(mips.CommentNode, "Executing SetAttr") self.memo.save() reg1 = self.memo.get_unused_reg() reg2 = self.memo.get_unused_reg() - + instance_offset = self.get_offset(node.instance) - self.register_instruction(mips.LoadWordNode,reg1,instance_offset,fp) - + self.register_instruction(mips.LoadWordNode, reg1, instance_offset, fp) + value_offset = self.get_offset(node.value) - self.register_instruction(mips.LoadWordNode,reg2,value_offset,fp) - + self.register_instruction(mips.LoadWordNode, reg2, value_offset, fp) + attr_os = self.attr_offset[node.type][node.attr] - self.register_instruction(mips.StoreWordNode,reg2,attr_os,reg1) + self.register_instruction(mips.StoreWordNode, reg2, attr_os, reg1) self.memo.clean() - + @visitor.when(cil.DefaultValueNode) - def visit(self,node): - self.register_instruction(mips.CommentNode,"Executing DefaultValue") + def visit(self, node): + self.register_instruction(mips.CommentNode, "Executing DefaultValue") self.memo.save() reg = self.memo.get_unused_reg() dest_offset = self.get_offset(node.dest) - if node.type in [INT,BOOL]: - self.register_instruction(mips.LoadInmediate,reg,0) - self.register_instruction(mips.StoreWordNode,reg,dest_offset,fp) + if node.type in [INT, BOOL]: + self.register_instruction(mips.LoadInmediate, reg, 0) + self.register_instruction(mips.StoreWordNode, reg, dest_offset, fp) elif node.type == STRING: _size = STRING_SIZE - self.register_instruction(mips.LoadInmediate,v0,SYSCALL_SBRK) - self.register_instruction(mips.LoadInmediate,a0,_size) + self.register_instruction(mips.LoadInmediate, v0, SYSCALL_SBRK) + self.register_instruction(mips.LoadInmediate, a0, _size) self.register_instruction(mips.SyscallNode) - self.register_instruction(mips.StoreWordNode,v0,dest_offset,fp) + self.register_instruction(mips.StoreWordNode, v0, dest_offset, fp) reg = self.memo.get_unused_reg() - self.register_instruction(mips.LoadAddress,reg,STRING) - self.register_instruction(mips.StoreWordNode,reg,0,v0) - - self.register_instruction(mips.LoadInmediate,reg,0) - self.register_instruction(mips.StoreWordNode, reg, LENGTH_ATTR_OFFSET, v0) #pq en vo esta el allocate + self.register_instruction(mips.LoadAddress, reg, STRING) + self.register_instruction(mips.StoreWordNode, reg, 0, v0) + + self.register_instruction(mips.LoadInmediate, reg, 0) + self.register_instruction( + mips.StoreWordNode, reg, LENGTH_ATTR_OFFSET, v0 + ) # pq en vo esta el allocate self.register_instruction(mips.LoadAddress, reg, EMPTY_STRING) self.register_instruction(mips.StoreWordNode, reg, CHARS_ATTR_OFFSET, v0) else: self.register_instruction(mips.LoadAddress, reg, VOID) self.register_instruction(mips.StoreWordNode, reg, dest_offset, fp) - + self.memo.clean() - - + @visitor.when(cil.PlusNode) - def visit(self,node): - self.register_instruction(mips.CommentNode,"Executing Plus Operation") + def visit(self, node): + self.register_instruction(mips.CommentNode, "Executing Plus Operation") self.memo.save() reg_l = self.memo.get_unused_reg() reg_r = self.memo.get_unused_reg() reg_dest = self.memo.get_unused_reg() - + left_offset = self.get_offset(node.left) right_offset = self.get_offset(node.right) - - self.register_instruction(mips.LoadWordNode,reg_l,left_offset,fp) - self.register_instruction(mips.LoadWordNode,reg_r,right_offset,fp) - - self.register_instruction(mips.AddNode,reg_dest,reg_l,reg_r) - + + self.register_instruction(mips.LoadWordNode, reg_l, left_offset, fp) + self.register_instruction(mips.LoadWordNode, reg_r, right_offset, fp) + + self.register_instruction(mips.AddNode, reg_dest, reg_l, reg_r) + offset = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode,reg_dest,offset,fp) - + self.register_instruction(mips.StoreWordNode, reg_dest, offset, fp) + self.memo.clean() - + @visitor.when(cil.MinusNode) - def visit(self,node): - self.register_instruction(mips.CommentNode,"Executing Minus Operation") + def visit(self, node): + self.register_instruction(mips.CommentNode, "Executing Minus Operation") self.memo.save() reg_l = self.memo.get_unused_reg() reg_r = self.memo.get_unused_reg() reg_dest = self.memo.get_unused_reg() - + left_offset = self.get_offset(node.left) right_offset = self.get_offset(node.right) - - self.register_instruction(mips.LoadWordNode,reg_l,left_offset,fp) - self.register_instruction(mips.LoadWordNode,reg_r,right_offset,fp) - - self.register_instruction(mips.SubNode,reg_dest,reg_l,reg_r) - + + self.register_instruction(mips.LoadWordNode, reg_l, left_offset, fp) + self.register_instruction(mips.LoadWordNode, reg_r, right_offset, fp) + + self.register_instruction(mips.SubNode, reg_dest, reg_l, reg_r) + offset = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode,reg_dest,offset,fp) - + self.register_instruction(mips.StoreWordNode, reg_dest, offset, fp) + self.memo.clean() - + @visitor.when(cil.StarNode) - def visit(self,node): - self.register_instruction(mips.CommentNode,"Executing Star Operation") + def visit(self, node): + self.register_instruction(mips.CommentNode, "Executing Star Operation") self.memo.save() reg1 = self.memo.get_unused_reg() reg2 = self.memo.get_unused_reg() - - + left_offset = self.get_offset(node.left) right_offset = self.get_offset(node.right) - - self.register_instruction(mips.LoadWordNode,reg1,left_offset,fp) - self.register_instruction(mips.LoadWordNode,reg2,right_offset,fp) - - self.register_instruction(mips.MultNode,reg1,reg2) - + + self.register_instruction(mips.LoadWordNode, reg1, left_offset, fp) + self.register_instruction(mips.LoadWordNode, reg2, right_offset, fp) + + self.register_instruction(mips.MultNode, reg1, reg2) + dest_offset = self.get_offset(node.dest) - self.register_instruction(mips.MoveFromLo,reg1) - self.register_instruction(mips.StoreWordNode,reg1,dest_offset,fp) - + self.register_instruction(mips.MoveFromLo, reg1) + self.register_instruction(mips.StoreWordNode, reg1, dest_offset, fp) + self.memo.clean() - + @visitor.when(cil.DivNode) - def visit(self,node): - self.register_instruction(mips.CommentNode,"Executing Div Operation") + def visit(self, node): + self.register_instruction(mips.CommentNode, "Executing Div Operation") self.memo.save() reg1 = self.memo.get_unused_reg() reg2 = self.memo.get_unused_reg() - - + left_offset = self.get_offset(node.left) right_offset = self.get_offset(node.right) - - self.register_instruction(mips.LoadWordNode,reg1,left_offset,fp) - self.register_instruction(mips.LoadWordNode,reg2,right_offset,fp) - - self.register_instruction(mips.DivideNode,reg1,reg2) - + + self.register_instruction(mips.LoadWordNode, reg1, left_offset, fp) + self.register_instruction(mips.LoadWordNode, reg2, right_offset, fp) + + self.register_instruction(mips.DivideNode, reg1, reg2) + dest_offset = self.get_offset(node.dest) - self.register_instruction(mips.MoveFromLo,reg1) - self.register_instruction(mips.StoreWordNode,reg1,dest_offset,fp) - + self.register_instruction(mips.MoveFromLo, reg1) + self.register_instruction(mips.StoreWordNode, reg1, dest_offset, fp) + self.memo.clean() - + @visitor.when(cil.IntComplementNode) - def visit(self,node): + def visit(self, node): self.memory_manager.save() source_offset = self.get_offset(node.source) @@ -667,154 +653,150 @@ def visit(self,node): reg1 = self.memo.get_unused_register() reg2 = self.memo.get_unused_register() - self.register_instruction(mips.LoadWordNode,reg1,source_offset,fp) - self.register_instruction(mips.NotNode,reg2,reg1) - self.register_instruction(mips.AddiNode,reg2,reg2,1) - self.register_instruction(mips.StoreWordNode,reg2,dest_offset,fp) + self.register_instruction(mips.LoadWordNode, reg1, source_offset, fp) + self.register_instruction(mips.NotNode, reg2, reg1) + self.register_instruction(mips.AddiNode, reg2, reg2, 1) + self.register_instruction(mips.StoreWordNode, reg2, dest_offset, fp) self.memo.clean() - - - #READSTRING + + # READSTRING @visitor.when(cil.ReadNode) - def visit(self,node): + def visit(self, node): self.memo.save() - self.register_instruction(mips.CommentNode,"ReadStrNode") - self.register_instruction(mips.CommentNode,"Reading String to buffer") + self.register_instruction(mips.CommentNode, "ReadStrNode") + self.register_instruction(mips.CommentNode, "Reading String to buffer") self.register_instruction(mips.LoadAddress, a0, INPUT_STR_BUFFER) self.register_instruction(mips.LoadInmediate, a1, BUFFER_SIZE) self.register_instruction(mips.LoadInmediate, v0, SYSCALL_READ_STR) self.register_instruction(mips.SyscallNode) - self.register_instruction(mips.CommentNode,"Saving reference to read string") + self.register_instruction(mips.CommentNode, "Saving reference to read string") reg1 = self.memo.get_unused_reg() - #if reg1 != t1: + # if reg1 != t1: # if t1 in self.memo.used_reg: # self.register_instruction(mips.MoveNode,reg1,t1) # else: # self.memo.clean() self.register_instruction(mips.MoveNode, t7, a0) - self.register_instruction(mips.CommentNode,"Calculating str length") + self.register_instruction(mips.CommentNode, "Calculating str length") self.register_instruction(mips.JumpAndLink, LENGTH) - - self.register_instruction(mips.CommentNode,"Allocating char array for new string") + self.register_instruction( + mips.CommentNode, "Allocating char array for new string" + ) self.register_instruction(mips.LoadInmediate, v0, SYSCALL_SBRK) self.register_instruction(mips.SyscallNode) self.register_instruction(mips.MoveNode, t6, v0) - + reg3 = self.memo.get_unused_reg() - self.register_instruction(mips.MoveNode, reg3, v0)#saving pointer to char array + self.register_instruction( + mips.MoveNode, reg3, v0 + ) # saving pointer to char array reg4 = self.memo.get_unused_reg() - #self.register_instruction(mips.AddNode, a0, a0, -1) - self.register_instruction(mips.MoveNode, reg4, a0)#saving length + # self.register_instruction(mips.AddNode, a0, a0, -1) + self.register_instruction(mips.MoveNode, reg4, a0) # saving length - self.register_instruction(mips.CommentNode,"Copying bytes from one char array to another") + self.register_instruction( + mips.CommentNode, "Copying bytes from one char array to another" + ) self.register_instruction(mips.JumpAndLink, COPY) - self.register_instruction(mips.CommentNode,"Null-terminating the string") + self.register_instruction(mips.CommentNode, "Null-terminating the string") self.register_instruction(mips.StoreByteNode, zero, 0, t6) - self.register_instruction(mips.CommentNode,"Allocating new String instance") + self.register_instruction(mips.CommentNode, "Allocating new String instance") _size = STRING_SIZE - self.register_instruction(mips.LoadInmediate,v0,SYSCALL_SBRK) - self.register_instruction(mips.LoadInmediate,a0,_size) + self.register_instruction(mips.LoadInmediate, v0, SYSCALL_SBRK) + self.register_instruction(mips.LoadInmediate, a0, _size) self.register_instruction(mips.SyscallNode) - + dest_offset = self.get_offset(node.dest) - self.register_instruction(mips.StoreWordNode,v0,dest_offset,fp) + self.register_instruction(mips.StoreWordNode, v0, dest_offset, fp) reg = self.memo.get_unused_reg() - self.register_instruction(mips.LoadAddress,reg,STRING) - self.register_instruction(mips.StoreWordNode,reg,0,v0) + self.register_instruction(mips.LoadAddress, reg, STRING) + self.register_instruction(mips.StoreWordNode, reg, 0, v0) - #storing string length - self.register_instruction(mips.CommentNode,"Storing length and reference to char array") + # storing string length + self.register_instruction( + mips.CommentNode, "Storing length and reference to char array" + ) self.register_instruction(mips.StoreWordNode, reg4, LENGTH_ATTR_OFFSET, v0) - #storing string chars ref + # storing string chars ref self.register_instruction(mips.StoreWordNode, reg3, CHARS_ATTR_OFFSET, v0) self.memo.clean() - + @visitor.when(cil.PrintStrNode) - def visit(self,node): - self.register_instruction(mips.CommentNode,"PrintStringNode") + def visit(self, node): + self.register_instruction(mips.CommentNode, "PrintStringNode") straddr_offset = self.get_offset(node.str_addr) self.register_instruction(mips.LoadWordNode, a0, straddr_offset, fp) self.register_instruction(mips.LoadWordNode, a0, CHARS_ATTR_OFFSET, a0) self.register_instruction(mips.LoadInmediate, v0, SYSCALL_PRINT_STR) self.register_instruction(mips.SyscallNode) - + @visitor.when(cil.PrintIntNode) - def visit(self,node): - self.register_instruction(mips.CommentNode,"PrintIntNode") - if isinstance(node.int_addr,int): - self.register_instruction(mips.LoadInmediate,a0,node.int_addr) + def visit(self, node): + self.register_instruction(mips.CommentNode, "PrintIntNode") + if isinstance(node.int_addr, int): + self.register_instruction(mips.LoadInmediate, a0, node.int_addr) else: int_offset = self.get_offset(node.int_addr) self.register_instruction(mips.LoadWordNode, a0, int_offset, fp) self.register_instruction(mips.LoadInmediate, v0, SYSCALL_PRINT_INT) self.register_instruction(mips.SyscallNode) - @visitor.when(cil.TypeOfNode) - def visit(self,node): + def visit(self, node): self.memo.save() obj_offset = self.get_offset(node.obj) dest_offset = self.get_offset(node.dest) - + reg1 = self.memo.get_unused_reg() - self.register_instruction(mips.CommentNode,"Executing typeof") + self.register_instruction(mips.CommentNode, "Executing typeof") self.register_instruction(mips.LoadWordNode, reg1, obj_offset, fp) self.register_instruction(mips.LoadWordNode, reg1, TYPEINFO_ATTR_OFFSET, reg1) self.register_instruction(mips.StoreWordNode, reg1, dest_offset, fp) self.memo.clean() - + @visitor.when(cil.ExitNode) - def visit(self,node): - self.register_instruction(mips.LoadInmediate,v0,SYSCALL_EXIT) + def visit(self, node): + self.register_instruction(mips.LoadInmediate, v0, SYSCALL_EXIT) self.register_instruction(mips.SyscallNode) - - - + @visitor.when(cil.CopyNode) - def visit(self,node): - pass - - @visitor.when(cil.TypeNameNode) - def visit(self,node): + def visit(self, node): pass - - - @visitor.when(cil.ToStrNode) - def visit(self,node): + + @visitor.when(cil.TypeNameNode) + def visit(self, node): pass - - + + # @visitor.when(cil.ToStrNode) + # def visit(self,node): + # pass + @visitor.when(cil.ConcatNode) - def visit(self,node): + def visit(self, node): pass + @visitor.when(cil.SubstringNode) - def visit(self,node): - pass - - @visitor.when(cil.PrefixNode) - def visit(self,node): + def visit(self, node): pass - + + # @visitor.when(cil.PrefixNode) + # def visit(self, node): + # pass + @visitor.when(cil.GotoIfNode) - def visit(self,node): + def visit(self, node): pass - - @visitor.when(cil.LocalNode) #No hace falta - def visit(self,node): + + @visitor.when(cil.LocalNode) # No hace falta + def visit(self, node): pass - - - - - - \ No newline at end of file From 688f9f45c249d78431afce3af49fccb71bd3a26c Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Tue, 8 Mar 2022 22:41:20 -0500 Subject: [PATCH 130/162] feat: update tests --- customized_tests/test_hello_world.cl | 20 ++++++++++++++------ tests/code_gen/string_methods _output.cl | 1 + tests/code_gen/string_methods.cl | 21 +++++++++++++++++++++ 3 files changed, 36 insertions(+), 6 deletions(-) create mode 100644 tests/code_gen/string_methods _output.cl create mode 100644 tests/code_gen/string_methods.cl diff --git a/customized_tests/test_hello_world.cl b/customized_tests/test_hello_world.cl index ad1bd0fdf..04c789999 100644 --- a/customized_tests/test_hello_world.cl +++ b/customized_tests/test_hello_world.cl @@ -162,17 +162,25 @@ class Point{ (* class Main inherits IO{ main (): Object { - self@IO.out_int((new Point)@Point.init(5, 6)) - + self.out_int((new Point).init(5, 6)) }; }; -class Point{ +class Point inherits Main{ x: Int; y: Int; - - init(x0: AUTO_TYPE, y0: AUTO_TYPE): AUTO_TYPE { - x0 + y0 + a: Point; + s: String; + + init(x0: AUTO_TYPE, y0: AUTO_TYPE): AUTO_TYPE {{ + a <- new Point; + s <- "Hello World"; + case a of + b: Int => x0 + y0; + d: String => s; + c: Main => new Main; + esac; + } }; }; *) diff --git a/tests/code_gen/string_methods _output.cl b/tests/code_gen/string_methods _output.cl new file mode 100644 index 000000000..42bc7029f --- /dev/null +++ b/tests/code_gen/string_methods _output.cl @@ -0,0 +1 @@ +First sentence.Second sentence.First sentence. \ No newline at end of file diff --git a/tests/code_gen/string_methods.cl b/tests/code_gen/string_methods.cl new file mode 100644 index 000000000..b6d7299fe --- /dev/null +++ b/tests/code_gen/string_methods.cl @@ -0,0 +1,21 @@ +class Main inherits IO{ + a : Int; + b : Int; + c : String <- "First sentence."; + d : String <- "Second sentence."; + main (): Object { + { + out_string(c.concat(d)); + out_string(c.substr(0, c.length())); + } + }; + x (): Object{ + 4 + }; +}; + +class A inherits Main{ + x () : Object{ + 3.copy() + }; +}; From 6aea015c7732206ea9bc7cf6369895737210a16b Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Tue, 8 Mar 2022 22:45:25 -0500 Subject: [PATCH 131/162] fix: discard changes in string_methods test --- tests/code_gen/string_methods.cl | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/tests/code_gen/string_methods.cl b/tests/code_gen/string_methods.cl index b6d7299fe..cdbbefa0c 100644 --- a/tests/code_gen/string_methods.cl +++ b/tests/code_gen/string_methods.cl @@ -1,3 +1,4 @@ + class Main inherits IO{ a : Int; b : Int; @@ -9,13 +10,4 @@ class Main inherits IO{ out_string(c.substr(0, c.length())); } }; - x (): Object{ - 4 - }; -}; - -class A inherits Main{ - x () : Object{ - 3.copy() - }; }; From 44707b04e28b96db979a1ee53ea3178f5ca3caab Mon Sep 17 00:00:00 2001 From: smartos99 Date: Tue, 8 Mar 2022 22:52:17 -0500 Subject: [PATCH 132/162] Add IsVoidNode --- src/cmp/cil.py | 13 ++++++++++--- src/code_gen/cil_builder.py | 7 ++++--- src/code_gen/mips_builder.py | 31 ++++++++++++++++++++++++++++--- 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/src/cmp/cil.py b/src/cmp/cil.py index 2b1723595..94f148e3e 100644 --- a/src/cmp/cil.py +++ b/src/cmp/cil.py @@ -203,10 +203,13 @@ def __init__(self, dest, source, index, length): self.length = length -class ReadNode(InstructionNode): +class ReadStringNode(InstructionNode): def __init__(self, dest): self.dest = dest +class ReadIntNode(InstructionNode): + def __init__(self, dest): + self.dest = dest class RuntimeErrorNode(InstructionNode): def __init__(self, signal): @@ -392,10 +395,14 @@ def visit(self, node): # def visit(self, node): # return f"{node.dest} = STR {node.ivalue}" - @visitor.when(ReadNode) + @visitor.when(ReadStringNode) def visit(self, node): - return f"{node.dest} = READ" + return f"{node.dest} = READ STR" + @visitor.when(ReadIntNode) + def visit(self, node): + return f"{node.dest} = READ INT" + @visitor.when(PrintStrNode) def visit(self, node): return f"PRINT STR{node.str_addr}" diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index a2cb95feb..ce87bfb6a 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -24,7 +24,8 @@ LengthNode, ConcatNode, SubstringNode, - ReadNode, + ReadStringNode, + ReadIntNode, PrintStrNode, PrintIntNode, PlusNode, @@ -324,13 +325,13 @@ def io_outint(self): def io_instring(self): self.params.append(ParamNode("self")) ret_vinfo = self.define_internal_local() - self.register_instruction(ReadNode(ret_vinfo)) + self.register_instruction(ReadStringNode(ret_vinfo)) self.register_instruction(ReturnNode(ret_vinfo)) def io_inint(self): self.params.append(ParamNode("self")) ret_vinfo = self.define_internal_local() - self.register_instruction(ReadNode(ret_vinfo)) # TODO: ReadInt? + self.register_instruction(ReadIntNode(ret_vinfo)) # TODO: ReadInt? self.register_instruction(ReturnNode(ret_vinfo)) def reset_state(self): diff --git a/src/code_gen/mips_builder.py b/src/code_gen/mips_builder.py index d9091d27c..2fa41e800 100644 --- a/src/code_gen/mips_builder.py +++ b/src/code_gen/mips_builder.py @@ -891,9 +891,17 @@ def visit(self, node): self.memo.clean() - - #READSTRING - @visitor.when(cil.ReadNode) + @visitor.when(cil.ReadIntNode) + def visit(self, node): + dest_off = self.get_offset(node.dest) + self.register_instruction(mips.CommentNode,"ReadIntNode") + self.register_instruction(mips.LoadInmediate, v0, SYSCALL_READ_INT) + self.register_instruction(mips.SyscallNode) + self.register_instruction(mips.StoreWordNode, v0, dest_off, fp) + + + + @visitor.when(cil.ReadStringNode) def visit(self,node): self.memo.save() self.register_instruction(mips.CommentNode,"ReadStrNode") @@ -995,6 +1003,23 @@ def visit(self,node): self.memo.clean() + @visitor.when(cil.IsVoidNode) + def visit(self, node): + self.register_instruction(mips.CommentNode,"Executing IsVoid") + self.memo.save() + reg1 = self.memo.get_unused_reg() + reg2 = self.memo.get_unused_reg() + source_off = self.get_offset(node.value) + dest_off = self.get_offset(node.dest) + + self.register_instruction(mips.LoadWordNode, reg1, source_off, fp) + self.register_instruction(mips.LoadAddress, reg2, VOID) + self.register_instruction(mips.SetEq, reg1, reg1, reg2) + + self.register_instruction(mips.StoreWordNode, reg1, dest_off, fp) + self.memo.clean() + + @visitor.when(cil.ExitNode) def visit(self,node): self.register_instruction(mips.LoadInmediate,v0,SYSCALL_EXIT) From ffffba0676250cf73d779ff4a01a77d361b35a9e Mon Sep 17 00:00:00 2001 From: smartos99 Date: Wed, 9 Mar 2022 00:34:32 -0500 Subject: [PATCH 133/162] Fix Conflicts --- src/cmp/cil.py | 2 +- src/code_gen/cil_builder.py | 9 +- src/code_gen/mips_builder.py | 2 +- tests/code_gen.py | 2 +- tests/code_gen/comparison.mips | 334 +++++++++++++++---------- tests/code_gen/hello_world.mips | 206 +++++++++------ tests/code_gen/point.mips | 260 +++++++++++-------- tests/code_gen/read_string.mips | 254 ++++++++++++------- tests/code_gen/string_methods.cl | 2 +- tests/code_gen/string_methods.mips | 389 +++++++++++++++++------------ tests/code_gen/test_goto_if.mips | 324 ++++++++++++++---------- tests/code_gen/unary_nodes.cl | 4 +- tests/code_gen/unary_nodes.mips | 329 ++++++++++++------------ tests/code_gen/while.mips | 347 ++++++++++++++----------- 14 files changed, 1452 insertions(+), 1012 deletions(-) diff --git a/src/cmp/cil.py b/src/cmp/cil.py index d108f9a40..e9a8200a7 100644 --- a/src/cmp/cil.py +++ b/src/cmp/cil.py @@ -417,7 +417,7 @@ def visit(self, node): @visitor.when(LoadNode) def visit(self, node): - return f"{node.dest} = LOAD {node.msg}" + return f"{node.dest} = LOAD {node.msg.name}" @visitor.when(ConcatNode) def visit(self, node): diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index e72b00072..cf80af71a 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -359,7 +359,14 @@ def object_type_name(self): self.register_instruction(AllocateNode("String", solve)) type_name = self.define_internal_local() self.register_instruction( - LoadNode(type_name, f"type_name_{self.current_type.name}") + LoadNode( + type_name, + VariableInfo( + f"type_name_{self.current_type.name}", + None, + False, + f"{self.current_type.name}") + ) ) self.register_instruction(AssignNode(solve, type_name)) self.register_instruction(ReturnNode(solve)) diff --git a/src/code_gen/mips_builder.py b/src/code_gen/mips_builder.py index 2d2b53cbb..89a6dc281 100644 --- a/src/code_gen/mips_builder.py +++ b/src/code_gen/mips_builder.py @@ -792,7 +792,7 @@ def visit(self, node): self.register_instruction(mips.JumpAndLink, COPY) self.register_instruction(mips.CommentNode,"Null-terminating the string") - self.register_instruction(mips.StoreByteNode, zero, 0, t0) + self.register_instruction(mips.StoreByteNode, zero, 0, t6) self.register_instruction(mips.CommentNode,"Allocating new String instance") dest_offset = self.get_offset(node.dest) diff --git a/tests/code_gen.py b/tests/code_gen.py index eee6e10e3..1fb167ad3 100644 --- a/tests/code_gen.py +++ b/tests/code_gen.py @@ -4,7 +4,7 @@ tests_dir = __file__.rpartition('/')[0] + '/code_gen/' -tests = [(file) for file in os.listdir(tests_dir) if file.endswith('unary_nodes.cl')] +tests = [(file) for file in os.listdir(tests_dir) if file.endswith('.cl')] # @pytest.mark.lexer # @pytest.mark.parser diff --git a/tests/code_gen/comparison.mips b/tests/code_gen/comparison.mips index 902e18b54..b387e1c2a 100644 --- a/tests/code_gen/comparison.mips +++ b/tests/code_gen/comparison.mips @@ -29,15 +29,15 @@ string_2 : .asciiz, "a<=b" .globl main length: - li $t1, 0 + li $t9, 0 length_loop: - lb $t3, 0($a0) - beq $zero, $t3, length_end - add $t1, $t1, 1 + lb $t2, 0($a0) + beq $zero, $t2, length_end + add $t9, $t9, 1 add $a0, $a0, 1 j length_loop length_end: - move $a0 $t1 + move $a0 $t9 j $ra copy: copy_loop: @@ -51,7 +51,7 @@ copy: copy_end: j $ra Object_abort: - move $t1 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -60,7 +60,7 @@ Object_abort: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing RuntimeError @@ -72,7 +72,7 @@ Object_abort: li $v0, 10 syscall Object_copy: - move $t3 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -81,7 +81,7 @@ Object_copy: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -122,7 +122,7 @@ Object_type_name: #Return jump jalr $ra IO_out_string: - move $t1 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -131,7 +131,7 @@ IO_out_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintStringNode @@ -181,7 +181,7 @@ IO_out_int: #Return jump jalr $ra IO_in_string: - move $t1 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -190,7 +190,7 @@ IO_in_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #ReadStrNode @@ -207,8 +207,8 @@ IO_in_string: li $v0, 9 syscall move $t6 $v0 - move $t2 $v0 - move $t0 $a0 + move $t1 $v0 + move $t5 $a0 #Copying bytes from one char array to another jal copy #Null-terminating the string @@ -218,11 +218,11 @@ IO_in_string: li $a0, 12 syscall sw $v0, 0($fp) - la $t3, String - sw $t3, 0($v0) + la $t0, String + sw $t0, 0($v0) #Storing length and reference to char array - sw $t0, 4($v0) - sw $t2, 8($v0) + sw $t5, 4($v0) + sw $t1, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -236,7 +236,7 @@ IO_in_string: #Return jump jalr $ra IO_in_int: - move $t0 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -245,7 +245,7 @@ IO_in_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #ReadStrNode @@ -263,7 +263,7 @@ IO_in_int: syscall move $t6 $v0 move $t5 $v0 - move $t4 $a0 + move $t0 $a0 #Copying bytes from one char array to another jal copy #Null-terminating the string @@ -273,10 +273,10 @@ IO_in_int: li $a0, 12 syscall sw $v0, 0($fp) - la $t0, String - sw $t0, 0($v0) + la $t9, String + sw $t9, 0($v0) #Storing length and reference to char array - sw $t4, 4($v0) + sw $t0, 4($v0) sw $t5, 8($v0) #Executing Return lw $a1, 0($fp) @@ -291,7 +291,7 @@ IO_in_int: #Return jump jalr $ra String_length: - move $t4 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -300,13 +300,13 @@ String_length: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Length - lw $t4, -4($fp) - lw $t4, 4($t4) - sw $t4, 0($fp) + lw $t0, -4($fp) + lw $t0, 4($t0) + sw $t0, 0($fp) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -320,7 +320,7 @@ String_length: #Return jump jalr $ra String_concat: - move $t5 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -329,9 +329,44 @@ String_concat: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t5, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions + #Loading length + lw $s1, -8($fp) + lw $s1, 4($s1) + lw $s2, -4($fp) + lw $s2, 4($s2) + add $t2, $s1, $s2 + #Allocating new char array + move $a0 $t2 + addi $a0, $a0, 1 + li $v0, 9 + syscall + move $t6 $v0 + move $t9 $v0 + #Copying bytes from first string + lw $t7, -8($fp) + lw $t7, 8($t7) + move $a0 $s1 + jal copy + #Copying bytes from second string + lw $t7, -4($fp) + lw $t7, 8($t7) + move $a0 $s2 + jal copy + #Null-terminating the string + sb $zero, 0($t6) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t5, String + sw $t5, 0($v0) + #Storing length and reference to char array + sw $t2, 4($v0) + sw $t9, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -345,7 +380,7 @@ String_concat: #Return jump jalr $ra String_substr: - move $t3 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -354,9 +389,38 @@ String_substr: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions + #Executing Substring + lw $s0, -4($fp) + move $a0 $s0 + addi $a0, $a0, 1 + li $v0, 9 + syscall + move $t6 $v0 + #Loading reference to char array of source string + lw $t7, -12($fp) + lw $t7, 8($t7) + lw $s2, -8($fp) + add $t7, $t7, $s2 + move $s1 $t6 + #Copying bytes from one char array to another + move $a0 $s0 + jal copy + #Null-terminating the string + sb $zero, 0($t0) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t9, String + sw $t9, 0($v0) + #Storing length and reference to char array + lw $s0, -4($fp) + sw $s0, 4($v0) + sw $s1, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -370,7 +434,7 @@ String_substr: #Return jump jalr $ra Object_constructor: - move $t1 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -379,7 +443,7 @@ Object_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -387,8 +451,8 @@ Object_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t5, Object - sw $t5, 0($v0) + la $t1, Object + sw $t1, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -402,7 +466,7 @@ Object_constructor: #Return jump jalr $ra IO_constructor: - move $t2 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -411,7 +475,7 @@ IO_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -419,8 +483,8 @@ IO_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t9, IO - sw $t9, 0($v0) + la $t1, IO + sw $t1, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -434,7 +498,7 @@ IO_constructor: #Return jump jalr $ra Int_constructor: - move $t4 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -443,7 +507,7 @@ Int_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -466,7 +530,7 @@ Int_constructor: #Return jump jalr $ra Bool_constructor: - move $t0 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -475,7 +539,7 @@ Bool_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -483,8 +547,8 @@ Bool_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t9, Bool - sw $t9, 0($v0) + la $t2, Bool + sw $t2, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -498,7 +562,7 @@ Bool_constructor: #Return jump jalr $ra String_constructor: - move $t5 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -507,7 +571,7 @@ String_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t5, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -515,8 +579,8 @@ String_constructor: li $a0, 12 syscall sw $v0, 0($fp) - la $t1, String - sw $t1, 0($v0) + la $t4, String + sw $t4, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -530,7 +594,7 @@ String_constructor: #Return jump jalr $ra main: - move $t3 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -539,7 +603,7 @@ main: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Static Call @@ -547,8 +611,8 @@ main: sw $a1, 0($fp) addi $sp, $sp, 0 #Receiving Arg local_main_internal_0 - lw $t3, 0($fp) - sw $t3, 0($sp) + lw $t5, 0($fp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing Static Call jal Main_main @@ -557,7 +621,7 @@ main: li $v0, 10 syscall Main_constructor: - move $t2 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -566,7 +630,7 @@ Main_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -574,22 +638,22 @@ Main_constructor: li $a0, 12 syscall sw $v0, 0($fp) - la $t9, Main - sw $t9, 0($v0) + la $t3, Main + sw $t3, 0($v0) #Executing DefaultValue li $t2, 0 sw $t2, 4($fp) #Executing SetAttr - lw $t9, 0($fp) - lw $t3, 4($fp) - sw $t3, 4($t9) + lw $t5, 0($fp) + lw $t0, 4($fp) + sw $t0, 4($t5) #Executing DefaultValue - li $t5, 0 - sw $t5, 8($fp) + li $t3, 0 + sw $t3, 8($fp) #Executing SetAttr - lw $t2, 0($fp) - lw $t3, 8($fp) - sw $t3, 8($t2) + lw $t0, 0($fp) + lw $t5, 8($fp) + sw $t5, 8($t0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -603,7 +667,7 @@ Main_constructor: #Return jump jalr $ra Main_main: - move $t3 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -612,77 +676,81 @@ Main_main: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing GetAttr - lw $t1, -4($fp) - lw $t5, 4($t1) - sw $t5, 4($fp) + lw $t3, -4($fp) + lw $t4, 4($t3) + sw $t4, 4($fp) #Executing GetAttr - lw $t9, -4($fp) - lw $t4, 8($t9) - sw $t4, 8($fp) - lw $t2, 4($fp) - lw $t4, 8($fp) - slt $t0, $t2, $t4 - sw $t0, 0($fp) + lw $t4, -4($fp) + lw $t5, 8($t4) + sw $t5, 8($fp) + #Executing Less Operation + lw $t1, 4($fp) + lw $t5, 8($fp) + slt $t3, $t1, $t5 + sw $t3, 0($fp) #Executing GetAttr - lw $t9, -4($fp) - lw $t2, 4($t9) - sw $t2, 12($fp) + lw $t2, -4($fp) + lw $t4, 4($t2) + sw $t4, 12($fp) #Executing GetAttr - lw $t4, -4($fp) - lw $t1, 8($t4) - sw $t1, 16($fp) - lw $t0, 12($fp) - lw $t3, 16($fp) - sle $t2, $t0, $t3 - sw $t2, 0($fp) + lw $t0, -4($fp) + lw $t5, 8($t0) + sw $t5, 16($fp) + #Executing Less Equal Operation + lw $t3, 12($fp) + lw $t5, 16($fp) + sle $t1, $t3, $t5 + sw $t1, 0($fp) #Executing GetAttr - lw $t9, -4($fp) - lw $t1, 4($t9) - sw $t1, 20($fp) + lw $t2, -4($fp) + lw $t4, 4($t2) + sw $t4, 20($fp) #Executing GetAttr lw $t0, -4($fp) - lw $t3, 8($t0) - sw $t3, 24($fp) - lw $t9, 20($fp) + lw $t2, 8($t0) + sw $t2, 24($fp) + #Executing Equal Operation + lw $t3, 20($fp) lw $t1, 24($fp) - seq $t3, $t9, $t1 - sw $t3, 0($fp) + seq $t4, $t3, $t1 + sw $t4, 0($fp) #Executing Assign - lw $t5, -4($fp) - sw $t5, 28($fp) + lw $t2, -4($fp) + sw $t2, 28($fp) #Executing typeof - lw $t1, 28($fp) - lw $t1, 0($t1) - sw $t1, 32($fp) + lw $t2, 28($fp) + lw $t2, 0($t2) + sw $t2, 32($fp) #Executing GetAttr - lw $t9, -4($fp) - lw $t4, 4($t9) - sw $t4, 44($fp) + lw $t0, -4($fp) + lw $t5, 4($t0) + sw $t5, 44($fp) #Executing GetAttr - lw $t2, -4($fp) - lw $t1, 8($t2) - sw $t1, 48($fp) - lw $t5, 44($fp) + lw $t5, -4($fp) + lw $t0, 8($t5) + sw $t0, 48($fp) + #Executing Less Equal Operation + lw $t0, 44($fp) lw $t4, 48($fp) - sle $t0, $t5, $t4 - sw $t0, 40($fp) - lw $t1, 40($fp) - bnez $t1, THEN_1 + sle $t1, $t0, $t4 + sw $t1, 40($fp) + lw $t2, 40($fp) + bnez $t2, THEN_1 #Executing Load li $v0, 9 li $a0, 12 syscall sw $v0, 36($fp) - la $t1, String - sw $t1, 0($v0) - li $t1, 3 - sw $t1, 4($v0) - la $t1, string_1 - sw $t1, 8($v0) + la $t2, String + sw $t2, 0($v0) + li $t2, 3 + sw $t2, 4($v0) + la $t2, string_1 + sw $t2, 8($v0) #Executing Goto j END_IF_2 THEN_1: @@ -691,25 +759,25 @@ Main_main: li $a0, 12 syscall sw $v0, 36($fp) - la $t0, String - sw $t0, 0($v0) - li $t0, 4 - sw $t0, 4($v0) - la $t0, string_2 - sw $t0, 8($v0) + la $t2, String + sw $t2, 0($v0) + li $t2, 4 + sw $t2, 4($v0) + la $t2, string_2 + sw $t2, 8($v0) END_IF_2: #Receiving Arg local_Main_main_internal_7 - lw $t3, 28($fp) - sw $t3, 0($sp) + lw $t5, 28($fp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Receiving Arg local_Main_main_internal_9 - lw $t3, 36($fp) - sw $t3, 0($sp) + lw $t2, 36($fp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing Dynamic Call - lw $t9, 32($fp) - lw $t5, 12($t9) - jalr $t5 + lw $t2, 32($fp) + lw $t1, 12($t2) + jalr $t1 sw $a1, 0($fp) addi $sp, $sp, -8 #Executing Return diff --git a/tests/code_gen/hello_world.mips b/tests/code_gen/hello_world.mips index 96e71fc6e..1bb10b206 100644 --- a/tests/code_gen/hello_world.mips +++ b/tests/code_gen/hello_world.mips @@ -30,8 +30,8 @@ string_1 : .asciiz, "Hello, World.\n" length: li $t9, 0 length_loop: - lb $t5, 0($a0) - beq $zero, $t5, length_end + lb $t0, 0($a0) + beq $zero, $t0, length_end add $t9, $t9, 1 add $a0, $a0, 1 j length_loop @@ -71,7 +71,7 @@ Object_abort: li $v0, 10 syscall Object_copy: - move $t4 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -80,7 +80,7 @@ Object_copy: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -96,7 +96,7 @@ Object_copy: #Return jump jalr $ra Object_type_name: - move $t9 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -105,7 +105,7 @@ Object_type_name: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -121,7 +121,7 @@ Object_type_name: #Return jump jalr $ra IO_out_string: - move $t9 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -130,7 +130,7 @@ IO_out_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintStringNode @@ -151,7 +151,7 @@ IO_out_string: #Return jump jalr $ra IO_out_int: - move $t9 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -160,7 +160,7 @@ IO_out_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintIntNode @@ -206,7 +206,7 @@ IO_in_string: li $v0, 9 syscall move $t6 $v0 - move $t2 $v0 + move $t1 $v0 move $t0 $a0 #Copying bytes from one char array to another jal copy @@ -221,7 +221,7 @@ IO_in_string: sw $t9, 0($v0) #Storing length and reference to char array sw $t0, 4($v0) - sw $t2, 8($v0) + sw $t1, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -235,7 +235,7 @@ IO_in_string: #Return jump jalr $ra IO_in_int: - move $t4 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -244,7 +244,7 @@ IO_in_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #ReadStrNode @@ -261,8 +261,8 @@ IO_in_int: li $v0, 9 syscall move $t6 $v0 - move $t3 $v0 - move $t9 $a0 + move $t1 $v0 + move $t2 $a0 #Copying bytes from one char array to another jal copy #Null-terminating the string @@ -272,11 +272,11 @@ IO_in_int: li $a0, 12 syscall sw $v0, 0($fp) - la $t0, String - sw $t0, 0($v0) + la $t3, String + sw $t3, 0($v0) #Storing length and reference to char array - sw $t9, 4($v0) - sw $t3, 8($v0) + sw $t2, 4($v0) + sw $t1, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -290,7 +290,7 @@ IO_in_int: #Return jump jalr $ra String_length: - move $t5 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -299,13 +299,13 @@ String_length: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t5, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Length - lw $t5, -4($fp) - lw $t5, 4($t5) - sw $t5, 0($fp) + lw $t2, -4($fp) + lw $t2, 4($t2) + sw $t2, 0($fp) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -319,7 +319,7 @@ String_length: #Return jump jalr $ra String_concat: - move $t9 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -328,9 +328,44 @@ String_concat: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions + #Loading length + lw $s1, -8($fp) + lw $s1, 4($s1) + lw $s2, -4($fp) + lw $s2, 4($s2) + add $t2, $s1, $s2 + #Allocating new char array + move $a0 $t2 + addi $a0, $a0, 1 + li $v0, 9 + syscall + move $t6 $v0 + move $t1 $v0 + #Copying bytes from first string + lw $t7, -8($fp) + lw $t7, 8($t7) + move $a0 $s1 + jal copy + #Copying bytes from second string + lw $t7, -4($fp) + lw $t7, 8($t7) + move $a0 $s2 + jal copy + #Null-terminating the string + sb $zero, 0($t6) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t0, String + sw $t0, 0($v0) + #Storing length and reference to char array + sw $t2, 4($v0) + sw $t1, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -356,6 +391,35 @@ String_substr: sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions + #Executing Substring + lw $s0, -4($fp) + move $a0 $s0 + addi $a0, $a0, 1 + li $v0, 9 + syscall + move $t6 $v0 + #Loading reference to char array of source string + lw $t7, -12($fp) + lw $t7, 8($t7) + lw $s2, -8($fp) + add $t7, $t7, $s2 + move $s1 $t6 + #Copying bytes from one char array to another + move $a0 $s0 + jal copy + #Null-terminating the string + sb $zero, 0($t0) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t9, String + sw $t9, 0($v0) + #Storing length and reference to char array + lw $s0, -4($fp) + sw $s0, 4($v0) + sw $s1, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -369,7 +433,7 @@ String_substr: #Return jump jalr $ra Object_constructor: - move $t0 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -378,7 +442,7 @@ Object_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -386,8 +450,8 @@ Object_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t4, Object - sw $t4, 0($v0) + la $t2, Object + sw $t2, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -401,7 +465,7 @@ Object_constructor: #Return jump jalr $ra IO_constructor: - move $t3 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -410,7 +474,7 @@ IO_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -433,7 +497,7 @@ IO_constructor: #Return jump jalr $ra Int_constructor: - move $t0 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -442,7 +506,7 @@ Int_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -450,8 +514,8 @@ Int_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t9, Int - sw $t9, 0($v0) + la $t3, Int + sw $t3, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -465,7 +529,7 @@ Int_constructor: #Return jump jalr $ra Bool_constructor: - move $t1 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -474,7 +538,7 @@ Bool_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -482,8 +546,8 @@ Bool_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t5, Bool - sw $t5, 0($v0) + la $t2, Bool + sw $t2, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -497,7 +561,7 @@ Bool_constructor: #Return jump jalr $ra String_constructor: - move $t2 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -506,7 +570,7 @@ String_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -514,8 +578,8 @@ String_constructor: li $a0, 12 syscall sw $v0, 0($fp) - la $t9, String - sw $t9, 0($v0) + la $t1, String + sw $t1, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -529,7 +593,7 @@ String_constructor: #Return jump jalr $ra main: - move $t1 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -538,7 +602,7 @@ main: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Static Call @@ -546,8 +610,8 @@ main: sw $a1, 0($fp) addi $sp, $sp, 0 #Receiving Arg local_main_internal_0 - lw $t0, 0($fp) - sw $t0, 0($sp) + lw $t1, 0($fp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing Static Call jal Main_main @@ -556,7 +620,7 @@ main: li $v0, 10 syscall Main_constructor: - move $t0 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -565,7 +629,7 @@ Main_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -588,7 +652,7 @@ Main_constructor: #Return jump jalr $ra Main_main: - move $t1 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -597,39 +661,39 @@ Main_main: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Assign - lw $t9, -4($fp) - sw $t9, 4($fp) + lw $t2, -4($fp) + sw $t2, 4($fp) #Executing typeof - lw $t9, 4($fp) - lw $t9, 0($t9) - sw $t9, 8($fp) + lw $t2, 4($fp) + lw $t2, 0($t2) + sw $t2, 8($fp) #Executing Load li $v0, 9 li $a0, 12 syscall sw $v0, 12($fp) - la $t0, String - sw $t0, 0($v0) - li $t0, 15 - sw $t0, 4($v0) - la $t0, string_1 - sw $t0, 8($v0) + la $t5, String + sw $t5, 0($v0) + li $t5, 15 + sw $t5, 4($v0) + la $t5, string_1 + sw $t5, 8($v0) #Receiving Arg local_Main_main_internal_1 - lw $t3, 4($fp) - sw $t3, 0($sp) + lw $t1, 4($fp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Receiving Arg local_Main_main_internal_3 - lw $t3, 12($fp) - sw $t3, 0($sp) + lw $t5, 12($fp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing Dynamic Call - lw $t9, 8($fp) - lw $t1, 12($t9) - jalr $t1 + lw $t0, 8($fp) + lw $t2, 12($t0) + jalr $t2 sw $a1, 0($fp) addi $sp, $sp, -8 #Executing Return diff --git a/tests/code_gen/point.mips b/tests/code_gen/point.mips index 950c9a7a0..d4f4676de 100644 --- a/tests/code_gen/point.mips +++ b/tests/code_gen/point.mips @@ -72,7 +72,7 @@ Object_abort: li $v0, 10 syscall Object_copy: - move $t0 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -81,7 +81,7 @@ Object_copy: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -97,7 +97,7 @@ Object_copy: #Return jump jalr $ra Object_type_name: - move $t9 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -106,7 +106,7 @@ Object_type_name: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -152,7 +152,7 @@ IO_out_string: #Return jump jalr $ra IO_out_int: - move $t3 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -161,7 +161,7 @@ IO_out_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintIntNode @@ -181,7 +181,7 @@ IO_out_int: #Return jump jalr $ra IO_in_string: - move $t0 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -190,7 +190,7 @@ IO_in_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #ReadStrNode @@ -207,8 +207,8 @@ IO_in_string: li $v0, 9 syscall move $t6 $v0 - move $t2 $v0 - move $t0 $a0 + move $t0 $v0 + move $t4 $a0 #Copying bytes from one char array to another jal copy #Null-terminating the string @@ -218,11 +218,11 @@ IO_in_string: li $a0, 12 syscall sw $v0, 0($fp) - la $t1, String - sw $t1, 0($v0) + la $t3, String + sw $t3, 0($v0) #Storing length and reference to char array - sw $t0, 4($v0) - sw $t2, 8($v0) + sw $t4, 4($v0) + sw $t0, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -236,7 +236,7 @@ IO_in_string: #Return jump jalr $ra IO_in_int: - move $t1 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -245,7 +245,7 @@ IO_in_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #ReadStrNode @@ -262,8 +262,8 @@ IO_in_int: li $v0, 9 syscall move $t6 $v0 - move $t0 $v0 - move $t2 $a0 + move $t5 $v0 + move $t0 $a0 #Copying bytes from one char array to another jal copy #Null-terminating the string @@ -273,11 +273,11 @@ IO_in_int: li $a0, 12 syscall sw $v0, 0($fp) - la $t5, String - sw $t5, 0($v0) + la $t1, String + sw $t1, 0($v0) #Storing length and reference to char array - sw $t2, 4($v0) - sw $t0, 8($v0) + sw $t0, 4($v0) + sw $t5, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -291,7 +291,7 @@ IO_in_int: #Return jump jalr $ra String_length: - move $t2 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -300,13 +300,13 @@ String_length: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Length - lw $t4, -4($fp) - lw $t4, 4($t4) - sw $t4, 0($fp) + lw $t3, -4($fp) + lw $t3, 4($t3) + sw $t3, 0($fp) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -320,7 +320,7 @@ String_length: #Return jump jalr $ra String_concat: - move $t2 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -329,9 +329,44 @@ String_concat: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions + #Loading length + lw $s1, -8($fp) + lw $s1, 4($s1) + lw $s2, -4($fp) + lw $s2, 4($s2) + add $t9, $s1, $s2 + #Allocating new char array + move $a0 $t9 + addi $a0, $a0, 1 + li $v0, 9 + syscall + move $t6 $v0 + move $t4 $v0 + #Copying bytes from first string + lw $t7, -8($fp) + lw $t7, 8($t7) + move $a0 $s1 + jal copy + #Copying bytes from second string + lw $t7, -4($fp) + lw $t7, 8($t7) + move $a0 $s2 + jal copy + #Null-terminating the string + sb $zero, 0($t6) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t2, String + sw $t2, 0($v0) + #Storing length and reference to char array + sw $t9, 4($v0) + sw $t4, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -345,7 +380,7 @@ String_concat: #Return jump jalr $ra String_substr: - move $t9 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -354,9 +389,38 @@ String_substr: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions + #Executing Substring + lw $s0, -4($fp) + move $a0 $s0 + addi $a0, $a0, 1 + li $v0, 9 + syscall + move $t6 $v0 + #Loading reference to char array of source string + lw $t7, -12($fp) + lw $t7, 8($t7) + lw $s2, -8($fp) + add $t7, $t7, $s2 + move $s1 $t6 + #Copying bytes from one char array to another + move $a0 $s0 + jal copy + #Null-terminating the string + sb $zero, 0($t0) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t4, String + sw $t4, 0($v0) + #Storing length and reference to char array + lw $s0, -4($fp) + sw $s0, 4($v0) + sw $s1, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -370,7 +434,7 @@ String_substr: #Return jump jalr $ra Object_constructor: - move $t1 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -379,7 +443,7 @@ Object_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -387,8 +451,8 @@ Object_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t2, Object - sw $t2, 0($v0) + la $t1, Object + sw $t1, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -402,7 +466,7 @@ Object_constructor: #Return jump jalr $ra IO_constructor: - move $t4 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -411,7 +475,7 @@ IO_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -419,8 +483,8 @@ IO_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t4, IO - sw $t4, 0($v0) + la $t1, IO + sw $t1, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -434,7 +498,7 @@ IO_constructor: #Return jump jalr $ra Int_constructor: - move $t4 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -443,7 +507,7 @@ Int_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -451,8 +515,8 @@ Int_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t2, Int - sw $t2, 0($v0) + la $t0, Int + sw $t0, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -466,7 +530,7 @@ Int_constructor: #Return jump jalr $ra Bool_constructor: - move $t9 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -475,7 +539,7 @@ Bool_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -483,8 +547,8 @@ Bool_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t5, Bool - sw $t5, 0($v0) + la $t3, Bool + sw $t3, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -498,7 +562,7 @@ Bool_constructor: #Return jump jalr $ra String_constructor: - move $t3 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -507,7 +571,7 @@ String_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -515,8 +579,8 @@ String_constructor: li $a0, 12 syscall sw $v0, 0($fp) - la $t9, String - sw $t9, 0($v0) + la $t5, String + sw $t5, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -530,7 +594,7 @@ String_constructor: #Return jump jalr $ra main: - move $t2 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -539,7 +603,7 @@ main: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Static Call @@ -557,7 +621,7 @@ main: li $v0, 10 syscall Main_constructor: - move $t9 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -566,7 +630,7 @@ Main_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -589,7 +653,7 @@ Main_constructor: #Return jump jalr $ra Main_main: - move $t1 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -598,60 +662,60 @@ Main_main: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Assign - lw $t4, -4($fp) - sw $t4, 4($fp) + lw $t5, -4($fp) + sw $t5, 4($fp) #Executing typeof - lw $t5, 4($fp) - lw $t5, 0($t5) - sw $t5, 8($fp) + lw $t9, 4($fp) + lw $t9, 0($t9) + sw $t9, 8($fp) #Executing Static Call jal Point_constructor sw $a1, 16($fp) addi $sp, $sp, 0 #Executing typeof - lw $t3, 16($fp) - lw $t3, 0($t3) - sw $t3, 20($fp) + lw $t9, 16($fp) + lw $t9, 0($t9) + sw $t9, 20($fp) #Executing Assign - li $t9, 5 - sw $t9, 24($fp) + li $t1, 5 + sw $t1, 24($fp) #Executing Assign - li $t4, 6 - sw $t4, 28($fp) + li $t3, 6 + sw $t3, 28($fp) #Receiving Arg local_Main_main_internal_4 lw $t1, 16($fp) sw $t1, 0($sp) addi $sp, $sp, 4 #Receiving Arg local_Main_main_internal_6 - lw $t4, 24($fp) - sw $t4, 0($sp) + lw $t0, 24($fp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Receiving Arg local_Main_main_internal_7 - lw $t1, 28($fp) - sw $t1, 0($sp) + lw $t3, 28($fp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing Dynamic Call lw $t5, 20($fp) - lw $t0, 12($t5) - jalr $t0 + lw $t2, 12($t5) + jalr $t2 sw $a1, 12($fp) addi $sp, $sp, -12 #Receiving Arg local_Main_main_internal_1 - lw $t3, 4($fp) - sw $t3, 0($sp) + lw $t0, 4($fp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Receiving Arg local_Main_main_internal_3 - lw $t0, 12($fp) - sw $t0, 0($sp) + lw $t3, 12($fp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing Dynamic Call lw $t3, 8($fp) - lw $t4, 16($t3) - jalr $t4 + lw $t5, 16($t3) + jalr $t5 sw $a1, 0($fp) addi $sp, $sp, -8 #Executing Return @@ -684,22 +748,22 @@ Point_constructor: li $a0, 12 syscall sw $v0, 0($fp) - la $t1, Point - sw $t1, 0($v0) + la $t2, Point + sw $t2, 0($v0) #Executing DefaultValue - li $t3, 0 - sw $t3, 4($fp) + li $t1, 0 + sw $t1, 4($fp) #Executing SetAttr - lw $t4, 0($fp) - lw $t0, 4($fp) - sw $t0, 4($t4) + lw $t9, 0($fp) + lw $t1, 4($fp) + sw $t1, 4($t9) #Executing DefaultValue - li $t0, 0 - sw $t0, 8($fp) + li $t9, 0 + sw $t9, 8($fp) #Executing SetAttr - lw $t1, 0($fp) - lw $t4, 8($fp) - sw $t4, 8($t1) + lw $t9, 0($fp) + lw $t2, 8($fp) + sw $t2, 8($t9) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -729,13 +793,13 @@ Point_init: lw $t1, -8($fp) sw $t1, 4($fp) #Executing Assign - lw $t3, -4($fp) - sw $t3, 8($fp) + lw $t0, -4($fp) + sw $t0, 8($fp) #Executing Plus Operation lw $t0, 4($fp) - lw $t5, 8($fp) - add $t4, $t0, $t5 - sw $t4, 0($fp) + lw $t9, 8($fp) + add $t1, $t0, $t9 + sw $t1, 0($fp) #Executing Return lw $a1, 0($fp) #Restoring saved $fp diff --git a/tests/code_gen/read_string.mips b/tests/code_gen/read_string.mips index a122d05d9..d8d334862 100644 --- a/tests/code_gen/read_string.mips +++ b/tests/code_gen/read_string.mips @@ -27,15 +27,15 @@ heap_overflow : .asciiz, "Heap overflow" .globl main length: - li $t1, 0 + li $t2, 0 length_loop: - lb $t5, 0($a0) - beq $zero, $t5, length_end - add $t1, $t1, 1 + lb $t0, 0($a0) + beq $zero, $t0, length_end + add $t2, $t2, 1 add $a0, $a0, 1 j length_loop length_end: - move $a0 $t1 + move $a0 $t2 j $ra copy: copy_loop: @@ -49,7 +49,7 @@ copy: copy_end: j $ra Object_abort: - move $t1 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -58,7 +58,7 @@ Object_abort: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing RuntimeError @@ -70,7 +70,7 @@ Object_abort: li $v0, 10 syscall Object_copy: - move $t0 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -79,7 +79,7 @@ Object_copy: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -95,7 +95,7 @@ Object_copy: #Return jump jalr $ra Object_type_name: - move $t9 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -104,7 +104,7 @@ Object_type_name: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -120,7 +120,7 @@ Object_type_name: #Return jump jalr $ra IO_out_string: - move $t4 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -129,7 +129,7 @@ IO_out_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintStringNode @@ -150,7 +150,7 @@ IO_out_string: #Return jump jalr $ra IO_out_int: - move $t4 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -159,7 +159,7 @@ IO_out_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintIntNode @@ -179,7 +179,7 @@ IO_out_int: #Return jump jalr $ra IO_in_string: - move $t1 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -188,7 +188,7 @@ IO_in_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #ReadStrNode @@ -205,8 +205,8 @@ IO_in_string: li $v0, 9 syscall move $t6 $v0 - move $t3 $v0 - move $t0 $a0 + move $t4 $v0 + move $t2 $a0 #Copying bytes from one char array to another jal copy #Null-terminating the string @@ -216,11 +216,11 @@ IO_in_string: li $a0, 12 syscall sw $v0, 0($fp) - la $t1, String - sw $t1, 0($v0) + la $t5, String + sw $t5, 0($v0) #Storing length and reference to char array - sw $t0, 4($v0) - sw $t3, 8($v0) + sw $t2, 4($v0) + sw $t4, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -234,7 +234,7 @@ IO_in_string: #Return jump jalr $ra IO_in_int: - move $t4 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -243,7 +243,7 @@ IO_in_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #ReadStrNode @@ -260,8 +260,8 @@ IO_in_int: li $v0, 9 syscall move $t6 $v0 - move $t3 $v0 - move $t5 $a0 + move $t4 $v0 + move $t1 $a0 #Copying bytes from one char array to another jal copy #Null-terminating the string @@ -271,11 +271,11 @@ IO_in_int: li $a0, 12 syscall sw $v0, 0($fp) - la $t9, String - sw $t9, 0($v0) + la $t5, String + sw $t5, 0($v0) #Storing length and reference to char array - sw $t5, 4($v0) - sw $t3, 8($v0) + sw $t1, 4($v0) + sw $t4, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -289,7 +289,7 @@ IO_in_int: #Return jump jalr $ra String_length: - move $t0 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -298,13 +298,13 @@ String_length: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Length - lw $t4, -4($fp) - lw $t4, 4($t4) - sw $t4, 0($fp) + lw $t0, -4($fp) + lw $t0, 4($t0) + sw $t0, 0($fp) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -330,6 +330,41 @@ String_concat: sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions + #Loading length + lw $s1, -8($fp) + lw $s1, 4($s1) + lw $s2, -4($fp) + lw $s2, 4($s2) + add $t1, $s1, $s2 + #Allocating new char array + move $a0 $t1 + addi $a0, $a0, 1 + li $v0, 9 + syscall + move $t6 $v0 + move $t3 $v0 + #Copying bytes from first string + lw $t7, -8($fp) + lw $t7, 8($t7) + move $a0 $s1 + jal copy + #Copying bytes from second string + lw $t7, -4($fp) + lw $t7, 8($t7) + move $a0 $s2 + jal copy + #Null-terminating the string + sb $zero, 0($t6) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t4, String + sw $t4, 0($v0) + #Storing length and reference to char array + sw $t1, 4($v0) + sw $t3, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -343,7 +378,7 @@ String_concat: #Return jump jalr $ra String_substr: - move $t2 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -352,9 +387,38 @@ String_substr: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions + #Executing Substring + lw $s0, -4($fp) + move $a0 $s0 + addi $a0, $a0, 1 + li $v0, 9 + syscall + move $t6 $v0 + #Loading reference to char array of source string + lw $t7, -12($fp) + lw $t7, 8($t7) + lw $s2, -8($fp) + add $t7, $t7, $s2 + move $s1 $t6 + #Copying bytes from one char array to another + move $a0 $s0 + jal copy + #Null-terminating the string + sb $zero, 0($t0) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t0, String + sw $t0, 0($v0) + #Storing length and reference to char array + lw $s0, -4($fp) + sw $s0, 4($v0) + sw $s1, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -368,7 +432,7 @@ String_substr: #Return jump jalr $ra Object_constructor: - move $t0 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -377,7 +441,7 @@ Object_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -385,8 +449,8 @@ Object_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t3, Object - sw $t3, 0($v0) + la $t1, Object + sw $t1, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -432,7 +496,7 @@ IO_constructor: #Return jump jalr $ra Int_constructor: - move $t1 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -441,7 +505,7 @@ Int_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -449,8 +513,8 @@ Int_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t4, Int - sw $t4, 0($v0) + la $t1, Int + sw $t1, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -464,7 +528,7 @@ Int_constructor: #Return jump jalr $ra Bool_constructor: - move $t0 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -473,7 +537,7 @@ Bool_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -481,8 +545,8 @@ Bool_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t0, Bool - sw $t0, 0($v0) + la $t3, Bool + sw $t3, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -496,7 +560,7 @@ Bool_constructor: #Return jump jalr $ra String_constructor: - move $t4 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -505,7 +569,7 @@ String_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -513,8 +577,8 @@ String_constructor: li $a0, 12 syscall sw $v0, 0($fp) - la $t4, String - sw $t4, 0($v0) + la $t5, String + sw $t5, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -555,7 +619,7 @@ main: li $v0, 10 syscall Main_constructor: - move $t0 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -564,7 +628,7 @@ Main_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -572,23 +636,23 @@ Main_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t1, Main - sw $t1, 0($v0) + la $t9, Main + sw $t9, 0($v0) #Executing DefaultValue li $v0, 9 li $a0, 12 syscall sw $v0, 4($fp) - la $t5, String - sw $t5, 0($v0) - li $t5, 0 - sw $t5, 4($v0) - la $t5, empty_string - sw $t5, 8($v0) + la $t2, String + sw $t2, 0($v0) + li $t2, 0 + sw $t2, 4($v0) + la $t2, empty_string + sw $t2, 8($v0) #Executing SetAttr - lw $t2, 0($fp) - lw $t0, 4($fp) - sw $t0, 4($t2) + lw $t5, 0($fp) + lw $t1, 4($fp) + sw $t1, 4($t5) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -602,7 +666,7 @@ Main_constructor: #Return jump jalr $ra Main_main: - move $t2 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -611,53 +675,53 @@ Main_main: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Assign - lw $t1, -4($fp) - sw $t1, 4($fp) + lw $t4, -4($fp) + sw $t4, 4($fp) #Executing typeof - lw $t1, 4($fp) - lw $t1, 0($t1) - sw $t1, 8($fp) + lw $t9, 4($fp) + lw $t9, 0($t9) + sw $t9, 8($fp) #Receiving Arg local_Main_main_internal_1 - lw $t4, 4($fp) - sw $t4, 0($sp) + lw $t5, 4($fp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing Dynamic Call - lw $t3, 8($fp) - lw $t5, 20($t3) - jalr $t5 + lw $t9, 8($fp) + lw $t1, 20($t9) + jalr $t1 sw $a1, 0($fp) addi $sp, $sp, -4 #Executing SetAttr - lw $t3, -4($fp) - lw $t1, 0($fp) - sw $t1, 4($t3) + lw $t4, -4($fp) + lw $t2, 0($fp) + sw $t2, 4($t4) #Executing Assign - lw $t5, -4($fp) - sw $t5, 12($fp) + lw $t9, -4($fp) + sw $t9, 12($fp) #Executing typeof - lw $t1, 12($fp) - lw $t1, 0($t1) - sw $t1, 16($fp) + lw $t3, 12($fp) + lw $t3, 0($t3) + sw $t3, 16($fp) #Executing GetAttr - lw $t0, -4($fp) - lw $t1, 4($t0) - sw $t1, 20($fp) + lw $t9, -4($fp) + lw $t3, 4($t9) + sw $t3, 20($fp) #Receiving Arg local_Main_main_internal_3 - lw $t0, 12($fp) - sw $t0, 0($sp) + lw $t5, 12($fp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Receiving Arg local_Main_main_internal_5 lw $t9, 20($fp) sw $t9, 0($sp) addi $sp, $sp, 4 #Executing Dynamic Call - lw $t2, 16($fp) - lw $t3, 12($t2) - jalr $t3 + lw $t9, 16($fp) + lw $t1, 12($t9) + jalr $t1 sw $a1, 0($fp) addi $sp, $sp, -8 #Executing Return diff --git a/tests/code_gen/string_methods.cl b/tests/code_gen/string_methods.cl index cdbbefa0c..15136ddf7 100644 --- a/tests/code_gen/string_methods.cl +++ b/tests/code_gen/string_methods.cl @@ -6,7 +6,7 @@ class Main inherits IO{ d : String <- "Second sentence."; main (): Object { { - out_string(c.concat(d)); + out_string(c.concat(d)); out_string(c.substr(0, c.length())); } }; diff --git a/tests/code_gen/string_methods.mips b/tests/code_gen/string_methods.mips index 681dd9a1b..6b2c949ae 100644 --- a/tests/code_gen/string_methods.mips +++ b/tests/code_gen/string_methods.mips @@ -29,15 +29,15 @@ string_2 : .asciiz, "Second sentence." .globl main length: - li $t2, 0 + li $t0, 0 length_loop: - lb $t1, 0($a0) - beq $zero, $t1, length_end - add $t2, $t2, 1 + lb $t2, 0($a0) + beq $zero, $t2, length_end + add $t0, $t0, 1 add $a0, $a0, 1 j length_loop length_end: - move $a0 $t2 + move $a0 $t0 j $ra copy: copy_loop: @@ -51,7 +51,7 @@ copy: copy_end: j $ra Object_abort: - move $t2 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -60,7 +60,7 @@ Object_abort: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing RuntimeError @@ -72,7 +72,7 @@ Object_abort: li $v0, 10 syscall Object_copy: - move $t4 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -81,7 +81,7 @@ Object_copy: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -97,7 +97,7 @@ Object_copy: #Return jump jalr $ra Object_type_name: - move $t3 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -106,7 +106,7 @@ Object_type_name: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -122,7 +122,7 @@ Object_type_name: #Return jump jalr $ra IO_out_string: - move $t9 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -131,7 +131,7 @@ IO_out_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintStringNode @@ -152,7 +152,7 @@ IO_out_string: #Return jump jalr $ra IO_out_int: - move $t4 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -161,7 +161,7 @@ IO_out_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintIntNode @@ -181,7 +181,7 @@ IO_out_int: #Return jump jalr $ra IO_in_string: - move $t0 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -190,7 +190,7 @@ IO_in_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #ReadStrNode @@ -207,8 +207,8 @@ IO_in_string: li $v0, 9 syscall move $t6 $v0 - move $t5 $v0 - move $t2 $a0 + move $t9 $v0 + move $t0 $a0 #Copying bytes from one char array to another jal copy #Null-terminating the string @@ -218,11 +218,11 @@ IO_in_string: li $a0, 12 syscall sw $v0, 0($fp) - la $t4, String - sw $t4, 0($v0) + la $t1, String + sw $t1, 0($v0) #Storing length and reference to char array - sw $t2, 4($v0) - sw $t5, 8($v0) + sw $t0, 4($v0) + sw $t9, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -236,7 +236,7 @@ IO_in_string: #Return jump jalr $ra IO_in_int: - move $t5 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -245,7 +245,7 @@ IO_in_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t5, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #ReadStrNode @@ -262,8 +262,8 @@ IO_in_int: li $v0, 9 syscall move $t6 $v0 - move $t0 $v0 - move $t1 $a0 + move $t9 $v0 + move $t0 $a0 #Copying bytes from one char array to another jal copy #Null-terminating the string @@ -273,11 +273,11 @@ IO_in_int: li $a0, 12 syscall sw $v0, 0($fp) - la $t2, String - sw $t2, 0($v0) + la $t1, String + sw $t1, 0($v0) #Storing length and reference to char array - sw $t1, 4($v0) - sw $t0, 8($v0) + sw $t0, 4($v0) + sw $t9, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -291,7 +291,7 @@ IO_in_int: #Return jump jalr $ra String_length: - move $t4 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -300,13 +300,13 @@ String_length: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Length - lw $t3, -4($fp) - lw $t3, 4($t3) - sw $t3, 0($fp) + lw $t9, -4($fp) + lw $t9, 4($t9) + sw $t9, 0($fp) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -320,7 +320,7 @@ String_length: #Return jump jalr $ra String_concat: - move $t9 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -329,7 +329,7 @@ String_concat: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #Loading length @@ -337,14 +337,14 @@ String_concat: lw $s1, 4($s1) lw $s2, -4($fp) lw $s2, 4($s2) - add $t9, $s1, $s2 + add $t5, $s1, $s2 #Allocating new char array - move $a0 $t9 + move $a0 $t5 addi $a0, $a0, 1 li $v0, 9 syscall move $t6 $v0 - move $t5 $v0 + move $t0 $v0 #Copying bytes from first string lw $t7, -8($fp) lw $t7, 8($t7) @@ -362,11 +362,11 @@ String_concat: li $a0, 12 syscall sw $v0, 0($fp) - la $t4, String - sw $t4, 0($v0) + la $t9, String + sw $t9, 0($v0) #Storing length and reference to char array - sw $t9, 4($v0) - sw $t5, 8($v0) + sw $t5, 4($v0) + sw $t0, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -380,7 +380,7 @@ String_concat: #Return jump jalr $ra String_substr: - move $t0 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -389,7 +389,7 @@ String_substr: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Substring @@ -415,8 +415,8 @@ String_substr: li $a0, 12 syscall sw $v0, 0($fp) - la $t5, String - sw $t5, 0($v0) + la $t1, String + sw $t1, 0($v0) #Storing length and reference to char array lw $s0, -4($fp) sw $s0, 4($v0) @@ -434,7 +434,7 @@ String_substr: #Return jump jalr $ra Object_constructor: - move $t9 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -443,7 +443,7 @@ Object_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -451,8 +451,8 @@ Object_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t1, Object - sw $t1, 0($v0) + la $t4, Object + sw $t4, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -466,7 +466,7 @@ Object_constructor: #Return jump jalr $ra IO_constructor: - move $t0 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -475,7 +475,7 @@ IO_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -483,8 +483,8 @@ IO_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t0, IO - sw $t0, 0($v0) + la $t4, IO + sw $t4, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -498,7 +498,7 @@ IO_constructor: #Return jump jalr $ra Int_constructor: - move $t4 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -507,7 +507,7 @@ Int_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -530,7 +530,7 @@ Int_constructor: #Return jump jalr $ra Bool_constructor: - move $t1 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -539,7 +539,7 @@ Bool_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -547,8 +547,8 @@ Bool_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t1, Bool - sw $t1, 0($v0) + la $t9, Bool + sw $t9, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -562,7 +562,7 @@ Bool_constructor: #Return jump jalr $ra String_constructor: - move $t1 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -571,7 +571,7 @@ String_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -594,7 +594,7 @@ String_constructor: #Return jump jalr $ra main: - move $t9 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -603,7 +603,7 @@ main: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Static Call @@ -611,8 +611,8 @@ main: sw $a1, 0($fp) addi $sp, $sp, 0 #Receiving Arg local_main_internal_0 - lw $t0, 0($fp) - sw $t0, 0($sp) + lw $t5, 0($fp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing Static Call jal Main_main @@ -621,85 +621,99 @@ main: li $v0, 10 syscall Main_constructor: - move $t1 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals - addi $sp, $sp, 20 + addi $sp, $sp, 28 #Pushing $ra sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate li $v0, 9 - li $a0, 12 + li $a0, 20 syscall sw $v0, 0($fp) - la $t3, Main - sw $t3, 0($v0) + la $t5, Main + sw $t5, 0($v0) + #Executing DefaultValue + li $t5, 0 + sw $t5, 4($fp) + #Executing SetAttr + lw $t5, 0($fp) + lw $t0, 4($fp) + sw $t0, 4($t5) + #Executing DefaultValue + li $t9, 0 + sw $t9, 8($fp) + #Executing SetAttr + lw $t0, 0($fp) + lw $t4, 8($fp) + sw $t4, 8($t0) #Executing DefaultValue li $v0, 9 li $a0, 12 syscall - sw $v0, 4($fp) - la $t1, String - sw $t1, 0($v0) - li $t1, 0 - sw $t1, 4($v0) - la $t1, empty_string - sw $t1, 8($v0) + sw $v0, 12($fp) + la $t3, String + sw $t3, 0($v0) + li $t3, 0 + sw $t3, 4($v0) + la $t3, empty_string + sw $t3, 8($v0) #Executing SetAttr - lw $t2, 0($fp) - lw $t3, 4($fp) - sw $t3, 4($t2) + lw $t4, 0($fp) + lw $t9, 12($fp) + sw $t9, 12($t4) #Executing DefaultValue li $v0, 9 li $a0, 12 syscall - sw $v0, 8($fp) - la $t4, String - sw $t4, 0($v0) - li $t4, 0 - sw $t4, 4($v0) - la $t4, empty_string - sw $t4, 8($v0) + sw $v0, 16($fp) + la $t2, String + sw $t2, 0($v0) + li $t2, 0 + sw $t2, 4($v0) + la $t2, empty_string + sw $t2, 8($v0) #Executing SetAttr - lw $t9, 0($fp) - lw $t0, 8($fp) - sw $t0, 8($t9) + lw $t5, 0($fp) + lw $t4, 16($fp) + sw $t4, 16($t5) #Executing Load li $v0, 9 li $a0, 12 syscall - sw $v0, 12($fp) - la $t1, String - sw $t1, 0($v0) - li $t1, 15 - sw $t1, 4($v0) - la $t1, string_1 - sw $t1, 8($v0) + sw $v0, 20($fp) + la $t5, String + sw $t5, 0($v0) + li $t5, 15 + sw $t5, 4($v0) + la $t5, string_1 + sw $t5, 8($v0) #Executing SetAttr - lw $t9, 0($fp) - lw $t1, 12($fp) - sw $t1, 4($t9) + lw $t5, 0($fp) + lw $t0, 20($fp) + sw $t0, 12($t5) #Executing Load li $v0, 9 li $a0, 12 syscall - sw $v0, 16($fp) - la $t3, String - sw $t3, 0($v0) - li $t3, 16 - sw $t3, 4($v0) - la $t3, string_2 - sw $t3, 8($v0) + sw $v0, 24($fp) + la $t0, String + sw $t0, 0($v0) + li $t0, 16 + sw $t0, 4($v0) + la $t0, string_2 + sw $t0, 8($v0) #Executing SetAttr - lw $t1, 0($fp) - lw $t4, 16($fp) - sw $t4, 8($t1) + lw $t0, 0($fp) + lw $t5, 24($fp) + sw $t5, 16($t0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -709,88 +723,135 @@ Main_constructor: addi $sp, $sp, -4 lw $ra, 0($sp) #Cleaning stack after call - addi $sp, $sp, -20 + addi $sp, $sp, -28 #Return jump jalr $ra Main_main: - move $t9 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals - addi $sp, $sp, 40 + addi $sp, $sp, 64 #Pushing $ra sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Assign + lw $t3, -4($fp) + sw $t3, 4($fp) + #Executing typeof + lw $t5, 4($fp) + lw $t5, 0($t5) + sw $t5, 8($fp) + #Executing GetAttr lw $t0, -4($fp) - sw $t0, 4($fp) + lw $t4, 12($t0) + sw $t4, 16($fp) #Executing typeof - lw $t3, 4($fp) + lw $t3, 16($fp) lw $t3, 0($t3) - sw $t3, 8($fp) + sw $t3, 20($fp) #Executing GetAttr - lw $t0, -4($fp) - lw $t3, 4($t0) - sw $t3, 16($fp) + lw $t2, -4($fp) + lw $t4, 16($t2) + sw $t4, 24($fp) + #Receiving Arg local_Main_main_internal_4 + lw $t5, 16($fp) + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Receiving Arg local_Main_main_internal_6 + lw $t2, 24($fp) + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Executing Dynamic Call + lw $t3, 20($fp) + lw $t9, 16($t3) + jalr $t9 + sw $a1, 12($fp) + addi $sp, $sp, -8 + #Receiving Arg local_Main_main_internal_1 + lw $t2, 4($fp) + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Receiving Arg local_Main_main_internal_3 + lw $t2, 12($fp) + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Executing Dynamic Call + lw $t5, 8($fp) + lw $t4, 12($t5) + jalr $t4 + sw $a1, 0($fp) + addi $sp, $sp, -8 + #Executing Assign + lw $t4, -4($fp) + sw $t4, 28($fp) + #Executing typeof + lw $t3, 28($fp) + lw $t3, 0($t3) + sw $t3, 32($fp) + #Executing GetAttr + lw $t3, -4($fp) + lw $t5, 12($t3) + sw $t5, 40($fp) #Executing typeof - lw $t9, 16($fp) - lw $t9, 0($t9) - sw $t9, 20($fp) + lw $t4, 40($fp) + lw $t4, 0($t4) + sw $t4, 44($fp) #Executing Assign li $t0, 0 - sw $t0, 24($fp) + sw $t0, 48($fp) #Executing GetAttr - lw $t4, -4($fp) - lw $t3, 4($t4) - sw $t3, 32($fp) + lw $t2, -4($fp) + lw $t9, 12($t2) + sw $t9, 56($fp) #Executing typeof - lw $t2, 32($fp) - lw $t2, 0($t2) - sw $t2, 36($fp) - #Receiving Arg local_Main_main_internal_8 - lw $t1, 32($fp) - sw $t1, 0($sp) + lw $t0, 56($fp) + lw $t0, 0($t0) + sw $t0, 60($fp) + #Receiving Arg local_Main_main_internal_14 + lw $t5, 56($fp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing Dynamic Call - lw $t9, 36($fp) - lw $t1, 12($t9) - jalr $t1 - sw $a1, 28($fp) + lw $t9, 60($fp) + lw $t5, 12($t9) + jalr $t5 + sw $a1, 52($fp) addi $sp, $sp, -4 - #Receiving Arg local_Main_main_internal_4 - lw $t9, 16($fp) - sw $t9, 0($sp) + #Receiving Arg local_Main_main_internal_10 + lw $t3, 40($fp) + sw $t3, 0($sp) addi $sp, $sp, 4 - #Receiving Arg local_Main_main_internal_6 - lw $t0, 24($fp) - sw $t0, 0($sp) + #Receiving Arg local_Main_main_internal_12 + lw $t3, 48($fp) + sw $t3, 0($sp) addi $sp, $sp, 4 - #Receiving Arg local_Main_main_internal_7 - lw $t3, 28($fp) + #Receiving Arg local_Main_main_internal_13 + lw $t3, 52($fp) sw $t3, 0($sp) addi $sp, $sp, 4 #Executing Dynamic Call - lw $t0, 20($fp) - lw $t3, 20($t0) - jalr $t3 - sw $a1, 12($fp) + lw $t3, 44($fp) + lw $t0, 20($t3) + jalr $t0 + sw $a1, 36($fp) addi $sp, $sp, -12 - #Receiving Arg local_Main_main_internal_1 - lw $t3, 4($fp) - sw $t3, 0($sp) + #Receiving Arg local_Main_main_internal_7 + lw $t5, 28($fp) + sw $t5, 0($sp) addi $sp, $sp, 4 - #Receiving Arg local_Main_main_internal_3 - lw $t3, 12($fp) - sw $t3, 0($sp) + #Receiving Arg local_Main_main_internal_9 + lw $t4, 36($fp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing Dynamic Call - lw $t9, 8($fp) - lw $t0, 12($t9) - jalr $t0 + lw $t3, 32($fp) + lw $t4, 12($t3) + jalr $t4 sw $a1, 0($fp) addi $sp, $sp, -8 #Executing Return @@ -802,6 +863,6 @@ Main_main: addi $sp, $sp, -4 lw $ra, 0($sp) #Cleaning stack after call - addi $sp, $sp, -40 + addi $sp, $sp, -64 #Return jump jalr $ra diff --git a/tests/code_gen/test_goto_if.mips b/tests/code_gen/test_goto_if.mips index f35dc73de..9a48c5b12 100644 --- a/tests/code_gen/test_goto_if.mips +++ b/tests/code_gen/test_goto_if.mips @@ -27,15 +27,15 @@ heap_overflow : .asciiz, "Heap overflow" .globl main length: - li $t9, 0 + li $t1, 0 length_loop: lb $t0, 0($a0) beq $zero, $t0, length_end - add $t9, $t9, 1 + add $t1, $t1, 1 add $a0, $a0, 1 j length_loop length_end: - move $a0 $t9 + move $a0 $t1 j $ra copy: copy_loop: @@ -49,7 +49,7 @@ copy: copy_end: j $ra Object_abort: - move $t3 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -58,7 +58,7 @@ Object_abort: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing RuntimeError @@ -70,7 +70,7 @@ Object_abort: li $v0, 10 syscall Object_copy: - move $t3 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -79,7 +79,7 @@ Object_copy: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -95,7 +95,7 @@ Object_copy: #Return jump jalr $ra Object_type_name: - move $t3 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -104,7 +104,7 @@ Object_type_name: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -120,7 +120,7 @@ Object_type_name: #Return jump jalr $ra IO_out_string: - move $t2 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -129,7 +129,7 @@ IO_out_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintStringNode @@ -150,7 +150,7 @@ IO_out_string: #Return jump jalr $ra IO_out_int: - move $t1 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -159,7 +159,7 @@ IO_out_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintIntNode @@ -179,7 +179,7 @@ IO_out_int: #Return jump jalr $ra IO_in_string: - move $t5 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -188,7 +188,7 @@ IO_in_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t5, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions #ReadStrNode @@ -205,8 +205,8 @@ IO_in_string: li $v0, 9 syscall move $t6 $v0 - move $t4 $v0 - move $t5 $a0 + move $t3 $v0 + move $t2 $a0 #Copying bytes from one char array to another jal copy #Null-terminating the string @@ -216,11 +216,11 @@ IO_in_string: li $a0, 12 syscall sw $v0, 0($fp) - la $t9, String - sw $t9, 0($v0) + la $t5, String + sw $t5, 0($v0) #Storing length and reference to char array - sw $t5, 4($v0) - sw $t4, 8($v0) + sw $t2, 4($v0) + sw $t3, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -234,7 +234,7 @@ IO_in_string: #Return jump jalr $ra IO_in_int: - move $t4 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -243,7 +243,7 @@ IO_in_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #ReadStrNode @@ -261,7 +261,7 @@ IO_in_int: syscall move $t6 $v0 move $t3 $v0 - move $t4 $a0 + move $t0 $a0 #Copying bytes from one char array to another jal copy #Null-terminating the string @@ -271,10 +271,10 @@ IO_in_int: li $a0, 12 syscall sw $v0, 0($fp) - la $t0, String - sw $t0, 0($v0) + la $t2, String + sw $t2, 0($v0) #Storing length and reference to char array - sw $t4, 4($v0) + sw $t0, 4($v0) sw $t3, 8($v0) #Executing Return lw $a1, 0($fp) @@ -289,7 +289,7 @@ IO_in_int: #Return jump jalr $ra String_length: - move $t4 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -298,7 +298,7 @@ String_length: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Length @@ -318,7 +318,7 @@ String_length: #Return jump jalr $ra String_concat: - move $t3 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -327,9 +327,44 @@ String_concat: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions + #Loading length + lw $s1, -8($fp) + lw $s1, 4($s1) + lw $s2, -4($fp) + lw $s2, 4($s2) + add $t0, $s1, $s2 + #Allocating new char array + move $a0 $t0 + addi $a0, $a0, 1 + li $v0, 9 + syscall + move $t6 $v0 + move $t9 $v0 + #Copying bytes from first string + lw $t7, -8($fp) + lw $t7, 8($t7) + move $a0 $s1 + jal copy + #Copying bytes from second string + lw $t7, -4($fp) + lw $t7, 8($t7) + move $a0 $s2 + jal copy + #Null-terminating the string + sb $zero, 0($t6) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t3, String + sw $t3, 0($v0) + #Storing length and reference to char array + sw $t0, 4($v0) + sw $t9, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -343,7 +378,7 @@ String_concat: #Return jump jalr $ra String_substr: - move $t4 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -352,9 +387,38 @@ String_substr: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions + #Executing Substring + lw $s0, -4($fp) + move $a0 $s0 + addi $a0, $a0, 1 + li $v0, 9 + syscall + move $t6 $v0 + #Loading reference to char array of source string + lw $t7, -12($fp) + lw $t7, 8($t7) + lw $s2, -8($fp) + add $t7, $t7, $s2 + move $s1 $t6 + #Copying bytes from one char array to another + move $a0 $s0 + jal copy + #Null-terminating the string + sb $zero, 0($t0) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t3, String + sw $t3, 0($v0) + #Storing length and reference to char array + lw $s0, -4($fp) + sw $s0, 4($v0) + sw $s1, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -368,7 +432,7 @@ String_substr: #Return jump jalr $ra Object_constructor: - move $t9 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -377,7 +441,7 @@ Object_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -400,7 +464,7 @@ Object_constructor: #Return jump jalr $ra IO_constructor: - move $t0 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -409,7 +473,7 @@ IO_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -417,8 +481,8 @@ IO_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t2, IO - sw $t2, 0($v0) + la $t9, IO + sw $t9, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -432,7 +496,7 @@ IO_constructor: #Return jump jalr $ra Int_constructor: - move $t2 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -441,7 +505,7 @@ Int_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -449,8 +513,8 @@ Int_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t5, Int - sw $t5, 0($v0) + la $t1, Int + sw $t1, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -464,7 +528,7 @@ Int_constructor: #Return jump jalr $ra Bool_constructor: - move $t5 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -473,7 +537,7 @@ Bool_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t5, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -481,8 +545,8 @@ Bool_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t0, Bool - sw $t0, 0($v0) + la $t1, Bool + sw $t1, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -513,8 +577,8 @@ String_constructor: li $a0, 12 syscall sw $v0, 0($fp) - la $t1, String - sw $t1, 0($v0) + la $t9, String + sw $t9, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -545,8 +609,8 @@ main: sw $a1, 0($fp) addi $sp, $sp, 0 #Receiving Arg local_main_internal_0 - lw $t0, 0($fp) - sw $t0, 0($sp) + lw $t4, 0($fp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing Static Call jal Main_main @@ -555,7 +619,7 @@ main: li $v0, 10 syscall Main_constructor: - move $t0 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -564,7 +628,7 @@ Main_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -572,36 +636,36 @@ Main_constructor: li $a0, 12 syscall sw $v0, 0($fp) - la $t2, Main - sw $t2, 0($v0) + la $t4, Main + sw $t4, 0($v0) #Executing DefaultValue - li $t3, 0 - sw $t3, 4($fp) + li $t2, 0 + sw $t2, 4($fp) #Executing SetAttr - lw $t1, 0($fp) - lw $t3, 4($fp) - sw $t3, 4($t1) + lw $t0, 0($fp) + lw $t9, 4($fp) + sw $t9, 4($t0) #Executing DefaultValue - li $t3, 0 - sw $t3, 8($fp) + li $t4, 0 + sw $t4, 8($fp) #Executing SetAttr - lw $t0, 0($fp) - lw $t1, 8($fp) - sw $t1, 8($t0) + lw $t2, 0($fp) + lw $t4, 8($fp) + sw $t4, 8($t2) #Executing Assign - li $t5, 1 - sw $t5, 12($fp) + li $t1, 1 + sw $t1, 12($fp) #Executing SetAttr - lw $t5, 0($fp) - lw $t0, 12($fp) - sw $t0, 4($t5) + lw $t1, 0($fp) + lw $t5, 12($fp) + sw $t5, 4($t1) #Executing Assign - li $t3, 2 - sw $t3, 16($fp) + li $t5, 2 + sw $t5, 16($fp) #Executing SetAttr - lw $t9, 0($fp) - lw $t5, 16($fp) - sw $t5, 8($t9) + lw $t2, 0($fp) + lw $t9, 16($fp) + sw $t9, 8($t2) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -615,7 +679,7 @@ Main_constructor: #Return jump jalr $ra Main_main: - move $t2 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -624,82 +688,82 @@ Main_main: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing GetAttr - lw $t4, -4($fp) - lw $t3, 4($t4) - sw $t3, 4($fp) + lw $t0, -4($fp) + lw $t9, 4($t0) + sw $t9, 4($fp) #Executing GetAttr - lw $t9, -4($fp) - lw $t0, 8($t9) - sw $t0, 8($fp) + lw $t4, -4($fp) + lw $t9, 8($t4) + sw $t9, 8($fp) #Executing Plus Operation - lw $t9, 4($fp) - lw $t1, 8($fp) - add $t4, $t9, $t1 - sw $t4, 0($fp) + lw $t0, 4($fp) + lw $t2, 8($fp) + add $t9, $t0, $t2 + sw $t9, 0($fp) #Executing GetAttr - lw $t2, -4($fp) - lw $t1, 4($t2) + lw $t0, -4($fp) + lw $t1, 4($t0) sw $t1, 12($fp) #Executing GetAttr - lw $t0, -4($fp) - lw $t3, 8($t0) - sw $t3, 16($fp) + lw $t2, -4($fp) + lw $t0, 8($t2) + sw $t0, 16($fp) #Executing Minus Operation - lw $t3, 12($fp) - lw $t9, 16($fp) - sub $t1, $t3, $t9 - sw $t1, 0($fp) + lw $t1, 12($fp) + lw $t4, 16($fp) + sub $t2, $t1, $t4 + sw $t2, 0($fp) #Executing GetAttr - lw $t3, -4($fp) - lw $t5, 4($t3) - sw $t5, 20($fp) + lw $t9, -4($fp) + lw $t1, 4($t9) + sw $t1, 20($fp) #Executing GetAttr - lw $t0, -4($fp) - lw $t4, 8($t0) - sw $t4, 24($fp) + lw $t1, -4($fp) + lw $t2, 8($t1) + sw $t2, 24($fp) #Executing Div Operation - lw $t5, 20($fp) - lw $t1, 24($fp) - div $t5, $t1 - mflo $t5 - sw $t5, 0($fp) + lw $t2, 20($fp) + lw $t4, 24($fp) + div $t2, $t4 + mflo $t2 + sw $t2, 0($fp) #Executing Assign - lw $t9, -4($fp) - sw $t9, 28($fp) + lw $t5, -4($fp) + sw $t5, 28($fp) #Executing typeof - lw $t3, 28($fp) - lw $t3, 0($t3) - sw $t3, 32($fp) + lw $t5, 28($fp) + lw $t5, 0($t5) + sw $t5, 32($fp) #Executing GetAttr - lw $t9, -4($fp) - lw $t1, 8($t9) - sw $t1, 40($fp) + lw $t0, -4($fp) + lw $t4, 8($t0) + sw $t4, 40($fp) #Executing GetAttr - lw $t3, -4($fp) - lw $t5, 4($t3) - sw $t5, 44($fp) + lw $t1, -4($fp) + lw $t2, 4($t1) + sw $t2, 44($fp) #Executing Star Operation - lw $t4, 40($fp) - lw $t0, 44($fp) - mult $t4, $t0 - mflo $t4 - sw $t4, 36($fp) + lw $t1, 40($fp) + lw $t9, 44($fp) + mult $t1, $t9 + mflo $t1 + sw $t1, 36($fp) #Receiving Arg local_Main_main_internal_7 - lw $t3, 28($fp) - sw $t3, 0($sp) + lw $t4, 28($fp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Receiving Arg local_Main_main_internal_9 - lw $t1, 36($fp) - sw $t1, 0($sp) + lw $t5, 36($fp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing Dynamic Call - lw $t1, 32($fp) - lw $t3, 16($t1) - jalr $t3 + lw $t9, 32($fp) + lw $t1, 16($t9) + jalr $t1 sw $a1, 0($fp) addi $sp, $sp, -8 #Executing Return diff --git a/tests/code_gen/unary_nodes.cl b/tests/code_gen/unary_nodes.cl index d9bc9e3b6..254efb12c 100644 --- a/tests/code_gen/unary_nodes.cl +++ b/tests/code_gen/unary_nodes.cl @@ -1,10 +1,10 @@ class Main inherits IO{ - a : Int <- 4; + a : Int; b : Int; c: Bool; main (): Object { { - out_string(if not a <= b then "True \n" else "False \n" fi); + (* out_string(if not a <= b then "True \n" else "False \n" fi); *) out_int(~a); } }; diff --git a/tests/code_gen/unary_nodes.mips b/tests/code_gen/unary_nodes.mips index 5a39678e0..d526b9076 100644 --- a/tests/code_gen/unary_nodes.mips +++ b/tests/code_gen/unary_nodes.mips @@ -22,22 +22,20 @@ dispatch_on_void : .asciiz, "Dispatch on void" division_by_zero : .asciiz, "Division by zero" substr_out_of_range : .asciiz, "Substring out of range" heap_overflow : .asciiz, "Heap overflow" -string_1 : .asciiz, "False \n" -string_2 : .asciiz, "True \n" .text .globl main length: - li $t5, 0 + li $t0, 0 length_loop: lb $t2, 0($a0) beq $zero, $t2, length_end - add $t5, $t5, 1 + add $t0, $t0, 1 add $a0, $a0, 1 j length_loop length_end: - move $a0 $t5 + move $a0 $t0 j $ra copy: copy_loop: @@ -51,7 +49,7 @@ copy: copy_end: j $ra Object_abort: - move $t1 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -60,7 +58,7 @@ Object_abort: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing RuntimeError @@ -72,7 +70,7 @@ Object_abort: li $v0, 10 syscall Object_copy: - move $t9 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -81,7 +79,7 @@ Object_copy: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -97,7 +95,7 @@ Object_copy: #Return jump jalr $ra Object_type_name: - move $t9 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -106,7 +104,7 @@ Object_type_name: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -122,7 +120,7 @@ Object_type_name: #Return jump jalr $ra IO_out_string: - move $t3 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -131,7 +129,7 @@ IO_out_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintStringNode @@ -152,7 +150,7 @@ IO_out_string: #Return jump jalr $ra IO_out_int: - move $t4 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -161,7 +159,7 @@ IO_out_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintIntNode @@ -181,7 +179,7 @@ IO_out_int: #Return jump jalr $ra IO_in_string: - move $t1 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -190,7 +188,7 @@ IO_in_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #ReadStrNode @@ -207,8 +205,8 @@ IO_in_string: li $v0, 9 syscall move $t6 $v0 - move $t1 $v0 - move $t0 $a0 + move $t3 $v0 + move $t5 $a0 #Copying bytes from one char array to another jal copy #Null-terminating the string @@ -218,11 +216,11 @@ IO_in_string: li $a0, 12 syscall sw $v0, 0($fp) - la $t4, String - sw $t4, 0($v0) + la $t1, String + sw $t1, 0($v0) #Storing length and reference to char array - sw $t0, 4($v0) - sw $t1, 8($v0) + sw $t5, 4($v0) + sw $t3, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -236,7 +234,7 @@ IO_in_string: #Return jump jalr $ra IO_in_int: - move $t5 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -245,7 +243,7 @@ IO_in_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t5, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #ReadStrNode @@ -262,8 +260,8 @@ IO_in_int: li $v0, 9 syscall move $t6 $v0 - move $t9 $v0 - move $t5 $a0 + move $t2 $v0 + move $t0 $a0 #Copying bytes from one char array to another jal copy #Null-terminating the string @@ -273,11 +271,11 @@ IO_in_int: li $a0, 12 syscall sw $v0, 0($fp) - la $t0, String - sw $t0, 0($v0) + la $t3, String + sw $t3, 0($v0) #Storing length and reference to char array - sw $t5, 4($v0) - sw $t9, 8($v0) + sw $t0, 4($v0) + sw $t2, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -304,9 +302,9 @@ String_length: addi $sp, $sp, 4 #Executing instructions #Executing Length - lw $t3, -4($fp) - lw $t3, 4($t3) - sw $t3, 0($fp) + lw $t4, -4($fp) + lw $t4, 4($t4) + sw $t4, 0($fp) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -320,7 +318,7 @@ String_length: #Return jump jalr $ra String_concat: - move $t1 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -329,9 +327,44 @@ String_concat: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions + #Loading length + lw $s1, -8($fp) + lw $s1, 4($s1) + lw $s2, -4($fp) + lw $s2, 4($s2) + add $t2, $s1, $s2 + #Allocating new char array + move $a0 $t2 + addi $a0, $a0, 1 + li $v0, 9 + syscall + move $t6 $v0 + move $t4 $v0 + #Copying bytes from first string + lw $t7, -8($fp) + lw $t7, 8($t7) + move $a0 $s1 + jal copy + #Copying bytes from second string + lw $t7, -4($fp) + lw $t7, 8($t7) + move $a0 $s2 + jal copy + #Null-terminating the string + sb $zero, 0($t6) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t0, String + sw $t0, 0($v0) + #Storing length and reference to char array + sw $t2, 4($v0) + sw $t4, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -345,7 +378,7 @@ String_concat: #Return jump jalr $ra String_substr: - move $t0 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -354,9 +387,38 @@ String_substr: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions + #Executing Substring + lw $s0, -4($fp) + move $a0 $s0 + addi $a0, $a0, 1 + li $v0, 9 + syscall + move $t6 $v0 + #Loading reference to char array of source string + lw $t7, -12($fp) + lw $t7, 8($t7) + lw $s2, -8($fp) + add $t7, $t7, $s2 + move $s1 $t6 + #Copying bytes from one char array to another + move $a0 $s0 + jal copy + #Null-terminating the string + sb $zero, 0($t0) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t0, String + sw $t0, 0($v0) + #Storing length and reference to char array + lw $s0, -4($fp) + sw $s0, 4($v0) + sw $s1, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -370,7 +432,7 @@ String_substr: #Return jump jalr $ra Object_constructor: - move $t1 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -379,7 +441,7 @@ Object_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -387,8 +449,8 @@ Object_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t1, Object - sw $t1, 0($v0) + la $t5, Object + sw $t5, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -402,7 +464,7 @@ Object_constructor: #Return jump jalr $ra IO_constructor: - move $t0 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -411,7 +473,7 @@ IO_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -419,8 +481,8 @@ IO_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t5, IO - sw $t5, 0($v0) + la $t9, IO + sw $t9, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -434,7 +496,7 @@ IO_constructor: #Return jump jalr $ra Int_constructor: - move $t0 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -443,7 +505,7 @@ Int_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -451,8 +513,8 @@ Int_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t5, Int - sw $t5, 0($v0) + la $t2, Int + sw $t2, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -466,7 +528,7 @@ Int_constructor: #Return jump jalr $ra Bool_constructor: - move $t3 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -475,7 +537,7 @@ Bool_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -483,8 +545,8 @@ Bool_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t4, Bool - sw $t4, 0($v0) + la $t9, Bool + sw $t9, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -515,8 +577,8 @@ String_constructor: li $a0, 12 syscall sw $v0, 0($fp) - la $t3, String - sw $t3, 0($v0) + la $t2, String + sw $t2, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -547,8 +609,8 @@ main: sw $a1, 0($fp) addi $sp, $sp, 0 #Receiving Arg local_main_internal_0 - lw $t4, 0($fp) - sw $t4, 0($sp) + lw $t9, 0($fp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing Static Call jal Main_main @@ -561,7 +623,7 @@ Main_constructor: #New $fp move $fp $sp #Reserving space for locals - addi $sp, $sp, 20 + addi $sp, $sp, 16 #Pushing $ra sw $ra, 0($sp) addi $sp, $sp, 4 @@ -574,36 +636,29 @@ Main_constructor: li $a0, 16 syscall sw $v0, 0($fp) - la $t2, Main - sw $t2, 0($v0) + la $t5, Main + sw $t5, 0($v0) #Executing DefaultValue - li $t0, 0 - sw $t0, 4($fp) + li $t2, 0 + sw $t2, 4($fp) #Executing SetAttr - lw $t4, 0($fp) - lw $t0, 4($fp) - sw $t0, 4($t4) + lw $t5, 0($fp) + lw $t1, 4($fp) + sw $t1, 4($t5) #Executing DefaultValue - li $t5, 0 - sw $t5, 8($fp) + li $t9, 0 + sw $t9, 8($fp) #Executing SetAttr - lw $t0, 0($fp) - lw $t5, 8($fp) - sw $t5, 8($t0) + lw $t9, 0($fp) + lw $t2, 8($fp) + sw $t2, 8($t9) #Executing DefaultValue li $t5, 0 sw $t5, 12($fp) #Executing SetAttr - lw $t2, 0($fp) + lw $t5, 0($fp) lw $t9, 12($fp) - sw $t9, 12($t2) - #Executing Assign - li $t1, 4 - sw $t1, 16($fp) - #Executing SetAttr - lw $t9, 0($fp) - lw $t4, 16($fp) - sw $t4, 4($t9) + sw $t9, 12($t5) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -613,84 +668,41 @@ Main_constructor: addi $sp, $sp, -4 lw $ra, 0($sp) #Cleaning stack after call - addi $sp, $sp, -20 + addi $sp, $sp, -16 #Return jump jalr $ra Main_main: - move $t4 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals - addi $sp, $sp, 52 + addi $sp, $sp, 20 #Pushing $ra sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Assign - lw $t5, -4($fp) - sw $t5, 4($fp) + lw $t2, -4($fp) + sw $t2, 4($fp) #Executing typeof - lw $t4, 4($fp) - lw $t4, 0($t4) - sw $t4, 8($fp) - #Executing GetAttr - lw $t3, -4($fp) - lw $t1, 4($t3) - sw $t1, 24($fp) + lw $t9, 4($fp) + lw $t9, 0($t9) + sw $t9, 8($fp) #Executing GetAttr - lw $t9, -4($fp) - lw $t5, 8($t9) - sw $t5, 28($fp) - lw $t1, 24($fp) - lw $t0, 28($fp) - sle $t5, $t1, $t0 - sw $t5, 20($fp) - #Executing Static Call - jal Bool_constructor - sw $a1, 32($fp) - addi $sp, $sp, 0 - #Executing Assign - li $t1, 1 - sw $t1, 32($fp) - #Executing Minus Operation - lw $t1, 32($fp) - lw $t2, 20($fp) - sub $t0, $t1, $t2 - sw $t0, 16($fp) - lw $t4, 16($fp) - bnez $t4, THEN_1 - #Executing Load - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 12($fp) - la $t1, String - sw $t1, 0($v0) - li $t1, 8 - sw $t1, 4($v0) - la $t1, string_1 - sw $t1, 8($v0) - #Executing Goto - j END_IF_2 - THEN_1: - #Executing Load - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 12($fp) - la $t2, String - sw $t2, 0($v0) - li $t2, 7 - sw $t2, 4($v0) - la $t2, string_2 - sw $t2, 8($v0) - END_IF_2: + lw $t1, -4($fp) + lw $t3, 4($t1) + sw $t3, 16($fp) + #Executing Int Complement + lw $t2, 16($fp) + not $t4, $t2 + addi $t4, $t4, 1 + sw $t4, 12($fp) #Receiving Arg local_Main_main_internal_1 - lw $t2, 4($fp) - sw $t2, 0($sp) + lw $t1, 4($fp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Receiving Arg local_Main_main_internal_3 lw $t9, 12($fp) @@ -698,39 +710,10 @@ Main_main: addi $sp, $sp, 4 #Executing Dynamic Call lw $t2, 8($fp) - lw $t5, 12($t2) + lw $t5, 16($t2) jalr $t5 sw $a1, 0($fp) addi $sp, $sp, -8 - #Executing Assign - lw $t9, -4($fp) - sw $t9, 36($fp) - #Executing typeof - lw $t1, 36($fp) - lw $t1, 0($t1) - sw $t1, 40($fp) - #Executing GetAttr - lw $t4, -4($fp) - lw $t3, 4($t4) - sw $t3, 48($fp) - lw $t9, 48($fp) - not $t5, $t9 - addi $t5, $t5, 1 - sw $t5, 44($fp) - #Receiving Arg local_Main_main_internal_9 - lw $t4, 36($fp) - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Receiving Arg local_Main_main_internal_11 - lw $t5, 44($fp) - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Executing Dynamic Call - lw $t3, 40($fp) - lw $t4, 16($t3) - jalr $t4 - sw $a1, 0($fp) - addi $sp, $sp, -8 #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -740,6 +723,6 @@ Main_main: addi $sp, $sp, -4 lw $ra, 0($sp) #Cleaning stack after call - addi $sp, $sp, -52 + addi $sp, $sp, -20 #Return jump jalr $ra diff --git a/tests/code_gen/while.mips b/tests/code_gen/while.mips index 082ae61b1..8325b1480 100644 --- a/tests/code_gen/while.mips +++ b/tests/code_gen/while.mips @@ -28,15 +28,15 @@ string_1 : .asciiz, "iteration \n" .globl main length: - li $t5, 0 + li $t1, 0 length_loop: - lb $t4, 0($a0) - beq $zero, $t4, length_end - add $t5, $t5, 1 + lb $t5, 0($a0) + beq $zero, $t5, length_end + add $t1, $t1, 1 add $a0, $a0, 1 j length_loop length_end: - move $a0 $t5 + move $a0 $t1 j $ra copy: copy_loop: @@ -50,7 +50,7 @@ copy: copy_end: j $ra Object_abort: - move $t0 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -59,7 +59,7 @@ Object_abort: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing RuntimeError @@ -71,7 +71,7 @@ Object_abort: li $v0, 10 syscall Object_copy: - move $t0 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -80,7 +80,7 @@ Object_copy: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -96,7 +96,7 @@ Object_copy: #Return jump jalr $ra Object_type_name: - move $t5 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -105,7 +105,7 @@ Object_type_name: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t5, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Return @@ -121,7 +121,7 @@ Object_type_name: #Return jump jalr $ra IO_out_string: - move $t2 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -130,7 +130,7 @@ IO_out_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintStringNode @@ -151,7 +151,7 @@ IO_out_string: #Return jump jalr $ra IO_out_int: - move $t0 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -160,7 +160,7 @@ IO_out_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintIntNode @@ -180,7 +180,7 @@ IO_out_int: #Return jump jalr $ra IO_in_string: - move $t3 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -189,7 +189,7 @@ IO_in_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #ReadStrNode @@ -206,8 +206,8 @@ IO_in_string: li $v0, 9 syscall move $t6 $v0 - move $t1 $v0 - move $t2 $a0 + move $t4 $v0 + move $t3 $a0 #Copying bytes from one char array to another jal copy #Null-terminating the string @@ -217,11 +217,11 @@ IO_in_string: li $a0, 12 syscall sw $v0, 0($fp) - la $t4, String - sw $t4, 0($v0) + la $t2, String + sw $t2, 0($v0) #Storing length and reference to char array - sw $t2, 4($v0) - sw $t1, 8($v0) + sw $t3, 4($v0) + sw $t4, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -235,7 +235,7 @@ IO_in_string: #Return jump jalr $ra IO_in_int: - move $t4 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -244,7 +244,7 @@ IO_in_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #ReadStrNode @@ -261,8 +261,8 @@ IO_in_int: li $v0, 9 syscall move $t6 $v0 - move $t0 $v0 - move $t1 $a0 + move $t4 $v0 + move $t9 $a0 #Copying bytes from one char array to another jal copy #Null-terminating the string @@ -272,11 +272,11 @@ IO_in_int: li $a0, 12 syscall sw $v0, 0($fp) - la $t3, String - sw $t3, 0($v0) + la $t5, String + sw $t5, 0($v0) #Storing length and reference to char array - sw $t1, 4($v0) - sw $t0, 8($v0) + sw $t9, 4($v0) + sw $t4, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -290,7 +290,7 @@ IO_in_int: #Return jump jalr $ra String_length: - move $t2 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -299,13 +299,13 @@ String_length: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Length - lw $t4, -4($fp) - lw $t4, 4($t4) - sw $t4, 0($fp) + lw $t1, -4($fp) + lw $t1, 4($t1) + sw $t1, 0($fp) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -319,7 +319,7 @@ String_length: #Return jump jalr $ra String_concat: - move $t0 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -328,9 +328,44 @@ String_concat: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions + #Loading length + lw $s1, -8($fp) + lw $s1, 4($s1) + lw $s2, -4($fp) + lw $s2, 4($s2) + add $t3, $s1, $s2 + #Allocating new char array + move $a0 $t3 + addi $a0, $a0, 1 + li $v0, 9 + syscall + move $t6 $v0 + move $t5 $v0 + #Copying bytes from first string + lw $t7, -8($fp) + lw $t7, 8($t7) + move $a0 $s1 + jal copy + #Copying bytes from second string + lw $t7, -4($fp) + lw $t7, 8($t7) + move $a0 $s2 + jal copy + #Null-terminating the string + sb $zero, 0($t6) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t2, String + sw $t2, 0($v0) + #Storing length and reference to char array + sw $t3, 4($v0) + sw $t5, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -344,7 +379,7 @@ String_concat: #Return jump jalr $ra String_substr: - move $t5 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -353,9 +388,38 @@ String_substr: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t5, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions + #Executing Substring + lw $s0, -4($fp) + move $a0 $s0 + addi $a0, $a0, 1 + li $v0, 9 + syscall + move $t6 $v0 + #Loading reference to char array of source string + lw $t7, -12($fp) + lw $t7, 8($t7) + lw $s2, -8($fp) + add $t7, $t7, $s2 + move $s1 $t6 + #Copying bytes from one char array to another + move $a0 $s0 + jal copy + #Null-terminating the string + sb $zero, 0($t0) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t5, String + sw $t5, 0($v0) + #Storing length and reference to char array + lw $s0, -4($fp) + sw $s0, 4($v0) + sw $s1, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -369,7 +433,7 @@ String_substr: #Return jump jalr $ra Object_constructor: - move $t5 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -378,7 +442,7 @@ Object_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t5, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -386,8 +450,8 @@ Object_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t3, Object - sw $t3, 0($v0) + la $t4, Object + sw $t4, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -418,8 +482,8 @@ IO_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t2, IO - sw $t2, 0($v0) + la $t0, IO + sw $t0, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -433,7 +497,7 @@ IO_constructor: #Return jump jalr $ra Int_constructor: - move $t9 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -442,7 +506,7 @@ Int_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -450,8 +514,8 @@ Int_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t0, Int - sw $t0, 0($v0) + la $t3, Int + sw $t3, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -465,7 +529,7 @@ Int_constructor: #Return jump jalr $ra Bool_constructor: - move $t0 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -474,7 +538,7 @@ Bool_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -482,8 +546,8 @@ Bool_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t4, Bool - sw $t4, 0($v0) + la $t1, Bool + sw $t1, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -497,7 +561,7 @@ Bool_constructor: #Return jump jalr $ra String_constructor: - move $t9 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -506,7 +570,7 @@ String_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -529,7 +593,7 @@ String_constructor: #Return jump jalr $ra main: - move $t3 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -538,7 +602,7 @@ main: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Static Call @@ -546,8 +610,8 @@ main: sw $a1, 0($fp) addi $sp, $sp, 0 #Receiving Arg local_main_internal_0 - lw $t4, 0($fp) - sw $t4, 0($sp) + lw $t3, 0($fp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing Static Call jal Main_main @@ -556,7 +620,7 @@ main: li $v0, 10 syscall Main_constructor: - move $t1 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -565,7 +629,7 @@ Main_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -573,36 +637,36 @@ Main_constructor: li $a0, 12 syscall sw $v0, 0($fp) - la $t4, Main - sw $t4, 0($v0) + la $t3, Main + sw $t3, 0($v0) #Executing DefaultValue li $t1, 0 sw $t1, 4($fp) #Executing SetAttr lw $t4, 0($fp) - lw $t2, 4($fp) - sw $t2, 4($t4) + lw $t1, 4($fp) + sw $t1, 4($t4) #Executing DefaultValue - li $t5, 0 - sw $t5, 8($fp) + li $t1, 0 + sw $t1, 8($fp) #Executing SetAttr - lw $t4, 0($fp) - lw $t5, 8($fp) - sw $t5, 8($t4) + lw $t3, 0($fp) + lw $t1, 8($fp) + sw $t1, 8($t3) #Executing Assign - li $t9, 0 - sw $t9, 12($fp) + li $t2, 0 + sw $t2, 12($fp) #Executing SetAttr - lw $t3, 0($fp) - lw $t4, 12($fp) - sw $t4, 4($t3) + lw $t9, 0($fp) + lw $t1, 12($fp) + sw $t1, 4($t9) #Executing Assign - li $t0, 3 - sw $t0, 16($fp) + li $t4, 3 + sw $t4, 16($fp) #Executing SetAttr - lw $t1, 0($fp) - lw $t5, 16($fp) - sw $t5, 8($t1) + lw $t4, 0($fp) + lw $t2, 16($fp) + sw $t2, 8($t4) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -616,7 +680,7 @@ Main_constructor: #Return jump jalr $ra Main_main: - move $t9 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -625,106 +689,107 @@ Main_main: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions WHILE_1: #Executing GetAttr - lw $t2, -4($fp) - lw $t9, 4($t2) - sw $t9, 8($fp) - #Executing GetAttr lw $t4, -4($fp) - lw $t0, 8($t4) + lw $t1, 4($t4) + sw $t1, 8($fp) + #Executing GetAttr + lw $t9, -4($fp) + lw $t0, 8($t9) sw $t0, 12($fp) - lw $t3, 8($fp) - lw $t1, 12($fp) - slt $t4, $t3, $t1 - sw $t4, 4($fp) - lw $t2, 4($fp) - bnez $t2, BODY_2 + #Executing Less Operation + lw $t9, 8($fp) + lw $t0, 12($fp) + slt $t3, $t9, $t0 + sw $t3, 4($fp) + lw $t1, 4($fp) + bnez $t1, BODY_2 #Executing Goto j END_WHILE_3 BODY_2: #Executing Assign - lw $t5, -4($fp) - sw $t5, 20($fp) + lw $t0, -4($fp) + sw $t0, 20($fp) #Executing typeof - lw $t3, 20($fp) - lw $t3, 0($t3) - sw $t3, 24($fp) + lw $t9, 20($fp) + lw $t9, 0($t9) + sw $t9, 24($fp) #Executing GetAttr - lw $t0, -4($fp) - lw $t5, 4($t0) - sw $t5, 28($fp) + lw $t2, -4($fp) + lw $t1, 4($t2) + sw $t1, 28($fp) #Receiving Arg local_Main_main_internal_5 - lw $t4, 20($fp) - sw $t4, 0($sp) + lw $t9, 20($fp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Receiving Arg local_Main_main_internal_7 - lw $t2, 28($fp) - sw $t2, 0($sp) + lw $t4, 28($fp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing Dynamic Call - lw $t5, 24($fp) - lw $t0, 16($t5) - jalr $t0 + lw $t1, 24($fp) + lw $t9, 16($t1) + jalr $t9 sw $a1, 16($fp) addi $sp, $sp, -8 #Executing Assign - lw $t2, -4($fp) - sw $t2, 32($fp) + lw $t3, -4($fp) + sw $t3, 32($fp) #Executing typeof - lw $t3, 32($fp) - lw $t3, 0($t3) - sw $t3, 36($fp) + lw $t0, 32($fp) + lw $t0, 0($t0) + sw $t0, 36($fp) #Executing Load li $v0, 9 li $a0, 12 syscall sw $v0, 40($fp) - la $t2, String - sw $t2, 0($v0) - li $t2, 12 - sw $t2, 4($v0) - la $t2, string_1 - sw $t2, 8($v0) + la $t1, String + sw $t1, 0($v0) + li $t1, 12 + sw $t1, 4($v0) + la $t1, string_1 + sw $t1, 8($v0) #Receiving Arg local_Main_main_internal_8 - lw $t2, 32($fp) - sw $t2, 0($sp) + lw $t1, 32($fp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Receiving Arg local_Main_main_internal_10 - lw $t5, 40($fp) - sw $t5, 0($sp) + lw $t2, 40($fp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing Dynamic Call - lw $t3, 36($fp) - lw $t5, 12($t3) - jalr $t5 + lw $t4, 36($fp) + lw $t9, 12($t4) + jalr $t9 sw $a1, 16($fp) addi $sp, $sp, -8 #Executing GetAttr - lw $t3, -4($fp) - lw $t2, 4($t3) - sw $t2, 44($fp) + lw $t1, -4($fp) + lw $t9, 4($t1) + sw $t9, 44($fp) #Executing Assign - li $t5, 1 - sw $t5, 48($fp) + li $t2, 1 + sw $t2, 48($fp) #Executing Plus Operation - lw $t0, 44($fp) - lw $t9, 48($fp) - add $t4, $t0, $t9 - sw $t4, 16($fp) + lw $t1, 44($fp) + lw $t4, 48($fp) + add $t0, $t1, $t4 + sw $t0, 16($fp) #Executing SetAttr - lw $t5, -4($fp) - lw $t3, 16($fp) - sw $t3, 4($t5) + lw $t3, -4($fp) + lw $t9, 16($fp) + sw $t9, 4($t3) #Executing Goto j WHILE_1 END_WHILE_3: #Executing DefaultValue - la $t3, void - sw $t3, 0($fp) + la $t4, void + sw $t4, 0($fp) #Executing Return lw $a1, 0($fp) #Restoring saved $fp From f0138b56b48348936f89134b3a38e876c20d41dc Mon Sep 17 00:00:00 2001 From: smartos99 Date: Wed, 9 Mar 2022 00:54:07 -0500 Subject: [PATCH 134/162] feat: add isvoid test --- tests/code_gen/comparison.mips | 754 ++++++++++--- tests/code_gen/hello_world.mips | 636 ++++++++--- tests/code_gen/is_void.cl | 12 + tests/code_gen/is_void.mips | 1237 ++++++++++++++++++++++ tests/code_gen/is_void_input.txt | 0 tests/code_gen/is_void_output.txt | 1 + tests/code_gen/point.mips | 805 +++++++++++--- tests/code_gen/read_string.mips | 692 +++++++++--- tests/code_gen/string_methods _output.cl | 1 - tests/code_gen/string_methods.mips | 838 +++++++++++---- tests/code_gen/test_goto_if.mips | 748 ++++++++++--- tests/code_gen/unary_nodes.mips | 672 +++++++++--- tests/code_gen/while.mips | 774 ++++++++++---- 13 files changed, 5905 insertions(+), 1265 deletions(-) create mode 100644 tests/code_gen/is_void.cl create mode 100644 tests/code_gen/is_void.mips create mode 100644 tests/code_gen/is_void_input.txt create mode 100644 tests/code_gen/is_void_output.txt delete mode 100644 tests/code_gen/string_methods _output.cl diff --git a/tests/code_gen/comparison.mips b/tests/code_gen/comparison.mips index b387e1c2a..0ae1dc383 100644 --- a/tests/code_gen/comparison.mips +++ b/tests/code_gen/comparison.mips @@ -2,15 +2,15 @@ Object : .word, Object_abort, Object_copy, Object_type_name Object_cname : .asciiz, "Object" -IO : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int +IO : .word, Object_abort, IO_copy, IO_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int IO_cname : .asciiz, "IO" -String : .word, Object_abort, Object_copy, Object_type_name, String_length, String_concat, String_substr +String : .word, Object_abort, String_copy, String_type_name, String_length, String_concat, String_substr String_cname : .asciiz, "String" -Int : .word, Object_abort, Object_copy, Object_type_name +Int : .word, Object_abort, Int_copy, Int_type_name Int_cname : .asciiz, "Int" -Bool : .word, Object_abort, Object_copy, Object_type_name +Bool : .word, Object_abort, Bool_copy, Bool_type_name Bool_cname : .asciiz, "Bool" -Main : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int, Main_main, Main_constructor +Main : .word, Object_abort, Main_copy, Main_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int, Main_main, Main_constructor Main_cname : .asciiz, "Main" void : .word, -1 empty_string : .asciiz, "" @@ -22,6 +22,12 @@ dispatch_on_void : .asciiz, "Dispatch on void" division_by_zero : .asciiz, "Division by zero" substr_out_of_range : .asciiz, "Substring out of range" heap_overflow : .asciiz, "Heap overflow" +type_name_Object : .asciiz, "Object" +type_name_IO : .asciiz, "IO" +type_name_String : .asciiz, "String" +type_name_Int : .asciiz, "Int" +type_name_Bool : .asciiz, "Bool" +type_name_Main : .asciiz, "Main" string_1 : .asciiz, "a>b" string_2 : .asciiz, "a<=b" @@ -29,15 +35,15 @@ string_2 : .asciiz, "a<=b" .globl main length: - li $t9, 0 + li $t1, 0 length_loop: - lb $t2, 0($a0) - beq $zero, $t2, length_end - add $t9, $t9, 1 + lb $t0, 0($a0) + beq $zero, $t0, length_end + add $t1, $t1, 1 add $a0, $a0, 1 j length_loop length_end: - move $a0 $t9 + move $a0 $t1 j $ra copy: copy_loop: @@ -50,8 +56,35 @@ copy: j copy_loop copy_end: j $ra +main: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Static Call + jal Main_constructor + sw $a1, 0($fp) + addi $sp, $sp, 0 + #Receiving Arg local_main_internal_0 + lw $t5, 0($fp) + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing Static Call + jal Main_main + sw $a1, 4($fp) + addi $sp, $sp, -4 + li $v0, 10 + syscall Object_abort: - move $t5 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -60,7 +93,7 @@ Object_abort: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t5, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing RuntimeError @@ -72,7 +105,7 @@ Object_abort: li $v0, 10 syscall Object_copy: - move $t2 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -81,9 +114,16 @@ Object_copy: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t5, Object + sw $t5, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -101,7 +141,7 @@ Object_type_name: #New $fp move $fp $sp #Reserving space for locals - addi $sp, $sp, 4 + addi $sp, $sp, 8 #Pushing $ra sw $ra, 0($sp) addi $sp, $sp, 4 @@ -109,6 +149,59 @@ Object_type_name: sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t5, String + sw $t5, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t9, String + sw $t9, 0($v0) + li $t9, 6 + sw $t9, 4($v0) + la $t9, type_name_Object + sw $t9, 8($v0) + #Executing Assign + lw $t4, 4($fp) + sw $t4, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra +IO_copy: + move $t3 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t5, IO + sw $t5, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -121,8 +214,54 @@ Object_type_name: addi $sp, $sp, -4 #Return jump jalr $ra +IO_type_name: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t5, String + sw $t5, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t9, String + sw $t9, 0($v0) + li $t9, 2 + sw $t9, 4($v0) + la $t9, type_name_IO + sw $t9, 8($v0) + #Executing Assign + lw $t5, 4($fp) + sw $t5, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra IO_out_string: - move $t9 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -131,7 +270,7 @@ IO_out_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintStringNode @@ -152,7 +291,7 @@ IO_out_string: #Return jump jalr $ra IO_out_int: - move $t9 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -161,7 +300,7 @@ IO_out_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintIntNode @@ -181,7 +320,7 @@ IO_out_int: #Return jump jalr $ra IO_in_string: - move $t4 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -190,7 +329,7 @@ IO_in_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #ReadStrNode @@ -207,7 +346,7 @@ IO_in_string: li $v0, 9 syscall move $t6 $v0 - move $t1 $v0 + move $t2 $v0 move $t5 $a0 #Copying bytes from one char array to another jal copy @@ -218,11 +357,11 @@ IO_in_string: li $a0, 12 syscall sw $v0, 0($fp) - la $t0, String - sw $t0, 0($v0) + la $t1, String + sw $t1, 0($v0) #Storing length and reference to char array sw $t5, 4($v0) - sw $t1, 8($v0) + sw $t2, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -236,7 +375,7 @@ IO_in_string: #Return jump jalr $ra IO_in_int: - move $t3 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -245,39 +384,91 @@ IO_in_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions - #ReadStrNode - #Reading String to buffer - la $a0, input_str_buffer - li $a1, 1024 - li $v0, 8 + #ReadIntNode + li $v0, 5 syscall - #Saving reference to read string - move $t7 $a0 - #Calculating str length - jal length - #Allocating char array for new string + sw $v0, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_copy: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate li $v0, 9 + li $a0, 12 syscall - move $t6 $v0 - move $t5 $v0 - move $t0 $a0 - #Copying bytes from one char array to another - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance + sw $v0, 0($fp) + la $t0, String + sw $t0, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_type_name: + move $t2 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate li $v0, 9 li $a0, 12 syscall sw $v0, 0($fp) - la $t9, String - sw $t9, 0($v0) - #Storing length and reference to char array - sw $t0, 4($v0) - sw $t5, 8($v0) + la $t3, String + sw $t3, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t2, String + sw $t2, 0($v0) + li $t2, 6 + sw $t2, 4($v0) + la $t2, type_name_String + sw $t2, 8($v0) + #Executing Assign + lw $t2, 4($fp) + sw $t2, 0($fp) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -287,11 +478,11 @@ IO_in_int: addi $sp, $sp, -4 lw $ra, 0($sp) #Cleaning stack after call - addi $sp, $sp, -4 + addi $sp, $sp, -8 #Return jump jalr $ra String_length: - move $t5 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -300,7 +491,7 @@ String_length: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t5, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Length @@ -320,7 +511,7 @@ String_length: #Return jump jalr $ra String_concat: - move $t1 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -329,7 +520,7 @@ String_concat: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Loading length @@ -344,7 +535,7 @@ String_concat: li $v0, 9 syscall move $t6 $v0 - move $t9 $v0 + move $t4 $v0 #Copying bytes from first string lw $t7, -8($fp) lw $t7, 8($t7) @@ -362,11 +553,11 @@ String_concat: li $a0, 12 syscall sw $v0, 0($fp) - la $t5, String - sw $t5, 0($v0) + la $t0, String + sw $t0, 0($v0) #Storing length and reference to char array sw $t2, 4($v0) - sw $t9, 8($v0) + sw $t4, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -380,7 +571,7 @@ String_concat: #Return jump jalr $ra String_substr: - move $t9 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -389,7 +580,7 @@ String_substr: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Substring @@ -409,14 +600,14 @@ String_substr: move $a0 $s0 jal copy #Null-terminating the string - sb $zero, 0($t0) + sb $zero, 0($t6) #Allocating new String instance li $v0, 9 li $a0, 12 syscall sw $v0, 0($fp) - la $t9, String - sw $t9, 0($v0) + la $t0, String + sw $t0, 0($v0) #Storing length and reference to char array lw $s0, -4($fp) sw $s0, 4($v0) @@ -433,8 +624,8 @@ String_substr: addi $sp, $sp, -4 #Return jump jalr $ra -Object_constructor: - move $t3 $fp +Int_copy: + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -443,16 +634,16 @@ Object_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate li $v0, 9 - li $a0, 4 + li $a0, 8 syscall sw $v0, 0($fp) - la $t1, Object - sw $t1, 0($v0) + la $t4, Int + sw $t4, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -465,7 +656,131 @@ Object_constructor: addi $sp, $sp, -4 #Return jump jalr $ra -IO_constructor: +Int_type_name: + move $t5 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t9, String + sw $t9, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t9, String + sw $t9, 0($v0) + li $t9, 3 + sw $t9, 4($v0) + la $t9, type_name_Int + sw $t9, 8($v0) + #Executing Assign + lw $t4, 4($fp) + sw $t4, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra +Bool_copy: + move $t5 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 8 + syscall + sw $v0, 0($fp) + la $t2, Bool + sw $t2, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Bool_type_name: + move $t3 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t1, String + sw $t1, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t1, String + sw $t1, 0($v0) + li $t1, 4 + sw $t1, 4($v0) + la $t1, type_name_Bool + sw $t1, 8($v0) + #Executing Assign + lw $t4, 4($fp) + sw $t4, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra +Object_constructor: move $t1 $fp #New $fp move $fp $sp @@ -483,8 +798,40 @@ IO_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t1, IO - sw $t1, 0($v0) + la $t9, Object + sw $t9, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +IO_constructor: + move $t4 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t2, IO + sw $t2, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -498,7 +845,7 @@ IO_constructor: #Return jump jalr $ra Int_constructor: - move $t3 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -507,7 +854,7 @@ Int_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -530,7 +877,7 @@ Int_constructor: #Return jump jalr $ra Bool_constructor: - move $t5 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -539,7 +886,7 @@ Bool_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t5, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -547,8 +894,8 @@ Bool_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t2, Bool - sw $t2, 0($v0) + la $t1, Bool + sw $t1, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -562,7 +909,7 @@ Bool_constructor: #Return jump jalr $ra String_constructor: - move $t2 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -571,7 +918,7 @@ String_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -593,7 +940,55 @@ String_constructor: addi $sp, $sp, -4 #Return jump jalr $ra -main: +Main_copy: + move $t4 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 12 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t1, Main + sw $t1, 0($v0) + #Executing GetAttr + lw $t3, -4($fp) + lw $t9, 4($t3) + sw $t9, 4($fp) + #Executing SetAttr + lw $t1, 0($fp) + lw $t4, 4($fp) + sw $t4, 4($t1) + #Executing GetAttr + lw $t5, -4($fp) + lw $t3, 8($t5) + sw $t3, 8($fp) + #Executing SetAttr + lw $t2, 0($fp) + lw $t4, 8($fp) + sw $t4, 8($t2) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -12 + #Return jump + jalr $ra +Main_type_name: move $t5 $fp #New $fp move $fp $sp @@ -606,22 +1001,41 @@ main: sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions - #Executing Static Call - jal Main_constructor - sw $a1, 0($fp) - addi $sp, $sp, 0 - #Receiving Arg local_main_internal_0 - lw $t5, 0($fp) - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Executing Static Call - jal Main_main - sw $a1, 4($fp) - addi $sp, $sp, -4 - li $v0, 10 + #Executing Allocate + li $v0, 9 + li $a0, 12 syscall + sw $v0, 0($fp) + la $t4, String + sw $t4, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t9, String + sw $t9, 0($v0) + li $t9, 4 + sw $t9, 4($v0) + la $t9, type_name_Main + sw $t9, 8($v0) + #Executing Assign + lw $t3, 4($fp) + sw $t3, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra Main_constructor: - move $t3 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -630,7 +1044,7 @@ Main_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -641,19 +1055,19 @@ Main_constructor: la $t3, Main sw $t3, 0($v0) #Executing DefaultValue - li $t2, 0 - sw $t2, 4($fp) + li $t9, 0 + sw $t9, 4($fp) #Executing SetAttr lw $t5, 0($fp) - lw $t0, 4($fp) - sw $t0, 4($t5) + lw $t2, 4($fp) + sw $t2, 4($t5) #Executing DefaultValue - li $t3, 0 - sw $t3, 8($fp) + li $t9, 0 + sw $t9, 8($fp) #Executing SetAttr - lw $t0, 0($fp) - lw $t5, 8($fp) - sw $t5, 8($t0) + lw $t2, 0($fp) + lw $t4, 8($fp) + sw $t4, 8($t2) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -667,7 +1081,7 @@ Main_constructor: #Return jump jalr $ra Main_main: - move $t4 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -676,81 +1090,81 @@ Main_main: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing GetAttr - lw $t3, -4($fp) - lw $t4, 4($t3) + lw $t5, -4($fp) + lw $t4, 4($t5) sw $t4, 4($fp) #Executing GetAttr - lw $t4, -4($fp) - lw $t5, 8($t4) - sw $t5, 8($fp) + lw $t1, -4($fp) + lw $t3, 8($t1) + sw $t3, 8($fp) #Executing Less Operation - lw $t1, 4($fp) - lw $t5, 8($fp) - slt $t3, $t1, $t5 + lw $t4, 4($fp) + lw $t9, 8($fp) + slt $t3, $t4, $t9 sw $t3, 0($fp) #Executing GetAttr - lw $t2, -4($fp) - lw $t4, 4($t2) - sw $t4, 12($fp) + lw $t5, -4($fp) + lw $t1, 4($t5) + sw $t1, 12($fp) #Executing GetAttr - lw $t0, -4($fp) - lw $t5, 8($t0) - sw $t5, 16($fp) + lw $t4, -4($fp) + lw $t3, 8($t4) + sw $t3, 16($fp) #Executing Less Equal Operation lw $t3, 12($fp) lw $t5, 16($fp) - sle $t1, $t3, $t5 - sw $t1, 0($fp) + sle $t4, $t3, $t5 + sw $t4, 0($fp) #Executing GetAttr - lw $t2, -4($fp) - lw $t4, 4($t2) - sw $t4, 20($fp) + lw $t3, -4($fp) + lw $t5, 4($t3) + sw $t5, 20($fp) #Executing GetAttr - lw $t0, -4($fp) - lw $t2, 8($t0) - sw $t2, 24($fp) + lw $t5, -4($fp) + lw $t1, 8($t5) + sw $t1, 24($fp) #Executing Equal Operation - lw $t3, 20($fp) - lw $t1, 24($fp) - seq $t4, $t3, $t1 - sw $t4, 0($fp) + lw $t9, 20($fp) + lw $t3, 24($fp) + seq $t5, $t9, $t3 + sw $t5, 0($fp) #Executing Assign - lw $t2, -4($fp) - sw $t2, 28($fp) + lw $t1, -4($fp) + sw $t1, 28($fp) #Executing typeof - lw $t2, 28($fp) - lw $t2, 0($t2) - sw $t2, 32($fp) - #Executing GetAttr - lw $t0, -4($fp) - lw $t5, 4($t0) - sw $t5, 44($fp) + lw $t5, 28($fp) + lw $t5, 0($t5) + sw $t5, 32($fp) #Executing GetAttr lw $t5, -4($fp) - lw $t0, 8($t5) - sw $t0, 48($fp) + lw $t2, 4($t5) + sw $t2, 44($fp) + #Executing GetAttr + lw $t3, -4($fp) + lw $t2, 8($t3) + sw $t2, 48($fp) #Executing Less Equal Operation - lw $t0, 44($fp) - lw $t4, 48($fp) - sle $t1, $t0, $t4 - sw $t1, 40($fp) - lw $t2, 40($fp) - bnez $t2, THEN_1 + lw $t4, 44($fp) + lw $t1, 48($fp) + sle $t9, $t4, $t1 + sw $t9, 40($fp) + lw $t9, 40($fp) + bnez $t9, THEN_1 #Executing Load li $v0, 9 li $a0, 12 syscall sw $v0, 36($fp) - la $t2, String - sw $t2, 0($v0) - li $t2, 3 - sw $t2, 4($v0) - la $t2, string_1 - sw $t2, 8($v0) + la $t5, String + sw $t5, 0($v0) + li $t5, 3 + sw $t5, 4($v0) + la $t5, string_1 + sw $t5, 8($v0) #Executing Goto j END_IF_2 THEN_1: @@ -759,25 +1173,25 @@ Main_main: li $a0, 12 syscall sw $v0, 36($fp) - la $t2, String - sw $t2, 0($v0) - li $t2, 4 - sw $t2, 4($v0) - la $t2, string_2 - sw $t2, 8($v0) + la $t5, String + sw $t5, 0($v0) + li $t5, 4 + sw $t5, 4($v0) + la $t5, string_2 + sw $t5, 8($v0) END_IF_2: #Receiving Arg local_Main_main_internal_7 - lw $t5, 28($fp) - sw $t5, 0($sp) + lw $t3, 28($fp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Receiving Arg local_Main_main_internal_9 - lw $t2, 36($fp) - sw $t2, 0($sp) + lw $t9, 36($fp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing Dynamic Call - lw $t2, 32($fp) - lw $t1, 12($t2) - jalr $t1 + lw $t3, 32($fp) + lw $t5, 12($t3) + jalr $t5 sw $a1, 0($fp) addi $sp, $sp, -8 #Executing Return diff --git a/tests/code_gen/hello_world.mips b/tests/code_gen/hello_world.mips index 1bb10b206..c66bd575e 100644 --- a/tests/code_gen/hello_world.mips +++ b/tests/code_gen/hello_world.mips @@ -2,15 +2,15 @@ Object : .word, Object_abort, Object_copy, Object_type_name Object_cname : .asciiz, "Object" -IO : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int +IO : .word, Object_abort, IO_copy, IO_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int IO_cname : .asciiz, "IO" -String : .word, Object_abort, Object_copy, Object_type_name, String_length, String_concat, String_substr +String : .word, Object_abort, String_copy, String_type_name, String_length, String_concat, String_substr String_cname : .asciiz, "String" -Int : .word, Object_abort, Object_copy, Object_type_name +Int : .word, Object_abort, Int_copy, Int_type_name Int_cname : .asciiz, "Int" -Bool : .word, Object_abort, Object_copy, Object_type_name +Bool : .word, Object_abort, Bool_copy, Bool_type_name Bool_cname : .asciiz, "Bool" -Main : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int, Main_main, Main_constructor +Main : .word, Object_abort, Main_copy, Main_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int, Main_main, Main_constructor Main_cname : .asciiz, "Main" void : .word, -1 empty_string : .asciiz, "" @@ -22,21 +22,27 @@ dispatch_on_void : .asciiz, "Dispatch on void" division_by_zero : .asciiz, "Division by zero" substr_out_of_range : .asciiz, "Substring out of range" heap_overflow : .asciiz, "Heap overflow" +type_name_Object : .asciiz, "Object" +type_name_IO : .asciiz, "IO" +type_name_String : .asciiz, "String" +type_name_Int : .asciiz, "Int" +type_name_Bool : .asciiz, "Bool" +type_name_Main : .asciiz, "Main" string_1 : .asciiz, "Hello, World.\n" .text .globl main length: - li $t9, 0 + li $t2, 0 length_loop: - lb $t0, 0($a0) - beq $zero, $t0, length_end - add $t9, $t9, 1 + lb $t3, 0($a0) + beq $zero, $t3, length_end + add $t2, $t2, 1 add $a0, $a0, 1 j length_loop length_end: - move $a0 $t9 + move $a0 $t2 j $ra copy: copy_loop: @@ -49,8 +55,35 @@ copy: j copy_loop copy_end: j $ra +main: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Static Call + jal Main_constructor + sw $a1, 0($fp) + addi $sp, $sp, 0 + #Receiving Arg local_main_internal_0 + lw $t4, 0($fp) + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing Static Call + jal Main_main + sw $a1, 4($fp) + addi $sp, $sp, -4 + li $v0, 10 + syscall Object_abort: - move $t0 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -59,7 +92,7 @@ Object_abort: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing RuntimeError @@ -71,7 +104,7 @@ Object_abort: li $v0, 10 syscall Object_copy: - move $t1 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -80,9 +113,16 @@ Object_copy: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t1, Object + sw $t1, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -96,7 +136,53 @@ Object_copy: #Return jump jalr $ra Object_type_name: - move $t5 $fp + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t4, String + sw $t4, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t0, String + sw $t0, 0($v0) + li $t0, 6 + sw $t0, 4($v0) + la $t0, type_name_Object + sw $t0, 8($v0) + #Executing Assign + lw $t4, 4($fp) + sw $t4, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra +IO_copy: + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -105,9 +191,16 @@ Object_type_name: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t5, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t0, IO + sw $t0, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -120,6 +213,52 @@ Object_type_name: addi $sp, $sp, -4 #Return jump jalr $ra +IO_type_name: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t2, String + sw $t2, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t3, String + sw $t3, 0($v0) + li $t3, 2 + sw $t3, 4($v0) + la $t3, type_name_IO + sw $t3, 8($v0) + #Executing Assign + lw $t9, 4($fp) + sw $t9, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra IO_out_string: move $t1 $fp #New $fp @@ -151,7 +290,7 @@ IO_out_string: #Return jump jalr $ra IO_out_int: - move $t4 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -160,7 +299,7 @@ IO_out_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintIntNode @@ -180,7 +319,7 @@ IO_out_int: #Return jump jalr $ra IO_in_string: - move $t3 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -189,7 +328,7 @@ IO_in_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions #ReadStrNode @@ -206,8 +345,8 @@ IO_in_string: li $v0, 9 syscall move $t6 $v0 - move $t1 $v0 - move $t0 $a0 + move $t0 $v0 + move $t5 $a0 #Copying bytes from one char array to another jal copy #Null-terminating the string @@ -217,11 +356,11 @@ IO_in_string: li $a0, 12 syscall sw $v0, 0($fp) - la $t9, String - sw $t9, 0($v0) + la $t2, String + sw $t2, 0($v0) #Storing length and reference to char array - sw $t0, 4($v0) - sw $t1, 8($v0) + sw $t5, 4($v0) + sw $t0, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -247,36 +386,88 @@ IO_in_int: sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions - #ReadStrNode - #Reading String to buffer - la $a0, input_str_buffer - li $a1, 1024 - li $v0, 8 + #ReadIntNode + li $v0, 5 syscall - #Saving reference to read string - move $t7 $a0 - #Calculating str length - jal length - #Allocating char array for new string + sw $v0, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_copy: + move $t5 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate li $v0, 9 + li $a0, 12 syscall - move $t6 $v0 - move $t1 $v0 - move $t2 $a0 - #Copying bytes from one char array to another - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance + sw $v0, 0($fp) + la $t9, String + sw $t9, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_type_name: + move $t5 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate li $v0, 9 li $a0, 12 syscall sw $v0, 0($fp) - la $t3, String - sw $t3, 0($v0) - #Storing length and reference to char array - sw $t2, 4($v0) + la $t4, String + sw $t4, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t1, String + sw $t1, 0($v0) + li $t1, 6 + sw $t1, 4($v0) + la $t1, type_name_String sw $t1, 8($v0) + #Executing Assign + lw $t2, 4($fp) + sw $t2, 0($fp) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -286,11 +477,11 @@ IO_in_int: addi $sp, $sp, -4 lw $ra, 0($sp) #Cleaning stack after call - addi $sp, $sp, -4 + addi $sp, $sp, -8 #Return jump jalr $ra String_length: - move $t9 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -299,13 +490,13 @@ String_length: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Length - lw $t2, -4($fp) - lw $t2, 4($t2) - sw $t2, 0($fp) + lw $t3, -4($fp) + lw $t3, 4($t3) + sw $t3, 0($fp) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -319,7 +510,7 @@ String_length: #Return jump jalr $ra String_concat: - move $t0 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -328,7 +519,7 @@ String_concat: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Loading length @@ -336,9 +527,9 @@ String_concat: lw $s1, 4($s1) lw $s2, -4($fp) lw $s2, 4($s2) - add $t2, $s1, $s2 + add $t9, $s1, $s2 #Allocating new char array - move $a0 $t2 + move $a0 $t9 addi $a0, $a0, 1 li $v0, 9 syscall @@ -364,7 +555,7 @@ String_concat: la $t0, String sw $t0, 0($v0) #Storing length and reference to char array - sw $t2, 4($v0) + sw $t9, 4($v0) sw $t1, 8($v0) #Executing Return lw $a1, 0($fp) @@ -408,14 +599,14 @@ String_substr: move $a0 $s0 jal copy #Null-terminating the string - sb $zero, 0($t0) + sb $zero, 0($t6) #Allocating new String instance li $v0, 9 li $a0, 12 syscall sw $v0, 0($fp) - la $t9, String - sw $t9, 0($v0) + la $t3, String + sw $t3, 0($v0) #Storing length and reference to char array lw $s0, -4($fp) sw $s0, 4($v0) @@ -432,8 +623,164 @@ String_substr: addi $sp, $sp, -4 #Return jump jalr $ra +Int_copy: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 8 + syscall + sw $v0, 0($fp) + la $t4, Int + sw $t4, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Int_type_name: + move $t2 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t5, String + sw $t5, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t5, String + sw $t5, 0($v0) + li $t5, 3 + sw $t5, 4($v0) + la $t5, type_name_Int + sw $t5, 8($v0) + #Executing Assign + lw $t2, 4($fp) + sw $t2, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra +Bool_copy: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 8 + syscall + sw $v0, 0($fp) + la $t1, Bool + sw $t1, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Bool_type_name: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t9, String + sw $t9, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t1, String + sw $t1, 0($v0) + li $t1, 4 + sw $t1, 4($v0) + la $t1, type_name_Bool + sw $t1, 8($v0) + #Executing Assign + lw $t9, 4($fp) + sw $t9, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra Object_constructor: - move $t4 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -442,7 +789,7 @@ Object_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -450,8 +797,8 @@ Object_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t2, Object - sw $t2, 0($v0) + la $t9, Object + sw $t9, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -465,7 +812,7 @@ Object_constructor: #Return jump jalr $ra IO_constructor: - move $t0 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -474,7 +821,7 @@ IO_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -482,8 +829,8 @@ IO_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t2, IO - sw $t2, 0($v0) + la $t9, IO + sw $t9, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -497,7 +844,7 @@ IO_constructor: #Return jump jalr $ra Int_constructor: - move $t1 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -506,7 +853,7 @@ Int_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -514,8 +861,8 @@ Int_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t3, Int - sw $t3, 0($v0) + la $t1, Int + sw $t1, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -529,7 +876,7 @@ Int_constructor: #Return jump jalr $ra Bool_constructor: - move $t2 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -538,7 +885,7 @@ Bool_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -546,8 +893,8 @@ Bool_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t2, Bool - sw $t2, 0($v0) + la $t9, Bool + sw $t9, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -578,7 +925,39 @@ String_constructor: li $a0, 12 syscall sw $v0, 0($fp) - la $t1, String + la $t0, String + sw $t0, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Main_copy: + move $t5 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t1, Main sw $t1, 0($v0) #Executing Return lw $a1, 0($fp) @@ -592,8 +971,8 @@ String_constructor: addi $sp, $sp, -4 #Return jump jalr $ra -main: - move $t4 $fp +Main_type_name: + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -602,25 +981,44 @@ main: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions - #Executing Static Call - jal Main_constructor - sw $a1, 0($fp) - addi $sp, $sp, 0 - #Receiving Arg local_main_internal_0 - lw $t1, 0($fp) - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Executing Static Call - jal Main_main - sw $a1, 4($fp) - addi $sp, $sp, -4 - li $v0, 10 + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t4, String + sw $t4, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 syscall + sw $v0, 4($fp) + la $t1, String + sw $t1, 0($v0) + li $t1, 4 + sw $t1, 4($v0) + la $t1, type_name_Main + sw $t1, 8($v0) + #Executing Assign + lw $t2, 4($fp) + sw $t2, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra Main_constructor: - move $t4 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -629,7 +1027,7 @@ Main_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -637,8 +1035,8 @@ Main_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t3, Main - sw $t3, 0($v0) + la $t0, Main + sw $t0, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -652,7 +1050,7 @@ Main_constructor: #Return jump jalr $ra Main_main: - move $t4 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -661,39 +1059,39 @@ Main_main: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Assign - lw $t2, -4($fp) - sw $t2, 4($fp) + lw $t0, -4($fp) + sw $t0, 4($fp) #Executing typeof - lw $t2, 4($fp) - lw $t2, 0($t2) - sw $t2, 8($fp) + lw $t0, 4($fp) + lw $t0, 0($t0) + sw $t0, 8($fp) #Executing Load li $v0, 9 li $a0, 12 syscall sw $v0, 12($fp) - la $t5, String - sw $t5, 0($v0) - li $t5, 15 - sw $t5, 4($v0) - la $t5, string_1 - sw $t5, 8($v0) + la $t2, String + sw $t2, 0($v0) + li $t2, 15 + sw $t2, 4($v0) + la $t2, string_1 + sw $t2, 8($v0) #Receiving Arg local_Main_main_internal_1 - lw $t1, 4($fp) - sw $t1, 0($sp) + lw $t4, 4($fp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Receiving Arg local_Main_main_internal_3 - lw $t5, 12($fp) - sw $t5, 0($sp) + lw $t1, 12($fp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing Dynamic Call - lw $t0, 8($fp) - lw $t2, 12($t0) - jalr $t2 + lw $t5, 8($fp) + lw $t1, 12($t5) + jalr $t1 sw $a1, 0($fp) addi $sp, $sp, -8 #Executing Return diff --git a/tests/code_gen/is_void.cl b/tests/code_gen/is_void.cl new file mode 100644 index 000000000..5b6327b91 --- /dev/null +++ b/tests/code_gen/is_void.cl @@ -0,0 +1,12 @@ +class Main inherits IO{ + a : Int <- 0; + b : Int <- 3; + main (): Object { + { + if isvoid while a < b loop { + a <- a + 1; + } + pool then out_string("YEI") else out_string("Ou nou") fi; + } + }; +}; \ No newline at end of file diff --git a/tests/code_gen/is_void.mips b/tests/code_gen/is_void.mips new file mode 100644 index 000000000..02c891e36 --- /dev/null +++ b/tests/code_gen/is_void.mips @@ -0,0 +1,1237 @@ +.data + +Object : .word, Object_abort, Object_copy, Object_type_name +Object_cname : .asciiz, "Object" +IO : .word, Object_abort, IO_copy, IO_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int +IO_cname : .asciiz, "IO" +String : .word, Object_abort, String_copy, String_type_name, String_length, String_concat, String_substr +String_cname : .asciiz, "String" +Int : .word, Object_abort, Int_copy, Int_type_name +Int_cname : .asciiz, "Int" +Bool : .word, Object_abort, Bool_copy, Bool_type_name +Bool_cname : .asciiz, "Bool" +Main : .word, Object_abort, Main_copy, Main_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int, Main_main, Main_constructor +Main_cname : .asciiz, "Main" +void : .word, -1 +empty_string : .asciiz, "" +input_str_buffer : .space, 1024 +abort_signal : .asciiz, "Program execution aborted" +case_missmatch : .asciiz, "Execution of a case statement without a matching branch" +case_on_void : .asciiz, "Case on void" +dispatch_on_void : .asciiz, "Dispatch on void" +division_by_zero : .asciiz, "Division by zero" +substr_out_of_range : .asciiz, "Substring out of range" +heap_overflow : .asciiz, "Heap overflow" +type_name_Object : .asciiz, "Object" +type_name_IO : .asciiz, "IO" +type_name_String : .asciiz, "String" +type_name_Int : .asciiz, "Int" +type_name_Bool : .asciiz, "Bool" +type_name_Main : .asciiz, "Main" +string_1 : .asciiz, "Ou nou" +string_2 : .asciiz, "YEI" + +.text +.globl main + +length: + li $t4, 0 + length_loop: + lb $t3, 0($a0) + beq $zero, $t3, length_end + add $t4, $t4, 1 + add $a0, $a0, 1 + j length_loop + length_end: + move $a0 $t4 + j $ra +copy: + copy_loop: + beq $zero, $a0, copy_end + lb $t8, 0($t7) + sb $t8, 0($t6) + addi $t6, $t6, 1 + addi $t7, $t7, 1 + addi $a0, $a0, -1 + j copy_loop + copy_end: + j $ra +main: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Static Call + jal Main_constructor + sw $a1, 0($fp) + addi $sp, $sp, 0 + #Receiving Arg local_main_internal_0 + lw $t5, 0($fp) + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing Static Call + jal Main_main + sw $a1, 4($fp) + addi $sp, $sp, -4 + li $v0, 10 + syscall +Object_abort: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 0 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing RuntimeError + #Printing Abort Message + la $a0, abort_signal + li $v0, 4 + syscall + #Aborting execution + li $v0, 10 + syscall +Object_copy: + move $t5 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t9, Object + sw $t9, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Object_type_name: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t2, String + sw $t2, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t9, String + sw $t9, 0($v0) + li $t9, 6 + sw $t9, 4($v0) + la $t9, type_name_Object + sw $t9, 8($v0) + #Executing Assign + lw $t3, 4($fp) + sw $t3, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra +IO_copy: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t4, IO + sw $t4, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +IO_type_name: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t3, String + sw $t3, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t3, String + sw $t3, 0($v0) + li $t3, 2 + sw $t3, 4($v0) + la $t3, type_name_IO + sw $t3, 8($v0) + #Executing Assign + lw $t3, 4($fp) + sw $t3, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra +IO_out_string: + move $t5 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 0 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #PrintStringNode + lw $a0, -4($fp) + lw $a0, 8($a0) + li $v0, 4 + syscall + #Executing Return + lw $a1, -8($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, 0 + #Return jump + jalr $ra +IO_out_int: + move $t4 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 0 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #PrintIntNode + lw $a0, -4($fp) + li $v0, 1 + syscall + #Executing Return + lw $a1, -8($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, 0 + #Return jump + jalr $ra +IO_in_string: + move $t2 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #ReadStrNode + #Reading String to buffer + la $a0, input_str_buffer + li $a1, 1024 + li $v0, 8 + syscall + #Saving reference to read string + move $t7 $a0 + #Calculating str length + jal length + #Allocating char array for new string + li $v0, 9 + syscall + move $t6 $v0 + move $t0 $v0 + move $t3 $a0 + #Copying bytes from one char array to another + jal copy + #Null-terminating the string + sb $zero, 0($t6) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t5, String + sw $t5, 0($v0) + #Storing length and reference to char array + sw $t3, 4($v0) + sw $t0, 8($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +IO_in_int: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #ReadIntNode + li $v0, 5 + syscall + sw $v0, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_copy: + move $t4 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t2, String + sw $t2, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_type_name: + move $t4 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t3, String + sw $t3, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t3, String + sw $t3, 0($v0) + li $t3, 6 + sw $t3, 4($v0) + la $t3, type_name_String + sw $t3, 8($v0) + #Executing Assign + lw $t9, 4($fp) + sw $t9, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra +String_length: + move $t4 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Length + lw $t3, -4($fp) + lw $t3, 4($t3) + sw $t3, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_concat: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Loading length + lw $s1, -8($fp) + lw $s1, 4($s1) + lw $s2, -4($fp) + lw $s2, 4($s2) + add $t2, $s1, $s2 + #Allocating new char array + move $a0 $t2 + addi $a0, $a0, 1 + li $v0, 9 + syscall + move $t6 $v0 + move $t0 $v0 + #Copying bytes from first string + lw $t7, -8($fp) + lw $t7, 8($t7) + move $a0 $s1 + jal copy + #Copying bytes from second string + lw $t7, -4($fp) + lw $t7, 8($t7) + move $a0 $s2 + jal copy + #Null-terminating the string + sb $zero, 0($t6) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t1, String + sw $t1, 0($v0) + #Storing length and reference to char array + sw $t2, 4($v0) + sw $t0, 8($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_substr: + move $t4 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Substring + lw $s0, -4($fp) + move $a0 $s0 + addi $a0, $a0, 1 + li $v0, 9 + syscall + move $t6 $v0 + #Loading reference to char array of source string + lw $t7, -12($fp) + lw $t7, 8($t7) + lw $s2, -8($fp) + add $t7, $t7, $s2 + move $s1 $t6 + #Copying bytes from one char array to another + move $a0 $s0 + jal copy + #Null-terminating the string + sb $zero, 0($t6) + #Allocating new String instance + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t2, String + sw $t2, 0($v0) + #Storing length and reference to char array + lw $s0, -4($fp) + sw $s0, 4($v0) + sw $s1, 8($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Int_copy: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 8 + syscall + sw $v0, 0($fp) + la $t1, Int + sw $t1, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Int_type_name: + move $t4 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t3, String + sw $t3, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t3, String + sw $t3, 0($v0) + li $t3, 3 + sw $t3, 4($v0) + la $t3, type_name_Int + sw $t3, 8($v0) + #Executing Assign + lw $t9, 4($fp) + sw $t9, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra +Bool_copy: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 8 + syscall + sw $v0, 0($fp) + la $t0, Bool + sw $t0, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Bool_type_name: + move $t3 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t1, String + sw $t1, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t5, String + sw $t5, 0($v0) + li $t5, 4 + sw $t5, 4($v0) + la $t5, type_name_Bool + sw $t5, 8($v0) + #Executing Assign + lw $t1, 4($fp) + sw $t1, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra +Object_constructor: + move $t5 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t1, Object + sw $t1, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +IO_constructor: + move $t3 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t0, IO + sw $t0, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Int_constructor: + move $t4 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 8 + syscall + sw $v0, 0($fp) + la $t0, Int + sw $t0, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Bool_constructor: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 8 + syscall + sw $v0, 0($fp) + la $t5, Bool + sw $t5, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_constructor: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t9, String + sw $t9, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Main_copy: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 12 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t9, Main + sw $t9, 0($v0) + #Executing GetAttr + lw $t0, -4($fp) + lw $t5, 4($t0) + sw $t5, 4($fp) + #Executing SetAttr + lw $t3, 0($fp) + lw $t5, 4($fp) + sw $t5, 4($t3) + #Executing GetAttr + lw $t3, -4($fp) + lw $t4, 8($t3) + sw $t4, 8($fp) + #Executing SetAttr + lw $t0, 0($fp) + lw $t9, 8($fp) + sw $t9, 8($t0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -12 + #Return jump + jalr $ra +Main_type_name: + move $t5 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t3, String + sw $t3, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t4, String + sw $t4, 0($v0) + li $t4, 4 + sw $t4, 4($v0) + la $t4, type_name_Main + sw $t4, 8($v0) + #Executing Assign + lw $t0, 4($fp) + sw $t0, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra +Main_constructor: + move $t4 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 20 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t5, Main + sw $t5, 0($v0) + #Executing DefaultValue + li $t0, 0 + sw $t0, 4($fp) + #Executing SetAttr + lw $t3, 0($fp) + lw $t4, 4($fp) + sw $t4, 4($t3) + #Executing DefaultValue + li $t1, 0 + sw $t1, 8($fp) + #Executing SetAttr + lw $t1, 0($fp) + lw $t3, 8($fp) + sw $t3, 8($t1) + #Executing Assign + li $t3, 0 + sw $t3, 12($fp) + #Executing SetAttr + lw $t4, 0($fp) + lw $t0, 12($fp) + sw $t0, 4($t4) + #Executing Assign + li $t1, 3 + sw $t1, 16($fp) + #Executing SetAttr + lw $t3, 0($fp) + lw $t5, 16($fp) + sw $t5, 8($t3) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -20 + #Return jump + jalr $ra +Main_main: + move $t4 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 60 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + WHILE_1: + #Executing GetAttr + lw $t5, -4($fp) + lw $t4, 4($t5) + sw $t4, 16($fp) + #Executing GetAttr + lw $t5, -4($fp) + lw $t9, 8($t5) + sw $t9, 20($fp) + #Executing Less Operation + lw $t0, 16($fp) + lw $t1, 20($fp) + slt $t3, $t0, $t1 + sw $t3, 12($fp) + lw $t4, 12($fp) + bnez $t4, BODY_2 + #Executing Goto + j END_WHILE_3 + BODY_2: + #Executing GetAttr + lw $t5, -4($fp) + lw $t9, 4($t5) + sw $t9, 28($fp) + #Executing Assign + li $t5, 1 + sw $t5, 32($fp) + #Executing Plus Operation + lw $t5, 28($fp) + lw $t1, 32($fp) + add $t9, $t5, $t1 + sw $t9, 24($fp) + #Executing SetAttr + lw $t1, -4($fp) + lw $t0, 24($fp) + sw $t0, 4($t1) + #Executing Goto + j WHILE_1 + END_WHILE_3: + #Executing DefaultValue + la $t5, void + sw $t5, 8($fp) + #Executing IsVoid + lw $t0, 8($fp) + la $t5, void + seq $t0, $t0, $t5 + sw $t0, 4($fp) + lw $t3, 4($fp) + bnez $t3, THEN_4 + #Executing Assign + lw $t4, -4($fp) + sw $t4, 36($fp) + #Executing typeof + lw $t1, 36($fp) + lw $t1, 0($t1) + sw $t1, 40($fp) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 44($fp) + la $t0, String + sw $t0, 0($v0) + li $t0, 6 + sw $t0, 4($v0) + la $t0, string_1 + sw $t0, 8($v0) + #Receiving Arg local_Main_main_internal_9 + lw $t4, 36($fp) + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Receiving Arg local_Main_main_internal_11 + lw $t3, 44($fp) + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing Dynamic Call + lw $t4, 40($fp) + lw $t9, 12($t4) + jalr $t9 + sw $a1, 0($fp) + addi $sp, $sp, -8 + #Executing Goto + j END_IF_5 + THEN_4: + #Executing Assign + lw $t9, -4($fp) + sw $t9, 48($fp) + #Executing typeof + lw $t5, 48($fp) + lw $t5, 0($t5) + sw $t5, 52($fp) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 56($fp) + la $t3, String + sw $t3, 0($v0) + li $t3, 3 + sw $t3, 4($v0) + la $t3, string_2 + sw $t3, 8($v0) + #Receiving Arg local_Main_main_internal_12 + lw $t5, 48($fp) + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Receiving Arg local_Main_main_internal_14 + lw $t4, 56($fp) + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing Dynamic Call + lw $t4, 52($fp) + lw $t3, 12($t4) + jalr $t3 + sw $a1, 0($fp) + addi $sp, $sp, -8 + END_IF_5: + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -60 + #Return jump + jalr $ra diff --git a/tests/code_gen/is_void_input.txt b/tests/code_gen/is_void_input.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/code_gen/is_void_output.txt b/tests/code_gen/is_void_output.txt new file mode 100644 index 000000000..2433fb4b4 --- /dev/null +++ b/tests/code_gen/is_void_output.txt @@ -0,0 +1 @@ +YEI \ No newline at end of file diff --git a/tests/code_gen/point.mips b/tests/code_gen/point.mips index d4f4676de..3d8467279 100644 --- a/tests/code_gen/point.mips +++ b/tests/code_gen/point.mips @@ -2,17 +2,17 @@ Object : .word, Object_abort, Object_copy, Object_type_name Object_cname : .asciiz, "Object" -IO : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int +IO : .word, Object_abort, IO_copy, IO_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int IO_cname : .asciiz, "IO" -String : .word, Object_abort, Object_copy, Object_type_name, String_length, String_concat, String_substr +String : .word, Object_abort, String_copy, String_type_name, String_length, String_concat, String_substr String_cname : .asciiz, "String" -Int : .word, Object_abort, Object_copy, Object_type_name +Int : .word, Object_abort, Int_copy, Int_type_name Int_cname : .asciiz, "Int" -Bool : .word, Object_abort, Object_copy, Object_type_name +Bool : .word, Object_abort, Bool_copy, Bool_type_name Bool_cname : .asciiz, "Bool" -Main : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int, Main_main, Main_constructor +Main : .word, Object_abort, Main_copy, Main_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int, Main_main, Main_constructor Main_cname : .asciiz, "Main" -Point : .word, Object_abort, Object_copy, Object_type_name, Point_init, Point_constructor +Point : .word, Object_abort, Point_copy, Point_type_name, Point_init, Point_constructor Point_cname : .asciiz, "Point" void : .word, -1 empty_string : .asciiz, "" @@ -24,20 +24,27 @@ dispatch_on_void : .asciiz, "Dispatch on void" division_by_zero : .asciiz, "Division by zero" substr_out_of_range : .asciiz, "Substring out of range" heap_overflow : .asciiz, "Heap overflow" +type_name_Object : .asciiz, "Object" +type_name_IO : .asciiz, "IO" +type_name_String : .asciiz, "String" +type_name_Int : .asciiz, "Int" +type_name_Bool : .asciiz, "Bool" +type_name_Main : .asciiz, "Main" +type_name_Point : .asciiz, "Point" .text .globl main length: - li $t4, 0 + li $t3, 0 length_loop: - lb $t5, 0($a0) - beq $zero, $t5, length_end - add $t4, $t4, 1 + lb $t1, 0($a0) + beq $zero, $t1, length_end + add $t3, $t3, 1 add $a0, $a0, 1 j length_loop length_end: - move $a0 $t4 + move $a0 $t3 j $ra copy: copy_loop: @@ -50,8 +57,35 @@ copy: j copy_loop copy_end: j $ra +main: + move $t2 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Static Call + jal Main_constructor + sw $a1, 0($fp) + addi $sp, $sp, 0 + #Receiving Arg local_main_internal_0 + lw $t5, 0($fp) + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing Static Call + jal Main_main + sw $a1, 4($fp) + addi $sp, $sp, -4 + li $v0, 10 + syscall Object_abort: - move $t4 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -60,7 +94,7 @@ Object_abort: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing RuntimeError @@ -72,7 +106,7 @@ Object_abort: li $v0, 10 syscall Object_copy: - move $t1 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -81,9 +115,16 @@ Object_copy: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t5, Object + sw $t5, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -97,7 +138,53 @@ Object_copy: #Return jump jalr $ra Object_type_name: - move $t2 $fp + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t2, String + sw $t2, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t2, String + sw $t2, 0($v0) + li $t2, 6 + sw $t2, 4($v0) + la $t2, type_name_Object + sw $t2, 8($v0) + #Executing Assign + lw $t1, 4($fp) + sw $t1, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra +IO_copy: + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -106,9 +193,16 @@ Object_type_name: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t4, IO + sw $t4, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -121,6 +215,52 @@ Object_type_name: addi $sp, $sp, -4 #Return jump jalr $ra +IO_type_name: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t9, String + sw $t9, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t1, String + sw $t1, 0($v0) + li $t1, 2 + sw $t1, 4($v0) + la $t1, type_name_IO + sw $t1, 8($v0) + #Executing Assign + lw $t1, 4($fp) + sw $t1, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra IO_out_string: move $t9 $fp #New $fp @@ -152,7 +292,7 @@ IO_out_string: #Return jump jalr $ra IO_out_int: - move $t9 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -161,7 +301,7 @@ IO_out_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintIntNode @@ -181,7 +321,7 @@ IO_out_int: #Return jump jalr $ra IO_in_string: - move $t1 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -190,7 +330,7 @@ IO_in_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions #ReadStrNode @@ -207,7 +347,7 @@ IO_in_string: li $v0, 9 syscall move $t6 $v0 - move $t0 $v0 + move $t1 $v0 move $t4 $a0 #Copying bytes from one char array to another jal copy @@ -222,7 +362,7 @@ IO_in_string: sw $t3, 0($v0) #Storing length and reference to char array sw $t4, 4($v0) - sw $t0, 8($v0) + sw $t1, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -248,36 +388,88 @@ IO_in_int: sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions - #ReadStrNode - #Reading String to buffer - la $a0, input_str_buffer - li $a1, 1024 - li $v0, 8 + #ReadIntNode + li $v0, 5 syscall - #Saving reference to read string - move $t7 $a0 - #Calculating str length - jal length - #Allocating char array for new string + sw $v0, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_copy: + move $t3 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate li $v0, 9 + li $a0, 12 syscall - move $t6 $v0 - move $t5 $v0 - move $t0 $a0 - #Copying bytes from one char array to another - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance + sw $v0, 0($fp) + la $t0, String + sw $t0, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_type_name: + move $t4 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate li $v0, 9 li $a0, 12 syscall sw $v0, 0($fp) la $t1, String sw $t1, 0($v0) - #Storing length and reference to char array - sw $t0, 4($v0) - sw $t5, 8($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t2, String + sw $t2, 0($v0) + li $t2, 6 + sw $t2, 4($v0) + la $t2, type_name_String + sw $t2, 8($v0) + #Executing Assign + lw $t5, 4($fp) + sw $t5, 0($fp) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -287,11 +479,11 @@ IO_in_int: addi $sp, $sp, -4 lw $ra, 0($sp) #Cleaning stack after call - addi $sp, $sp, -4 + addi $sp, $sp, -8 #Return jump jalr $ra String_length: - move $t5 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -300,13 +492,13 @@ String_length: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t5, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Length - lw $t3, -4($fp) - lw $t3, 4($t3) - sw $t3, 0($fp) + lw $t4, -4($fp) + lw $t4, 4($t4) + sw $t4, 0($fp) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -320,7 +512,7 @@ String_length: #Return jump jalr $ra String_concat: - move $t3 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -329,7 +521,7 @@ String_concat: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Loading length @@ -337,14 +529,14 @@ String_concat: lw $s1, 4($s1) lw $s2, -4($fp) lw $s2, 4($s2) - add $t9, $s1, $s2 + add $t2, $s1, $s2 #Allocating new char array - move $a0 $t9 + move $a0 $t2 addi $a0, $a0, 1 li $v0, 9 syscall move $t6 $v0 - move $t4 $v0 + move $t0 $v0 #Copying bytes from first string lw $t7, -8($fp) lw $t7, 8($t7) @@ -362,11 +554,11 @@ String_concat: li $a0, 12 syscall sw $v0, 0($fp) - la $t2, String - sw $t2, 0($v0) + la $t4, String + sw $t4, 0($v0) #Storing length and reference to char array - sw $t9, 4($v0) - sw $t4, 8($v0) + sw $t2, 4($v0) + sw $t0, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -380,7 +572,7 @@ String_concat: #Return jump jalr $ra String_substr: - move $t3 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -389,7 +581,7 @@ String_substr: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Substring @@ -409,14 +601,14 @@ String_substr: move $a0 $s0 jal copy #Null-terminating the string - sb $zero, 0($t0) + sb $zero, 0($t6) #Allocating new String instance li $v0, 9 li $a0, 12 syscall sw $v0, 0($fp) - la $t4, String - sw $t4, 0($v0) + la $t3, String + sw $t3, 0($v0) #Storing length and reference to char array lw $s0, -4($fp) sw $s0, 4($v0) @@ -433,7 +625,7 @@ String_substr: addi $sp, $sp, -4 #Return jump jalr $ra -Object_constructor: +Int_copy: move $t5 $fp #New $fp move $fp $sp @@ -448,11 +640,11 @@ Object_constructor: #Executing instructions #Executing Allocate li $v0, 9 - li $a0, 4 + li $a0, 8 syscall sw $v0, 0($fp) - la $t1, Object - sw $t1, 0($v0) + la $t0, Int + sw $t0, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -465,25 +657,149 @@ Object_constructor: addi $sp, $sp, -4 #Return jump jalr $ra -IO_constructor: - move $t9 $fp +Int_type_name: + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals - addi $sp, $sp, 4 + addi $sp, $sp, 8 #Pushing $ra sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate li $v0, 9 - li $a0, 4 + li $a0, 12 syscall sw $v0, 0($fp) - la $t1, IO + la $t0, String + sw $t0, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t1, String + sw $t1, 0($v0) + li $t1, 3 + sw $t1, 4($v0) + la $t1, type_name_Int + sw $t1, 8($v0) + #Executing Assign + lw $t9, 4($fp) + sw $t9, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra +Bool_copy: + move $t2 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 8 + syscall + sw $v0, 0($fp) + la $t9, Bool + sw $t9, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Bool_type_name: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t2, String + sw $t2, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t5, String + sw $t5, 0($v0) + li $t5, 4 + sw $t5, 4($v0) + la $t5, type_name_Bool + sw $t5, 8($v0) + #Executing Assign + lw $t0, 4($fp) + sw $t0, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra +Object_constructor: + move $t5 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t1, Object sw $t1, 0($v0) #Executing Return lw $a1, 0($fp) @@ -497,8 +813,40 @@ IO_constructor: addi $sp, $sp, -4 #Return jump jalr $ra +IO_constructor: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t0, IO + sw $t0, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra Int_constructor: - move $t1 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -507,7 +855,7 @@ Int_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -515,8 +863,8 @@ Int_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t0, Int - sw $t0, 0($v0) + la $t5, Int + sw $t5, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -530,7 +878,7 @@ Int_constructor: #Return jump jalr $ra Bool_constructor: - move $t3 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -539,7 +887,7 @@ Bool_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -547,8 +895,8 @@ Bool_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t3, Bool - sw $t3, 0($v0) + la $t1, Bool + sw $t1, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -562,6 +910,38 @@ Bool_constructor: #Return jump jalr $ra String_constructor: + move $t5 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t0, String + sw $t0, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Main_copy: move $t9 $fp #New $fp move $fp $sp @@ -576,11 +956,11 @@ String_constructor: #Executing instructions #Executing Allocate li $v0, 9 - li $a0, 12 + li $a0, 4 syscall sw $v0, 0($fp) - la $t5, String - sw $t5, 0($v0) + la $t4, Main + sw $t4, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -593,8 +973,8 @@ String_constructor: addi $sp, $sp, -4 #Return jump jalr $ra -main: - move $t3 $fp +Main_type_name: + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -603,23 +983,42 @@ main: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions - #Executing Static Call - jal Main_constructor - sw $a1, 0($fp) - addi $sp, $sp, 0 - #Receiving Arg local_main_internal_0 - lw $t3, 0($fp) - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing Static Call - jal Main_main - sw $a1, 4($fp) - addi $sp, $sp, -4 - li $v0, 10 + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t4, String + sw $t4, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 syscall + sw $v0, 4($fp) + la $t9, String + sw $t9, 0($v0) + li $t9, 4 + sw $t9, 4($v0) + la $t9, type_name_Main + sw $t9, 8($v0) + #Executing Assign + lw $t1, 4($fp) + sw $t1, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra Main_constructor: move $t2 $fp #New $fp @@ -638,8 +1037,8 @@ Main_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t2, Main - sw $t2, 0($v0) + la $t1, Main + sw $t1, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -653,7 +1052,7 @@ Main_constructor: #Return jump jalr $ra Main_main: - move $t3 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -662,60 +1061,60 @@ Main_main: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Assign - lw $t5, -4($fp) - sw $t5, 4($fp) + lw $t4, -4($fp) + sw $t4, 4($fp) #Executing typeof - lw $t9, 4($fp) - lw $t9, 0($t9) - sw $t9, 8($fp) + lw $t5, 4($fp) + lw $t5, 0($t5) + sw $t5, 8($fp) #Executing Static Call jal Point_constructor sw $a1, 16($fp) addi $sp, $sp, 0 #Executing typeof - lw $t9, 16($fp) - lw $t9, 0($t9) - sw $t9, 20($fp) + lw $t1, 16($fp) + lw $t1, 0($t1) + sw $t1, 20($fp) #Executing Assign - li $t1, 5 - sw $t1, 24($fp) + li $t2, 5 + sw $t2, 24($fp) #Executing Assign - li $t3, 6 - sw $t3, 28($fp) + li $t0, 6 + sw $t0, 28($fp) #Receiving Arg local_Main_main_internal_4 - lw $t1, 16($fp) - sw $t1, 0($sp) + lw $t0, 16($fp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Receiving Arg local_Main_main_internal_6 - lw $t0, 24($fp) - sw $t0, 0($sp) + lw $t9, 24($fp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Receiving Arg local_Main_main_internal_7 - lw $t3, 28($fp) - sw $t3, 0($sp) + lw $t1, 28($fp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing Dynamic Call - lw $t5, 20($fp) - lw $t2, 12($t5) - jalr $t2 + lw $t0, 20($fp) + lw $t5, 12($t0) + jalr $t5 sw $a1, 12($fp) addi $sp, $sp, -12 #Receiving Arg local_Main_main_internal_1 - lw $t0, 4($fp) - sw $t0, 0($sp) + lw $t5, 4($fp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Receiving Arg local_Main_main_internal_3 - lw $t3, 12($fp) - sw $t3, 0($sp) + lw $t1, 12($fp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing Dynamic Call - lw $t3, 8($fp) - lw $t5, 16($t3) - jalr $t5 + lw $t4, 8($fp) + lw $t1, 16($t4) + jalr $t1 sw $a1, 0($fp) addi $sp, $sp, -8 #Executing Return @@ -730,8 +1129,8 @@ Main_main: addi $sp, $sp, -32 #Return jump jalr $ra -Point_constructor: - move $t1 $fp +Point_copy: + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -740,7 +1139,7 @@ Point_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -750,20 +1149,114 @@ Point_constructor: sw $v0, 0($fp) la $t2, Point sw $t2, 0($v0) + #Executing GetAttr + lw $t2, -4($fp) + lw $t4, 4($t2) + sw $t4, 4($fp) + #Executing SetAttr + lw $t4, 0($fp) + lw $t9, 4($fp) + sw $t9, 4($t4) + #Executing GetAttr + lw $t1, -4($fp) + lw $t2, 8($t1) + sw $t2, 8($fp) + #Executing SetAttr + lw $t0, 0($fp) + lw $t4, 8($fp) + sw $t4, 8($t0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -12 + #Return jump + jalr $ra +Point_type_name: + move $t4 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t9, String + sw $t9, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t5, String + sw $t5, 0($v0) + li $t5, 5 + sw $t5, 4($v0) + la $t5, type_name_Point + sw $t5, 8($v0) + #Executing Assign + lw $t0, 4($fp) + sw $t0, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra +Point_constructor: + move $t2 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 12 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t9, Point + sw $t9, 0($v0) #Executing DefaultValue - li $t1, 0 - sw $t1, 4($fp) + li $t0, 0 + sw $t0, 4($fp) #Executing SetAttr - lw $t9, 0($fp) - lw $t1, 4($fp) - sw $t1, 4($t9) + lw $t2, 0($fp) + lw $t0, 4($fp) + sw $t0, 4($t2) #Executing DefaultValue - li $t9, 0 - sw $t9, 8($fp) + li $t2, 0 + sw $t2, 8($fp) #Executing SetAttr - lw $t9, 0($fp) - lw $t2, 8($fp) - sw $t2, 8($t9) + lw $t2, 0($fp) + lw $t4, 8($fp) + sw $t4, 8($t2) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -777,7 +1270,7 @@ Point_constructor: #Return jump jalr $ra Point_init: - move $t1 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -786,20 +1279,20 @@ Point_init: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Assign - lw $t1, -8($fp) - sw $t1, 4($fp) + lw $t5, -8($fp) + sw $t5, 4($fp) #Executing Assign - lw $t0, -4($fp) - sw $t0, 8($fp) + lw $t4, -4($fp) + sw $t4, 8($fp) #Executing Plus Operation - lw $t0, 4($fp) - lw $t9, 8($fp) - add $t1, $t0, $t9 - sw $t1, 0($fp) + lw $t9, 4($fp) + lw $t1, 8($fp) + add $t4, $t9, $t1 + sw $t4, 0($fp) #Executing Return lw $a1, 0($fp) #Restoring saved $fp diff --git a/tests/code_gen/read_string.mips b/tests/code_gen/read_string.mips index d8d334862..df382cb32 100644 --- a/tests/code_gen/read_string.mips +++ b/tests/code_gen/read_string.mips @@ -2,15 +2,15 @@ Object : .word, Object_abort, Object_copy, Object_type_name Object_cname : .asciiz, "Object" -IO : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int +IO : .word, Object_abort, IO_copy, IO_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int IO_cname : .asciiz, "IO" -String : .word, Object_abort, Object_copy, Object_type_name, String_length, String_concat, String_substr +String : .word, Object_abort, String_copy, String_type_name, String_length, String_concat, String_substr String_cname : .asciiz, "String" -Int : .word, Object_abort, Object_copy, Object_type_name +Int : .word, Object_abort, Int_copy, Int_type_name Int_cname : .asciiz, "Int" -Bool : .word, Object_abort, Object_copy, Object_type_name +Bool : .word, Object_abort, Bool_copy, Bool_type_name Bool_cname : .asciiz, "Bool" -Main : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int, Main_main, Main_constructor +Main : .word, Object_abort, Main_copy, Main_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int, Main_main, Main_constructor Main_cname : .asciiz, "Main" void : .word, -1 empty_string : .asciiz, "" @@ -22,20 +22,26 @@ dispatch_on_void : .asciiz, "Dispatch on void" division_by_zero : .asciiz, "Division by zero" substr_out_of_range : .asciiz, "Substring out of range" heap_overflow : .asciiz, "Heap overflow" +type_name_Object : .asciiz, "Object" +type_name_IO : .asciiz, "IO" +type_name_String : .asciiz, "String" +type_name_Int : .asciiz, "Int" +type_name_Bool : .asciiz, "Bool" +type_name_Main : .asciiz, "Main" .text .globl main length: - li $t2, 0 + li $t4, 0 length_loop: - lb $t0, 0($a0) - beq $zero, $t0, length_end - add $t2, $t2, 1 + lb $t5, 0($a0) + beq $zero, $t5, length_end + add $t4, $t4, 1 add $a0, $a0, 1 j length_loop length_end: - move $a0 $t2 + move $a0 $t4 j $ra copy: copy_loop: @@ -48,8 +54,35 @@ copy: j copy_loop copy_end: j $ra +main: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Static Call + jal Main_constructor + sw $a1, 0($fp) + addi $sp, $sp, 0 + #Receiving Arg local_main_internal_0 + lw $t1, 0($fp) + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing Static Call + jal Main_main + sw $a1, 4($fp) + addi $sp, $sp, -4 + li $v0, 10 + syscall Object_abort: - move $t4 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -58,7 +91,7 @@ Object_abort: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing RuntimeError @@ -70,7 +103,7 @@ Object_abort: li $v0, 10 syscall Object_copy: - move $t4 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -79,9 +112,16 @@ Object_copy: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t4, Object + sw $t4, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -95,6 +135,52 @@ Object_copy: #Return jump jalr $ra Object_type_name: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t5, String + sw $t5, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t1, String + sw $t1, 0($v0) + li $t1, 6 + sw $t1, 4($v0) + la $t1, type_name_Object + sw $t1, 8($v0) + #Executing Assign + lw $t5, 4($fp) + sw $t5, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra +IO_copy: move $t1 $fp #New $fp move $fp $sp @@ -107,6 +193,13 @@ Object_type_name: sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t9, IO + sw $t9, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -119,8 +212,54 @@ Object_type_name: addi $sp, $sp, -4 #Return jump jalr $ra +IO_type_name: + move $t5 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t2, String + sw $t2, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t5, String + sw $t5, 0($v0) + li $t5, 2 + sw $t5, 4($v0) + la $t5, type_name_IO + sw $t5, 8($v0) + #Executing Assign + lw $t2, 4($fp) + sw $t2, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra IO_out_string: - move $t1 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -129,7 +268,7 @@ IO_out_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintStringNode @@ -150,7 +289,7 @@ IO_out_string: #Return jump jalr $ra IO_out_int: - move $t9 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -159,7 +298,7 @@ IO_out_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintIntNode @@ -179,7 +318,7 @@ IO_out_int: #Return jump jalr $ra IO_in_string: - move $t4 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -188,7 +327,7 @@ IO_in_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #ReadStrNode @@ -205,8 +344,8 @@ IO_in_string: li $v0, 9 syscall move $t6 $v0 - move $t4 $v0 - move $t2 $a0 + move $t0 $v0 + move $t9 $a0 #Copying bytes from one char array to another jal copy #Null-terminating the string @@ -216,11 +355,11 @@ IO_in_string: li $a0, 12 syscall sw $v0, 0($fp) - la $t5, String - sw $t5, 0($v0) + la $t4, String + sw $t4, 0($v0) #Storing length and reference to char array - sw $t2, 4($v0) - sw $t4, 8($v0) + sw $t9, 4($v0) + sw $t0, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -246,36 +385,88 @@ IO_in_int: sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions - #ReadStrNode - #Reading String to buffer - la $a0, input_str_buffer - li $a1, 1024 - li $v0, 8 + #ReadIntNode + li $v0, 5 syscall - #Saving reference to read string - move $t7 $a0 - #Calculating str length - jal length - #Allocating char array for new string + sw $v0, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_copy: + move $t5 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate li $v0, 9 + li $a0, 12 syscall - move $t6 $v0 - move $t4 $v0 - move $t1 $a0 - #Copying bytes from one char array to another - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance + sw $v0, 0($fp) + la $t0, String + sw $t0, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_type_name: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate li $v0, 9 li $a0, 12 syscall sw $v0, 0($fp) - la $t5, String - sw $t5, 0($v0) - #Storing length and reference to char array - sw $t1, 4($v0) - sw $t4, 8($v0) + la $t1, String + sw $t1, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t9, String + sw $t9, 0($v0) + li $t9, 6 + sw $t9, 4($v0) + la $t9, type_name_String + sw $t9, 8($v0) + #Executing Assign + lw $t3, 4($fp) + sw $t3, 0($fp) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -285,11 +476,11 @@ IO_in_int: addi $sp, $sp, -4 lw $ra, 0($sp) #Cleaning stack after call - addi $sp, $sp, -4 + addi $sp, $sp, -8 #Return jump jalr $ra String_length: - move $t3 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -298,13 +489,13 @@ String_length: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Length - lw $t0, -4($fp) - lw $t0, 4($t0) - sw $t0, 0($fp) + lw $t1, -4($fp) + lw $t1, 4($t1) + sw $t1, 0($fp) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -318,7 +509,7 @@ String_length: #Return jump jalr $ra String_concat: - move $t2 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -327,7 +518,7 @@ String_concat: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Loading length @@ -335,14 +526,14 @@ String_concat: lw $s1, 4($s1) lw $s2, -4($fp) lw $s2, 4($s2) - add $t1, $s1, $s2 + add $t3, $s1, $s2 #Allocating new char array - move $a0 $t1 + move $a0 $t3 addi $a0, $a0, 1 li $v0, 9 syscall move $t6 $v0 - move $t3 $v0 + move $t5 $v0 #Copying bytes from first string lw $t7, -8($fp) lw $t7, 8($t7) @@ -360,11 +551,11 @@ String_concat: li $a0, 12 syscall sw $v0, 0($fp) - la $t4, String - sw $t4, 0($v0) + la $t1, String + sw $t1, 0($v0) #Storing length and reference to char array - sw $t1, 4($v0) - sw $t3, 8($v0) + sw $t3, 4($v0) + sw $t5, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -378,7 +569,7 @@ String_concat: #Return jump jalr $ra String_substr: - move $t5 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -387,7 +578,7 @@ String_substr: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t5, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Substring @@ -407,14 +598,14 @@ String_substr: move $a0 $s0 jal copy #Null-terminating the string - sb $zero, 0($t0) + sb $zero, 0($t6) #Allocating new String instance li $v0, 9 li $a0, 12 syscall sw $v0, 0($fp) - la $t0, String - sw $t0, 0($v0) + la $t1, String + sw $t1, 0($v0) #Storing length and reference to char array lw $s0, -4($fp) sw $s0, 4($v0) @@ -431,8 +622,164 @@ String_substr: addi $sp, $sp, -4 #Return jump jalr $ra +Int_copy: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 8 + syscall + sw $v0, 0($fp) + la $t3, Int + sw $t3, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Int_type_name: + move $t2 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t9, String + sw $t9, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t5, String + sw $t5, 0($v0) + li $t5, 3 + sw $t5, 4($v0) + la $t5, type_name_Int + sw $t5, 8($v0) + #Executing Assign + lw $t2, 4($fp) + sw $t2, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra +Bool_copy: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 8 + syscall + sw $v0, 0($fp) + la $t3, Bool + sw $t3, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Bool_type_name: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t3, String + sw $t3, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t2, String + sw $t2, 0($v0) + li $t2, 4 + sw $t2, 4($v0) + la $t2, type_name_Bool + sw $t2, 8($v0) + #Executing Assign + lw $t3, 4($fp) + sw $t3, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra Object_constructor: - move $t4 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -441,7 +788,7 @@ Object_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -449,8 +796,8 @@ Object_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t1, Object - sw $t1, 0($v0) + la $t4, Object + sw $t4, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -464,7 +811,7 @@ Object_constructor: #Return jump jalr $ra IO_constructor: - move $t3 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -473,7 +820,7 @@ IO_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -481,8 +828,8 @@ IO_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t1, IO - sw $t1, 0($v0) + la $t4, IO + sw $t4, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -513,8 +860,8 @@ Int_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t1, Int - sw $t1, 0($v0) + la $t3, Int + sw $t3, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -528,7 +875,7 @@ Int_constructor: #Return jump jalr $ra Bool_constructor: - move $t3 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -537,7 +884,7 @@ Bool_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -545,8 +892,8 @@ Bool_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t3, Bool - sw $t3, 0($v0) + la $t2, Bool + sw $t2, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -560,7 +907,7 @@ Bool_constructor: #Return jump jalr $ra String_constructor: - move $t5 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -569,7 +916,7 @@ String_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t5, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -577,8 +924,8 @@ String_constructor: li $a0, 12 syscall sw $v0, 0($fp) - la $t5, String - sw $t5, 0($v0) + la $t3, String + sw $t3, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -591,8 +938,8 @@ String_constructor: addi $sp, $sp, -4 #Return jump jalr $ra -main: - move $t3 $fp +Main_copy: + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -601,25 +948,84 @@ main: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions - #Executing Static Call - jal Main_constructor - sw $a1, 0($fp) - addi $sp, $sp, 0 - #Receiving Arg local_main_internal_0 - lw $t4, 0($fp) - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing Static Call - jal Main_main - sw $a1, 4($fp) + #Executing Allocate + li $v0, 9 + li $a0, 8 + syscall + sw $v0, 0($fp) + la $t3, Main + sw $t3, 0($v0) + #Executing GetAttr + lw $t5, -4($fp) + lw $t0, 4($t5) + sw $t0, 4($fp) + #Executing SetAttr + lw $t3, 0($fp) + lw $t9, 4($fp) + sw $t9, 4($t3) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp addi $sp, $sp, -4 - li $v0, 10 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra +Main_type_name: + move $t5 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t3, String + sw $t3, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 syscall + sw $v0, 4($fp) + la $t9, String + sw $t9, 0($v0) + li $t9, 4 + sw $t9, 4($v0) + la $t9, type_name_Main + sw $t9, 8($v0) + #Executing Assign + lw $t5, 4($fp) + sw $t5, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra Main_constructor: - move $t1 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -628,7 +1034,7 @@ Main_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -636,23 +1042,23 @@ Main_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t9, Main - sw $t9, 0($v0) + la $t4, Main + sw $t4, 0($v0) #Executing DefaultValue li $v0, 9 li $a0, 12 syscall sw $v0, 4($fp) - la $t2, String - sw $t2, 0($v0) - li $t2, 0 - sw $t2, 4($v0) - la $t2, empty_string - sw $t2, 8($v0) + la $t5, String + sw $t5, 0($v0) + li $t5, 0 + sw $t5, 4($v0) + la $t5, empty_string + sw $t5, 8($v0) #Executing SetAttr - lw $t5, 0($fp) - lw $t1, 4($fp) - sw $t1, 4($t5) + lw $t9, 0($fp) + lw $t2, 4($fp) + sw $t2, 4($t9) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -666,7 +1072,7 @@ Main_constructor: #Return jump jalr $ra Main_main: - move $t4 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -675,53 +1081,53 @@ Main_main: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Assign - lw $t4, -4($fp) - sw $t4, 4($fp) + lw $t9, -4($fp) + sw $t9, 4($fp) #Executing typeof - lw $t9, 4($fp) - lw $t9, 0($t9) - sw $t9, 8($fp) + lw $t4, 4($fp) + lw $t4, 0($t4) + sw $t4, 8($fp) #Receiving Arg local_Main_main_internal_1 - lw $t5, 4($fp) - sw $t5, 0($sp) + lw $t9, 4($fp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing Dynamic Call - lw $t9, 8($fp) - lw $t1, 20($t9) - jalr $t1 + lw $t4, 8($fp) + lw $t5, 20($t4) + jalr $t5 sw $a1, 0($fp) addi $sp, $sp, -4 #Executing SetAttr - lw $t4, -4($fp) - lw $t2, 0($fp) - sw $t2, 4($t4) + lw $t3, -4($fp) + lw $t5, 0($fp) + sw $t5, 4($t3) #Executing Assign - lw $t9, -4($fp) - sw $t9, 12($fp) + lw $t0, -4($fp) + sw $t0, 12($fp) #Executing typeof - lw $t3, 12($fp) - lw $t3, 0($t3) - sw $t3, 16($fp) + lw $t2, 12($fp) + lw $t2, 0($t2) + sw $t2, 16($fp) #Executing GetAttr - lw $t9, -4($fp) - lw $t3, 4($t9) - sw $t3, 20($fp) + lw $t3, -4($fp) + lw $t0, 4($t3) + sw $t0, 20($fp) #Receiving Arg local_Main_main_internal_3 - lw $t5, 12($fp) - sw $t5, 0($sp) + lw $t0, 12($fp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Receiving Arg local_Main_main_internal_5 lw $t9, 20($fp) sw $t9, 0($sp) addi $sp, $sp, 4 #Executing Dynamic Call - lw $t9, 16($fp) - lw $t1, 12($t9) - jalr $t1 + lw $t4, 16($fp) + lw $t2, 12($t4) + jalr $t2 sw $a1, 0($fp) addi $sp, $sp, -8 #Executing Return diff --git a/tests/code_gen/string_methods _output.cl b/tests/code_gen/string_methods _output.cl deleted file mode 100644 index 42bc7029f..000000000 --- a/tests/code_gen/string_methods _output.cl +++ /dev/null @@ -1 +0,0 @@ -First sentence.Second sentence.First sentence. \ No newline at end of file diff --git a/tests/code_gen/string_methods.mips b/tests/code_gen/string_methods.mips index 6b2c949ae..8db744031 100644 --- a/tests/code_gen/string_methods.mips +++ b/tests/code_gen/string_methods.mips @@ -2,15 +2,15 @@ Object : .word, Object_abort, Object_copy, Object_type_name Object_cname : .asciiz, "Object" -IO : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int +IO : .word, Object_abort, IO_copy, IO_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int IO_cname : .asciiz, "IO" -String : .word, Object_abort, Object_copy, Object_type_name, String_length, String_concat, String_substr +String : .word, Object_abort, String_copy, String_type_name, String_length, String_concat, String_substr String_cname : .asciiz, "String" -Int : .word, Object_abort, Object_copy, Object_type_name +Int : .word, Object_abort, Int_copy, Int_type_name Int_cname : .asciiz, "Int" -Bool : .word, Object_abort, Object_copy, Object_type_name +Bool : .word, Object_abort, Bool_copy, Bool_type_name Bool_cname : .asciiz, "Bool" -Main : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int, Main_main, Main_constructor +Main : .word, Object_abort, Main_copy, Main_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int, Main_main, Main_constructor Main_cname : .asciiz, "Main" void : .word, -1 empty_string : .asciiz, "" @@ -22,6 +22,12 @@ dispatch_on_void : .asciiz, "Dispatch on void" division_by_zero : .asciiz, "Division by zero" substr_out_of_range : .asciiz, "Substring out of range" heap_overflow : .asciiz, "Heap overflow" +type_name_Object : .asciiz, "Object" +type_name_IO : .asciiz, "IO" +type_name_String : .asciiz, "String" +type_name_Int : .asciiz, "Int" +type_name_Bool : .asciiz, "Bool" +type_name_Main : .asciiz, "Main" string_1 : .asciiz, "First sentence." string_2 : .asciiz, "Second sentence." @@ -31,8 +37,8 @@ string_2 : .asciiz, "Second sentence." length: li $t0, 0 length_loop: - lb $t2, 0($a0) - beq $zero, $t2, length_end + lb $t1, 0($a0) + beq $zero, $t1, length_end add $t0, $t0, 1 add $a0, $a0, 1 j length_loop @@ -50,8 +56,35 @@ copy: j copy_loop copy_end: j $ra +main: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Static Call + jal Main_constructor + sw $a1, 0($fp) + addi $sp, $sp, 0 + #Receiving Arg local_main_internal_0 + lw $t3, 0($fp) + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing Static Call + jal Main_main + sw $a1, 4($fp) + addi $sp, $sp, -4 + li $v0, 10 + syscall Object_abort: - move $t1 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -60,7 +93,7 @@ Object_abort: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing RuntimeError @@ -72,7 +105,7 @@ Object_abort: li $v0, 10 syscall Object_copy: - move $t0 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -81,9 +114,16 @@ Object_copy: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t2, Object + sw $t2, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -97,7 +137,53 @@ Object_copy: #Return jump jalr $ra Object_type_name: - move $t1 $fp + move $t5 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t0, String + sw $t0, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t4, String + sw $t4, 0($v0) + li $t4, 6 + sw $t4, 4($v0) + la $t4, type_name_Object + sw $t4, 8($v0) + #Executing Assign + lw $t1, 4($fp) + sw $t1, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra +IO_copy: + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -106,9 +192,16 @@ Object_type_name: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t0, IO + sw $t0, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -121,8 +214,54 @@ Object_type_name: addi $sp, $sp, -4 #Return jump jalr $ra +IO_type_name: + move $t3 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t9, String + sw $t9, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t4, String + sw $t4, 0($v0) + li $t4, 2 + sw $t4, 4($v0) + la $t4, type_name_IO + sw $t4, 8($v0) + #Executing Assign + lw $t3, 4($fp) + sw $t3, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra IO_out_string: - move $t0 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -131,7 +270,7 @@ IO_out_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintStringNode @@ -152,7 +291,7 @@ IO_out_string: #Return jump jalr $ra IO_out_int: - move $t3 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -161,7 +300,7 @@ IO_out_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintIntNode @@ -181,7 +320,7 @@ IO_out_int: #Return jump jalr $ra IO_in_string: - move $t4 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -190,7 +329,7 @@ IO_in_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #ReadStrNode @@ -207,8 +346,8 @@ IO_in_string: li $v0, 9 syscall move $t6 $v0 - move $t9 $v0 - move $t0 $a0 + move $t3 $v0 + move $t2 $a0 #Copying bytes from one char array to another jal copy #Null-terminating the string @@ -218,11 +357,11 @@ IO_in_string: li $a0, 12 syscall sw $v0, 0($fp) - la $t1, String - sw $t1, 0($v0) + la $t4, String + sw $t4, 0($v0) #Storing length and reference to char array - sw $t0, 4($v0) - sw $t9, 8($v0) + sw $t2, 4($v0) + sw $t3, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -236,7 +375,7 @@ IO_in_string: #Return jump jalr $ra IO_in_int: - move $t2 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -245,39 +384,91 @@ IO_in_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions - #ReadStrNode - #Reading String to buffer - la $a0, input_str_buffer - li $a1, 1024 - li $v0, 8 + #ReadIntNode + li $v0, 5 syscall - #Saving reference to read string - move $t7 $a0 - #Calculating str length - jal length - #Allocating char array for new string + sw $v0, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_copy: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate li $v0, 9 + li $a0, 12 syscall - move $t6 $v0 - move $t9 $v0 - move $t0 $a0 - #Copying bytes from one char array to another - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance + sw $v0, 0($fp) + la $t9, String + sw $t9, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_type_name: + move $t3 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate li $v0, 9 li $a0, 12 syscall sw $v0, 0($fp) - la $t1, String - sw $t1, 0($v0) - #Storing length and reference to char array - sw $t0, 4($v0) - sw $t9, 8($v0) + la $t5, String + sw $t5, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t4, String + sw $t4, 0($v0) + li $t4, 6 + sw $t4, 4($v0) + la $t4, type_name_String + sw $t4, 8($v0) + #Executing Assign + lw $t4, 4($fp) + sw $t4, 0($fp) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -287,11 +478,11 @@ IO_in_int: addi $sp, $sp, -4 lw $ra, 0($sp) #Cleaning stack after call - addi $sp, $sp, -4 + addi $sp, $sp, -8 #Return jump jalr $ra String_length: - move $t2 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -300,13 +491,13 @@ String_length: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Length - lw $t9, -4($fp) - lw $t9, 4($t9) - sw $t9, 0($fp) + lw $t0, -4($fp) + lw $t0, 4($t0) + sw $t0, 0($fp) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -320,7 +511,7 @@ String_length: #Return jump jalr $ra String_concat: - move $t4 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -329,7 +520,7 @@ String_concat: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Loading length @@ -337,14 +528,14 @@ String_concat: lw $s1, 4($s1) lw $s2, -4($fp) lw $s2, 4($s2) - add $t5, $s1, $s2 + add $t4, $s1, $s2 #Allocating new char array - move $a0 $t5 + move $a0 $t4 addi $a0, $a0, 1 li $v0, 9 syscall move $t6 $v0 - move $t0 $v0 + move $t3 $v0 #Copying bytes from first string lw $t7, -8($fp) lw $t7, 8($t7) @@ -362,11 +553,11 @@ String_concat: li $a0, 12 syscall sw $v0, 0($fp) - la $t9, String - sw $t9, 0($v0) + la $t0, String + sw $t0, 0($v0) #Storing length and reference to char array - sw $t5, 4($v0) - sw $t0, 8($v0) + sw $t4, 4($v0) + sw $t3, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -380,7 +571,7 @@ String_concat: #Return jump jalr $ra String_substr: - move $t3 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -389,7 +580,7 @@ String_substr: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Substring @@ -409,14 +600,14 @@ String_substr: move $a0 $s0 jal copy #Null-terminating the string - sb $zero, 0($t0) + sb $zero, 0($t6) #Allocating new String instance li $v0, 9 li $a0, 12 syscall sw $v0, 0($fp) - la $t1, String - sw $t1, 0($v0) + la $t9, String + sw $t9, 0($v0) #Storing length and reference to char array lw $s0, -4($fp) sw $s0, 4($v0) @@ -433,8 +624,8 @@ String_substr: addi $sp, $sp, -4 #Return jump jalr $ra -Object_constructor: - move $t3 $fp +Int_copy: + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -443,16 +634,94 @@ Object_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 8 + syscall + sw $v0, 0($fp) + la $t0, Int + sw $t0, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Int_type_name: + move $t3 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate li $v0, 9 - li $a0, 4 + li $a0, 12 syscall sw $v0, 0($fp) - la $t4, Object + la $t4, String sw $t4, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t2, String + sw $t2, 0($v0) + li $t2, 3 + sw $t2, 4($v0) + la $t2, type_name_Int + sw $t2, 8($v0) + #Executing Assign + lw $t4, 4($fp) + sw $t4, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra +Bool_copy: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 8 + syscall + sw $v0, 0($fp) + la $t3, Bool + sw $t3, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -465,7 +734,53 @@ Object_constructor: addi $sp, $sp, -4 #Return jump jalr $ra -IO_constructor: +Bool_type_name: + move $t5 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t2, String + sw $t2, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t0, String + sw $t0, 0($v0) + li $t0, 4 + sw $t0, 4($v0) + la $t0, type_name_Bool + sw $t0, 8($v0) + #Executing Assign + lw $t1, 4($fp) + sw $t1, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra +Object_constructor: move $t4 $fp #New $fp move $fp $sp @@ -483,8 +798,40 @@ IO_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t4, IO - sw $t4, 0($v0) + la $t0, Object + sw $t0, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +IO_constructor: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t1, IO + sw $t1, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -498,7 +845,7 @@ IO_constructor: #Return jump jalr $ra Int_constructor: - move $t9 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -507,7 +854,7 @@ Int_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -515,8 +862,8 @@ Int_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t3, Int - sw $t3, 0($v0) + la $t2, Int + sw $t2, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -530,7 +877,7 @@ Int_constructor: #Return jump jalr $ra Bool_constructor: - move $t2 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -539,7 +886,7 @@ Bool_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -547,8 +894,8 @@ Bool_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t9, Bool - sw $t9, 0($v0) + la $t3, Bool + sw $t3, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -562,7 +909,7 @@ Bool_constructor: #Return jump jalr $ra String_constructor: - move $t5 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -571,7 +918,7 @@ String_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t5, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -593,35 +940,118 @@ String_constructor: addi $sp, $sp, -4 #Return jump jalr $ra -main: - move $t0 $fp +Main_copy: + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals - addi $sp, $sp, 8 + addi $sp, $sp, 20 #Pushing $ra sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions - #Executing Static Call - jal Main_constructor - sw $a1, 0($fp) - addi $sp, $sp, 0 - #Receiving Arg local_main_internal_0 - lw $t5, 0($fp) + #Executing Allocate + li $v0, 9 + li $a0, 20 + syscall + sw $v0, 0($fp) + la $t4, Main + sw $t4, 0($v0) + #Executing GetAttr + lw $t5, -4($fp) + lw $t2, 4($t5) + sw $t2, 4($fp) + #Executing SetAttr + lw $t2, 0($fp) + lw $t4, 4($fp) + sw $t4, 4($t2) + #Executing GetAttr + lw $t2, -4($fp) + lw $t3, 8($t2) + sw $t3, 8($fp) + #Executing SetAttr + lw $t2, 0($fp) + lw $t1, 8($fp) + sw $t1, 8($t2) + #Executing GetAttr + lw $t4, -4($fp) + lw $t0, 12($t4) + sw $t0, 12($fp) + #Executing SetAttr + lw $t1, 0($fp) + lw $t3, 12($fp) + sw $t3, 12($t1) + #Executing GetAttr + lw $t0, -4($fp) + lw $t1, 16($t0) + sw $t1, 16($fp) + #Executing SetAttr + lw $t4, 0($fp) + lw $t3, 16($fp) + sw $t3, 16($t4) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -20 + #Return jump + jalr $ra +Main_type_name: + move $t5 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp sw $t5, 0($sp) addi $sp, $sp, 4 - #Executing Static Call - jal Main_main - sw $a1, 4($fp) - addi $sp, $sp, -4 - li $v0, 10 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t3, String + sw $t3, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 syscall + sw $v0, 4($fp) + la $t0, String + sw $t0, 0($v0) + li $t0, 4 + sw $t0, 4($v0) + la $t0, type_name_Main + sw $t0, 8($v0) + #Executing Assign + lw $t2, 4($fp) + sw $t2, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra Main_constructor: - move $t9 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -630,7 +1060,7 @@ Main_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -638,22 +1068,22 @@ Main_constructor: li $a0, 20 syscall sw $v0, 0($fp) - la $t5, Main - sw $t5, 0($v0) + la $t1, Main + sw $t1, 0($v0) #Executing DefaultValue - li $t5, 0 - sw $t5, 4($fp) + li $t0, 0 + sw $t0, 4($fp) #Executing SetAttr lw $t5, 0($fp) - lw $t0, 4($fp) - sw $t0, 4($t5) + lw $t4, 4($fp) + sw $t4, 4($t5) #Executing DefaultValue - li $t9, 0 - sw $t9, 8($fp) + li $t4, 0 + sw $t4, 8($fp) #Executing SetAttr - lw $t0, 0($fp) - lw $t4, 8($fp) - sw $t4, 8($t0) + lw $t1, 0($fp) + lw $t5, 8($fp) + sw $t5, 8($t1) #Executing DefaultValue li $v0, 9 li $a0, 12 @@ -666,24 +1096,24 @@ Main_constructor: la $t3, empty_string sw $t3, 8($v0) #Executing SetAttr - lw $t4, 0($fp) - lw $t9, 12($fp) - sw $t9, 12($t4) + lw $t5, 0($fp) + lw $t2, 12($fp) + sw $t2, 12($t5) #Executing DefaultValue li $v0, 9 li $a0, 12 syscall sw $v0, 16($fp) - la $t2, String - sw $t2, 0($v0) - li $t2, 0 - sw $t2, 4($v0) - la $t2, empty_string - sw $t2, 8($v0) + la $t5, String + sw $t5, 0($v0) + li $t5, 0 + sw $t5, 4($v0) + la $t5, empty_string + sw $t5, 8($v0) #Executing SetAttr - lw $t5, 0($fp) - lw $t4, 16($fp) - sw $t4, 16($t5) + lw $t0, 0($fp) + lw $t3, 16($fp) + sw $t3, 16($t0) #Executing Load li $v0, 9 li $a0, 12 @@ -696,24 +1126,24 @@ Main_constructor: la $t5, string_1 sw $t5, 8($v0) #Executing SetAttr - lw $t5, 0($fp) - lw $t0, 20($fp) - sw $t0, 12($t5) + lw $t3, 0($fp) + lw $t4, 20($fp) + sw $t4, 12($t3) #Executing Load li $v0, 9 li $a0, 12 syscall sw $v0, 24($fp) - la $t0, String - sw $t0, 0($v0) - li $t0, 16 - sw $t0, 4($v0) - la $t0, string_2 - sw $t0, 8($v0) + la $t4, String + sw $t4, 0($v0) + li $t4, 16 + sw $t4, 4($v0) + la $t4, string_2 + sw $t4, 8($v0) #Executing SetAttr - lw $t0, 0($fp) - lw $t5, 24($fp) - sw $t5, 16($t0) + lw $t3, 0($fp) + lw $t4, 24($fp) + sw $t4, 16($t3) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -727,7 +1157,7 @@ Main_constructor: #Return jump jalr $ra Main_main: - move $t0 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -736,90 +1166,90 @@ Main_main: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Assign - lw $t3, -4($fp) - sw $t3, 4($fp) + lw $t4, -4($fp) + sw $t4, 4($fp) #Executing typeof - lw $t5, 4($fp) - lw $t5, 0($t5) - sw $t5, 8($fp) + lw $t2, 4($fp) + lw $t2, 0($t2) + sw $t2, 8($fp) #Executing GetAttr - lw $t0, -4($fp) - lw $t4, 12($t0) - sw $t4, 16($fp) + lw $t5, -4($fp) + lw $t3, 12($t5) + sw $t3, 16($fp) #Executing typeof - lw $t3, 16($fp) - lw $t3, 0($t3) - sw $t3, 20($fp) + lw $t4, 16($fp) + lw $t4, 0($t4) + sw $t4, 20($fp) #Executing GetAttr - lw $t2, -4($fp) - lw $t4, 16($t2) - sw $t4, 24($fp) + lw $t1, -4($fp) + lw $t3, 16($t1) + sw $t3, 24($fp) #Receiving Arg local_Main_main_internal_4 - lw $t5, 16($fp) - sw $t5, 0($sp) + lw $t1, 16($fp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Receiving Arg local_Main_main_internal_6 - lw $t2, 24($fp) - sw $t2, 0($sp) + lw $t0, 24($fp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing Dynamic Call - lw $t3, 20($fp) - lw $t9, 16($t3) - jalr $t9 + lw $t0, 20($fp) + lw $t4, 16($t0) + jalr $t4 sw $a1, 12($fp) addi $sp, $sp, -8 #Receiving Arg local_Main_main_internal_1 - lw $t2, 4($fp) - sw $t2, 0($sp) + lw $t3, 4($fp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Receiving Arg local_Main_main_internal_3 - lw $t2, 12($fp) - sw $t2, 0($sp) + lw $t4, 12($fp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing Dynamic Call - lw $t5, 8($fp) - lw $t4, 12($t5) - jalr $t4 + lw $t0, 8($fp) + lw $t5, 12($t0) + jalr $t5 sw $a1, 0($fp) addi $sp, $sp, -8 #Executing Assign - lw $t4, -4($fp) - sw $t4, 28($fp) + lw $t3, -4($fp) + sw $t3, 28($fp) #Executing typeof - lw $t3, 28($fp) - lw $t3, 0($t3) - sw $t3, 32($fp) + lw $t5, 28($fp) + lw $t5, 0($t5) + sw $t5, 32($fp) #Executing GetAttr - lw $t3, -4($fp) - lw $t5, 12($t3) - sw $t5, 40($fp) + lw $t0, -4($fp) + lw $t1, 12($t0) + sw $t1, 40($fp) #Executing typeof - lw $t4, 40($fp) - lw $t4, 0($t4) - sw $t4, 44($fp) + lw $t3, 40($fp) + lw $t3, 0($t3) + sw $t3, 44($fp) #Executing Assign - li $t0, 0 - sw $t0, 48($fp) + li $t1, 0 + sw $t1, 48($fp) #Executing GetAttr lw $t2, -4($fp) - lw $t9, 12($t2) - sw $t9, 56($fp) + lw $t3, 12($t2) + sw $t3, 56($fp) #Executing typeof - lw $t0, 56($fp) - lw $t0, 0($t0) - sw $t0, 60($fp) + lw $t2, 56($fp) + lw $t2, 0($t2) + sw $t2, 60($fp) #Receiving Arg local_Main_main_internal_14 lw $t5, 56($fp) sw $t5, 0($sp) addi $sp, $sp, 4 #Executing Dynamic Call - lw $t9, 60($fp) - lw $t5, 12($t9) - jalr $t5 + lw $t1, 60($fp) + lw $t2, 12($t1) + jalr $t2 sw $a1, 52($fp) addi $sp, $sp, -4 #Receiving Arg local_Main_main_internal_10 @@ -827,31 +1257,31 @@ Main_main: sw $t3, 0($sp) addi $sp, $sp, 4 #Receiving Arg local_Main_main_internal_12 - lw $t3, 48($fp) - sw $t3, 0($sp) + lw $t4, 48($fp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Receiving Arg local_Main_main_internal_13 - lw $t3, 52($fp) - sw $t3, 0($sp) + lw $t2, 52($fp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing Dynamic Call - lw $t3, 44($fp) - lw $t0, 20($t3) - jalr $t0 + lw $t4, 44($fp) + lw $t3, 20($t4) + jalr $t3 sw $a1, 36($fp) addi $sp, $sp, -12 #Receiving Arg local_Main_main_internal_7 - lw $t5, 28($fp) - sw $t5, 0($sp) + lw $t3, 28($fp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Receiving Arg local_Main_main_internal_9 - lw $t4, 36($fp) - sw $t4, 0($sp) + lw $t1, 36($fp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing Dynamic Call - lw $t3, 32($fp) - lw $t4, 12($t3) - jalr $t4 + lw $t4, 32($fp) + lw $t2, 12($t4) + jalr $t2 sw $a1, 0($fp) addi $sp, $sp, -8 #Executing Return diff --git a/tests/code_gen/test_goto_if.mips b/tests/code_gen/test_goto_if.mips index 9a48c5b12..f89754d86 100644 --- a/tests/code_gen/test_goto_if.mips +++ b/tests/code_gen/test_goto_if.mips @@ -2,15 +2,15 @@ Object : .word, Object_abort, Object_copy, Object_type_name Object_cname : .asciiz, "Object" -IO : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int +IO : .word, Object_abort, IO_copy, IO_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int IO_cname : .asciiz, "IO" -String : .word, Object_abort, Object_copy, Object_type_name, String_length, String_concat, String_substr +String : .word, Object_abort, String_copy, String_type_name, String_length, String_concat, String_substr String_cname : .asciiz, "String" -Int : .word, Object_abort, Object_copy, Object_type_name +Int : .word, Object_abort, Int_copy, Int_type_name Int_cname : .asciiz, "Int" -Bool : .word, Object_abort, Object_copy, Object_type_name +Bool : .word, Object_abort, Bool_copy, Bool_type_name Bool_cname : .asciiz, "Bool" -Main : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int, Main_main, Main_constructor +Main : .word, Object_abort, Main_copy, Main_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int, Main_main, Main_constructor Main_cname : .asciiz, "Main" void : .word, -1 empty_string : .asciiz, "" @@ -22,20 +22,26 @@ dispatch_on_void : .asciiz, "Dispatch on void" division_by_zero : .asciiz, "Division by zero" substr_out_of_range : .asciiz, "Substring out of range" heap_overflow : .asciiz, "Heap overflow" +type_name_Object : .asciiz, "Object" +type_name_IO : .asciiz, "IO" +type_name_String : .asciiz, "String" +type_name_Int : .asciiz, "Int" +type_name_Bool : .asciiz, "Bool" +type_name_Main : .asciiz, "Main" .text .globl main length: - li $t1, 0 + li $t2, 0 length_loop: lb $t0, 0($a0) beq $zero, $t0, length_end - add $t1, $t1, 1 + add $t2, $t2, 1 add $a0, $a0, 1 j length_loop length_end: - move $a0 $t1 + move $a0 $t2 j $ra copy: copy_loop: @@ -48,8 +54,35 @@ copy: j copy_loop copy_end: j $ra +main: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Static Call + jal Main_constructor + sw $a1, 0($fp) + addi $sp, $sp, 0 + #Receiving Arg local_main_internal_0 + lw $t4, 0($fp) + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing Static Call + jal Main_main + sw $a1, 4($fp) + addi $sp, $sp, -4 + li $v0, 10 + syscall Object_abort: - move $t5 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -58,7 +91,7 @@ Object_abort: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t5, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing RuntimeError @@ -70,7 +103,7 @@ Object_abort: li $v0, 10 syscall Object_copy: - move $t1 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -79,9 +112,16 @@ Object_copy: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t0, Object + sw $t0, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -95,7 +135,53 @@ Object_copy: #Return jump jalr $ra Object_type_name: - move $t5 $fp + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t0, String + sw $t0, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t9, String + sw $t9, 0($v0) + li $t9, 6 + sw $t9, 4($v0) + la $t9, type_name_Object + sw $t9, 8($v0) + #Executing Assign + lw $t5, 4($fp) + sw $t5, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra +IO_copy: + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -104,9 +190,16 @@ Object_type_name: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t5, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t3, IO + sw $t3, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -119,12 +212,12 @@ Object_type_name: addi $sp, $sp, -4 #Return jump jalr $ra -IO_out_string: +IO_type_name: move $t9 $fp #New $fp move $fp $sp #Reserving space for locals - addi $sp, $sp, 0 + addi $sp, $sp, 8 #Pushing $ra sw $ra, 0($sp) addi $sp, $sp, 4 @@ -132,6 +225,52 @@ IO_out_string: sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t4, String + sw $t4, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t9, String + sw $t9, 0($v0) + li $t9, 2 + sw $t9, 4($v0) + la $t9, type_name_IO + sw $t9, 8($v0) + #Executing Assign + lw $t0, 4($fp) + sw $t0, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra +IO_out_string: + move $t3 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 0 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing instructions #PrintStringNode lw $a0, -4($fp) lw $a0, 8($a0) @@ -179,7 +318,7 @@ IO_out_int: #Return jump jalr $ra IO_in_string: - move $t9 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -188,7 +327,7 @@ IO_in_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #ReadStrNode @@ -205,8 +344,8 @@ IO_in_string: li $v0, 9 syscall move $t6 $v0 - move $t3 $v0 - move $t2 $a0 + move $t0 $v0 + move $t5 $a0 #Copying bytes from one char array to another jal copy #Null-terminating the string @@ -216,11 +355,11 @@ IO_in_string: li $a0, 12 syscall sw $v0, 0($fp) - la $t5, String - sw $t5, 0($v0) + la $t4, String + sw $t4, 0($v0) #Storing length and reference to char array - sw $t2, 4($v0) - sw $t3, 8($v0) + sw $t5, 4($v0) + sw $t0, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -234,7 +373,7 @@ IO_in_string: #Return jump jalr $ra IO_in_int: - move $t2 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -243,39 +382,91 @@ IO_in_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions - #ReadStrNode - #Reading String to buffer - la $a0, input_str_buffer - li $a1, 1024 - li $v0, 8 + #ReadIntNode + li $v0, 5 syscall - #Saving reference to read string - move $t7 $a0 - #Calculating str length - jal length - #Allocating char array for new string + sw $v0, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_copy: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate li $v0, 9 + li $a0, 12 syscall - move $t6 $v0 - move $t3 $v0 - move $t0 $a0 - #Copying bytes from one char array to another - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance + sw $v0, 0($fp) + la $t4, String + sw $t4, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_type_name: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate li $v0, 9 li $a0, 12 syscall sw $v0, 0($fp) - la $t2, String - sw $t2, 0($v0) - #Storing length and reference to char array - sw $t0, 4($v0) - sw $t3, 8($v0) + la $t4, String + sw $t4, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t1, String + sw $t1, 0($v0) + li $t1, 6 + sw $t1, 4($v0) + la $t1, type_name_String + sw $t1, 8($v0) + #Executing Assign + lw $t0, 4($fp) + sw $t0, 0($fp) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -285,11 +476,11 @@ IO_in_int: addi $sp, $sp, -4 lw $ra, 0($sp) #Cleaning stack after call - addi $sp, $sp, -4 + addi $sp, $sp, -8 #Return jump jalr $ra String_length: - move $t9 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -298,13 +489,13 @@ String_length: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Length - lw $t4, -4($fp) - lw $t4, 4($t4) - sw $t4, 0($fp) + lw $t3, -4($fp) + lw $t3, 4($t3) + sw $t3, 0($fp) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -318,7 +509,7 @@ String_length: #Return jump jalr $ra String_concat: - move $t2 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -327,7 +518,7 @@ String_concat: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #Loading length @@ -342,7 +533,7 @@ String_concat: li $v0, 9 syscall move $t6 $v0 - move $t9 $v0 + move $t1 $v0 #Copying bytes from first string lw $t7, -8($fp) lw $t7, 8($t7) @@ -360,11 +551,11 @@ String_concat: li $a0, 12 syscall sw $v0, 0($fp) - la $t3, String - sw $t3, 0($v0) + la $t5, String + sw $t5, 0($v0) #Storing length and reference to char array sw $t0, 4($v0) - sw $t9, 8($v0) + sw $t1, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -378,7 +569,7 @@ String_concat: #Return jump jalr $ra String_substr: - move $t2 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -387,7 +578,7 @@ String_substr: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Substring @@ -407,14 +598,14 @@ String_substr: move $a0 $s0 jal copy #Null-terminating the string - sb $zero, 0($t0) + sb $zero, 0($t6) #Allocating new String instance li $v0, 9 li $a0, 12 syscall sw $v0, 0($fp) - la $t3, String - sw $t3, 0($v0) + la $t4, String + sw $t4, 0($v0) #Storing length and reference to char array lw $s0, -4($fp) sw $s0, 4($v0) @@ -431,6 +622,162 @@ String_substr: addi $sp, $sp, -4 #Return jump jalr $ra +Int_copy: + move $t5 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 8 + syscall + sw $v0, 0($fp) + la $t3, Int + sw $t3, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Int_type_name: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t0, String + sw $t0, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t3, String + sw $t3, 0($v0) + li $t3, 3 + sw $t3, 4($v0) + la $t3, type_name_Int + sw $t3, 8($v0) + #Executing Assign + lw $t9, 4($fp) + sw $t9, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra +Bool_copy: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 8 + syscall + sw $v0, 0($fp) + la $t1, Bool + sw $t1, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Bool_type_name: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t1, String + sw $t1, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t9, String + sw $t9, 0($v0) + li $t9, 4 + sw $t9, 4($v0) + la $t9, type_name_Bool + sw $t9, 8($v0) + #Executing Assign + lw $t3, 4($fp) + sw $t3, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra Object_constructor: move $t1 $fp #New $fp @@ -449,8 +796,8 @@ Object_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t4, Object - sw $t4, 0($v0) + la $t2, Object + sw $t2, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -496,7 +843,7 @@ IO_constructor: #Return jump jalr $ra Int_constructor: - move $t0 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -505,7 +852,7 @@ Int_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -513,8 +860,8 @@ Int_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t1, Int - sw $t1, 0($v0) + la $t5, Int + sw $t5, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -528,7 +875,7 @@ Int_constructor: #Return jump jalr $ra Bool_constructor: - move $t0 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -537,7 +884,7 @@ Bool_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -545,8 +892,8 @@ Bool_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t1, Bool - sw $t1, 0($v0) + la $t9, Bool + sw $t9, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -560,7 +907,7 @@ Bool_constructor: #Return jump jalr $ra String_constructor: - move $t0 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -569,7 +916,7 @@ String_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -577,8 +924,8 @@ String_constructor: li $a0, 12 syscall sw $v0, 0($fp) - la $t9, String - sw $t9, 0($v0) + la $t1, String + sw $t1, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -591,35 +938,102 @@ String_constructor: addi $sp, $sp, -4 #Return jump jalr $ra -main: - move $t1 $fp +Main_copy: + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals - addi $sp, $sp, 8 + addi $sp, $sp, 12 #Pushing $ra sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions - #Executing Static Call - jal Main_constructor - sw $a1, 0($fp) - addi $sp, $sp, 0 - #Receiving Arg local_main_internal_0 - lw $t4, 0($fp) - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing Static Call - jal Main_main - sw $a1, 4($fp) + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t3, Main + sw $t3, 0($v0) + #Executing GetAttr + lw $t5, -4($fp) + lw $t1, 4($t5) + sw $t1, 4($fp) + #Executing SetAttr + lw $t2, 0($fp) + lw $t0, 4($fp) + sw $t0, 4($t2) + #Executing GetAttr + lw $t2, -4($fp) + lw $t1, 8($t2) + sw $t1, 8($fp) + #Executing SetAttr + lw $t0, 0($fp) + lw $t1, 8($fp) + sw $t1, 8($t0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp addi $sp, $sp, -4 - li $v0, 10 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -12 + #Return jump + jalr $ra +Main_type_name: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t0, String + sw $t0, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 syscall + sw $v0, 4($fp) + la $t2, String + sw $t2, 0($v0) + li $t2, 4 + sw $t2, 4($v0) + la $t2, type_name_Main + sw $t2, 8($v0) + #Executing Assign + lw $t1, 4($fp) + sw $t1, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra Main_constructor: - move $t4 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -628,7 +1042,7 @@ Main_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -636,36 +1050,36 @@ Main_constructor: li $a0, 12 syscall sw $v0, 0($fp) - la $t4, Main - sw $t4, 0($v0) + la $t5, Main + sw $t5, 0($v0) #Executing DefaultValue - li $t2, 0 - sw $t2, 4($fp) + li $t3, 0 + sw $t3, 4($fp) #Executing SetAttr lw $t0, 0($fp) - lw $t9, 4($fp) - sw $t9, 4($t0) + lw $t1, 4($fp) + sw $t1, 4($t0) #Executing DefaultValue - li $t4, 0 - sw $t4, 8($fp) + li $t2, 0 + sw $t2, 8($fp) #Executing SetAttr - lw $t2, 0($fp) - lw $t4, 8($fp) - sw $t4, 8($t2) + lw $t5, 0($fp) + lw $t0, 8($fp) + sw $t0, 8($t5) #Executing Assign - li $t1, 1 - sw $t1, 12($fp) + li $t0, 1 + sw $t0, 12($fp) #Executing SetAttr - lw $t1, 0($fp) - lw $t5, 12($fp) - sw $t5, 4($t1) + lw $t5, 0($fp) + lw $t2, 12($fp) + sw $t2, 4($t5) #Executing Assign - li $t5, 2 - sw $t5, 16($fp) + li $t9, 2 + sw $t9, 16($fp) #Executing SetAttr - lw $t2, 0($fp) - lw $t9, 16($fp) - sw $t9, 8($t2) + lw $t3, 0($fp) + lw $t0, 16($fp) + sw $t0, 8($t3) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -692,78 +1106,78 @@ Main_main: addi $sp, $sp, 4 #Executing instructions #Executing GetAttr - lw $t0, -4($fp) - lw $t9, 4($t0) - sw $t9, 4($fp) + lw $t1, -4($fp) + lw $t5, 4($t1) + sw $t5, 4($fp) #Executing GetAttr - lw $t4, -4($fp) - lw $t9, 8($t4) - sw $t9, 8($fp) + lw $t9, -4($fp) + lw $t1, 8($t9) + sw $t1, 8($fp) #Executing Plus Operation - lw $t0, 4($fp) - lw $t2, 8($fp) - add $t9, $t0, $t2 - sw $t9, 0($fp) + lw $t2, 4($fp) + lw $t0, 8($fp) + add $t5, $t2, $t0 + sw $t5, 0($fp) #Executing GetAttr - lw $t0, -4($fp) - lw $t1, 4($t0) - sw $t1, 12($fp) + lw $t9, -4($fp) + lw $t3, 4($t9) + sw $t3, 12($fp) #Executing GetAttr - lw $t2, -4($fp) - lw $t0, 8($t2) - sw $t0, 16($fp) + lw $t0, -4($fp) + lw $t3, 8($t0) + sw $t3, 16($fp) #Executing Minus Operation - lw $t1, 12($fp) - lw $t4, 16($fp) - sub $t2, $t1, $t4 + lw $t0, 12($fp) + lw $t3, 16($fp) + sub $t2, $t0, $t3 sw $t2, 0($fp) #Executing GetAttr - lw $t9, -4($fp) - lw $t1, 4($t9) - sw $t1, 20($fp) + lw $t5, -4($fp) + lw $t3, 4($t5) + sw $t3, 20($fp) #Executing GetAttr - lw $t1, -4($fp) - lw $t2, 8($t1) - sw $t2, 24($fp) + lw $t3, -4($fp) + lw $t9, 8($t3) + sw $t9, 24($fp) #Executing Div Operation - lw $t2, 20($fp) - lw $t4, 24($fp) - div $t2, $t4 - mflo $t2 - sw $t2, 0($fp) + lw $t5, 20($fp) + lw $t9, 24($fp) + div $t5, $t9 + mflo $t5 + sw $t5, 0($fp) #Executing Assign - lw $t5, -4($fp) - sw $t5, 28($fp) + lw $t0, -4($fp) + sw $t0, 28($fp) #Executing typeof lw $t5, 28($fp) lw $t5, 0($t5) sw $t5, 32($fp) #Executing GetAttr lw $t0, -4($fp) - lw $t4, 8($t0) - sw $t4, 40($fp) + lw $t5, 8($t0) + sw $t5, 40($fp) #Executing GetAttr - lw $t1, -4($fp) - lw $t2, 4($t1) + lw $t5, -4($fp) + lw $t2, 4($t5) sw $t2, 44($fp) #Executing Star Operation - lw $t1, 40($fp) - lw $t9, 44($fp) - mult $t1, $t9 - mflo $t1 - sw $t1, 36($fp) + lw $t2, 40($fp) + lw $t5, 44($fp) + mult $t2, $t5 + mflo $t2 + sw $t2, 36($fp) #Receiving Arg local_Main_main_internal_7 - lw $t4, 28($fp) - sw $t4, 0($sp) + lw $t3, 28($fp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Receiving Arg local_Main_main_internal_9 - lw $t5, 36($fp) - sw $t5, 0($sp) + lw $t3, 36($fp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing Dynamic Call - lw $t9, 32($fp) - lw $t1, 16($t9) - jalr $t1 + lw $t2, 32($fp) + lw $t9, 16($t2) + jalr $t9 sw $a1, 0($fp) addi $sp, $sp, -8 #Executing Return diff --git a/tests/code_gen/unary_nodes.mips b/tests/code_gen/unary_nodes.mips index d526b9076..9923ab6f7 100644 --- a/tests/code_gen/unary_nodes.mips +++ b/tests/code_gen/unary_nodes.mips @@ -2,15 +2,15 @@ Object : .word, Object_abort, Object_copy, Object_type_name Object_cname : .asciiz, "Object" -IO : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int +IO : .word, Object_abort, IO_copy, IO_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int IO_cname : .asciiz, "IO" -String : .word, Object_abort, Object_copy, Object_type_name, String_length, String_concat, String_substr +String : .word, Object_abort, String_copy, String_type_name, String_length, String_concat, String_substr String_cname : .asciiz, "String" -Int : .word, Object_abort, Object_copy, Object_type_name +Int : .word, Object_abort, Int_copy, Int_type_name Int_cname : .asciiz, "Int" -Bool : .word, Object_abort, Object_copy, Object_type_name +Bool : .word, Object_abort, Bool_copy, Bool_type_name Bool_cname : .asciiz, "Bool" -Main : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int, Main_main, Main_constructor +Main : .word, Object_abort, Main_copy, Main_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int, Main_main, Main_constructor Main_cname : .asciiz, "Main" void : .word, -1 empty_string : .asciiz, "" @@ -22,6 +22,12 @@ dispatch_on_void : .asciiz, "Dispatch on void" division_by_zero : .asciiz, "Division by zero" substr_out_of_range : .asciiz, "Substring out of range" heap_overflow : .asciiz, "Heap overflow" +type_name_Object : .asciiz, "Object" +type_name_IO : .asciiz, "IO" +type_name_String : .asciiz, "String" +type_name_Int : .asciiz, "Int" +type_name_Bool : .asciiz, "Bool" +type_name_Main : .asciiz, "Main" .text .globl main @@ -48,6 +54,33 @@ copy: j copy_loop copy_end: j $ra +main: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Static Call + jal Main_constructor + sw $a1, 0($fp) + addi $sp, $sp, 0 + #Receiving Arg local_main_internal_0 + lw $t4, 0($fp) + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing Static Call + jal Main_main + sw $a1, 4($fp) + addi $sp, $sp, -4 + li $v0, 10 + syscall Object_abort: move $t5 $fp #New $fp @@ -70,7 +103,7 @@ Object_abort: li $v0, 10 syscall Object_copy: - move $t2 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -79,9 +112,16 @@ Object_copy: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t5, Object + sw $t5, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -99,7 +139,7 @@ Object_type_name: #New $fp move $fp $sp #Reserving space for locals - addi $sp, $sp, 4 + addi $sp, $sp, 8 #Pushing $ra sw $ra, 0($sp) addi $sp, $sp, 4 @@ -107,6 +147,27 @@ Object_type_name: sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t9, String + sw $t9, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t9, String + sw $t9, 0($v0) + li $t9, 6 + sw $t9, 4($v0) + la $t9, type_name_Object + sw $t9, 8($v0) + #Executing Assign + lw $t1, 4($fp) + sw $t1, 0($fp) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -116,7 +177,85 @@ Object_type_name: addi $sp, $sp, -4 lw $ra, 0($sp) #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra +IO_copy: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t0, IO + sw $t0, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +IO_type_name: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t5, String + sw $t5, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t0, String + sw $t0, 0($v0) + li $t0, 2 + sw $t0, 4($v0) + la $t0, type_name_IO + sw $t0, 8($v0) + #Executing Assign + lw $t1, 4($fp) + sw $t1, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 #Return jump jalr $ra IO_out_string: @@ -150,7 +289,7 @@ IO_out_string: #Return jump jalr $ra IO_out_int: - move $t3 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -159,7 +298,7 @@ IO_out_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintIntNode @@ -179,7 +318,7 @@ IO_out_int: #Return jump jalr $ra IO_in_string: - move $t5 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -188,7 +327,7 @@ IO_in_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t5, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions #ReadStrNode @@ -205,8 +344,8 @@ IO_in_string: li $v0, 9 syscall move $t6 $v0 - move $t3 $v0 - move $t5 $a0 + move $t5 $v0 + move $t4 $a0 #Copying bytes from one char array to another jal copy #Null-terminating the string @@ -216,11 +355,11 @@ IO_in_string: li $a0, 12 syscall sw $v0, 0($fp) - la $t1, String - sw $t1, 0($v0) + la $t9, String + sw $t9, 0($v0) #Storing length and reference to char array - sw $t5, 4($v0) - sw $t3, 8($v0) + sw $t4, 4($v0) + sw $t5, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -246,36 +385,88 @@ IO_in_int: sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions - #ReadStrNode - #Reading String to buffer - la $a0, input_str_buffer - li $a1, 1024 - li $v0, 8 + #ReadIntNode + li $v0, 5 syscall - #Saving reference to read string - move $t7 $a0 - #Calculating str length - jal length - #Allocating char array for new string + sw $v0, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_copy: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate li $v0, 9 + li $a0, 12 syscall - move $t6 $v0 - move $t2 $v0 - move $t0 $a0 - #Copying bytes from one char array to another - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance + sw $v0, 0($fp) + la $t3, String + sw $t3, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_type_name: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate li $v0, 9 li $a0, 12 syscall sw $v0, 0($fp) + la $t5, String + sw $t5, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) la $t3, String sw $t3, 0($v0) - #Storing length and reference to char array - sw $t0, 4($v0) - sw $t2, 8($v0) + li $t3, 6 + sw $t3, 4($v0) + la $t3, type_name_String + sw $t3, 8($v0) + #Executing Assign + lw $t1, 4($fp) + sw $t1, 0($fp) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -285,11 +476,11 @@ IO_in_int: addi $sp, $sp, -4 lw $ra, 0($sp) #Cleaning stack after call - addi $sp, $sp, -4 + addi $sp, $sp, -8 #Return jump jalr $ra String_length: - move $t1 $fp + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -298,13 +489,13 @@ String_length: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Length - lw $t4, -4($fp) - lw $t4, 4($t4) - sw $t4, 0($fp) + lw $t2, -4($fp) + lw $t2, 4($t2) + sw $t2, 0($fp) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -318,7 +509,7 @@ String_length: #Return jump jalr $ra String_concat: - move $t3 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -327,7 +518,7 @@ String_concat: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #Loading length @@ -335,14 +526,14 @@ String_concat: lw $s1, 4($s1) lw $s2, -4($fp) lw $s2, 4($s2) - add $t2, $s1, $s2 + add $t0, $s1, $s2 #Allocating new char array - move $a0 $t2 + move $a0 $t0 addi $a0, $a0, 1 li $v0, 9 syscall move $t6 $v0 - move $t4 $v0 + move $t2 $v0 #Copying bytes from first string lw $t7, -8($fp) lw $t7, 8($t7) @@ -360,11 +551,11 @@ String_concat: li $a0, 12 syscall sw $v0, 0($fp) - la $t0, String - sw $t0, 0($v0) + la $t1, String + sw $t1, 0($v0) #Storing length and reference to char array - sw $t2, 4($v0) - sw $t4, 8($v0) + sw $t0, 4($v0) + sw $t2, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -378,7 +569,7 @@ String_concat: #Return jump jalr $ra String_substr: - move $t2 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -387,7 +578,7 @@ String_substr: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Substring @@ -407,14 +598,14 @@ String_substr: move $a0 $s0 jal copy #Null-terminating the string - sb $zero, 0($t0) + sb $zero, 0($t6) #Allocating new String instance li $v0, 9 li $a0, 12 syscall sw $v0, 0($fp) - la $t0, String - sw $t0, 0($v0) + la $t4, String + sw $t4, 0($v0) #Storing length and reference to char array lw $s0, -4($fp) sw $s0, 4($v0) @@ -431,7 +622,7 @@ String_substr: addi $sp, $sp, -4 #Return jump jalr $ra -Object_constructor: +Int_copy: move $t2 $fp #New $fp move $fp $sp @@ -446,11 +637,11 @@ Object_constructor: #Executing instructions #Executing Allocate li $v0, 9 - li $a0, 4 + li $a0, 8 syscall sw $v0, 0($fp) - la $t5, Object - sw $t5, 0($v0) + la $t9, Int + sw $t9, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -463,7 +654,53 @@ Object_constructor: addi $sp, $sp, -4 #Return jump jalr $ra -IO_constructor: +Int_type_name: + move $t5 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t1, String + sw $t1, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t1, String + sw $t1, 0($v0) + li $t1, 3 + sw $t1, 4($v0) + la $t1, type_name_Int + sw $t1, 8($v0) + #Executing Assign + lw $t3, 4($fp) + sw $t3, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra +Bool_copy: move $t3 $fp #New $fp move $fp $sp @@ -478,11 +715,121 @@ IO_constructor: #Executing instructions #Executing Allocate li $v0, 9 - li $a0, 4 + li $a0, 8 syscall sw $v0, 0($fp) - la $t9, IO + la $t5, Bool + sw $t5, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Bool_type_name: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t2, String + sw $t2, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t9, String sw $t9, 0($v0) + li $t9, 4 + sw $t9, 4($v0) + la $t9, type_name_Bool + sw $t9, 8($v0) + #Executing Assign + lw $t2, 4($fp) + sw $t2, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra +Object_constructor: + move $t5 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t2, Object + sw $t2, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +IO_constructor: + move $t2 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t3, IO + sw $t3, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -496,7 +843,7 @@ IO_constructor: #Return jump jalr $ra Int_constructor: - move $t3 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -505,7 +852,7 @@ Int_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -513,8 +860,8 @@ Int_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t2, Int - sw $t2, 0($v0) + la $t3, Int + sw $t3, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -528,7 +875,7 @@ Int_constructor: #Return jump jalr $ra Bool_constructor: - move $t1 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -537,7 +884,7 @@ Bool_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -545,8 +892,8 @@ Bool_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t9, Bool - sw $t9, 0($v0) + la $t5, Bool + sw $t5, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -560,7 +907,7 @@ Bool_constructor: #Return jump jalr $ra String_constructor: - move $t4 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -569,7 +916,7 @@ String_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -577,8 +924,8 @@ String_constructor: li $a0, 12 syscall sw $v0, 0($fp) - la $t2, String - sw $t2, 0($v0) + la $t9, String + sw $t9, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -591,35 +938,110 @@ String_constructor: addi $sp, $sp, -4 #Return jump jalr $ra -main: - move $t2 $fp +Main_copy: + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals - addi $sp, $sp, 8 + addi $sp, $sp, 16 #Pushing $ra sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions - #Executing Static Call - jal Main_constructor - sw $a1, 0($fp) - addi $sp, $sp, 0 - #Receiving Arg local_main_internal_0 + #Executing Allocate + li $v0, 9 + li $a0, 16 + syscall + sw $v0, 0($fp) + la $t9, Main + sw $t9, 0($v0) + #Executing GetAttr + lw $t1, -4($fp) + lw $t9, 4($t1) + sw $t9, 4($fp) + #Executing SetAttr + lw $t1, 0($fp) + lw $t5, 4($fp) + sw $t5, 4($t1) + #Executing GetAttr + lw $t3, -4($fp) + lw $t2, 8($t3) + sw $t2, 8($fp) + #Executing SetAttr lw $t9, 0($fp) - sw $t9, 0($sp) - addi $sp, $sp, 4 - #Executing Static Call - jal Main_main - sw $a1, 4($fp) + lw $t1, 8($fp) + sw $t1, 8($t9) + #Executing GetAttr + lw $t5, -4($fp) + lw $t9, 12($t5) + sw $t9, 12($fp) + #Executing SetAttr + lw $t2, 0($fp) + lw $t3, 12($fp) + sw $t3, 12($t2) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp addi $sp, $sp, -4 - li $v0, 10 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -16 + #Return jump + jalr $ra +Main_type_name: + move $t0 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 syscall + sw $v0, 0($fp) + la $t0, String + sw $t0, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t0, String + sw $t0, 0($v0) + li $t0, 4 + sw $t0, 4($v0) + la $t0, type_name_Main + sw $t0, 8($v0) + #Executing Assign + lw $t5, 4($fp) + sw $t5, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra Main_constructor: - move $t3 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -628,7 +1050,7 @@ Main_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t3, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -636,29 +1058,29 @@ Main_constructor: li $a0, 16 syscall sw $v0, 0($fp) - la $t5, Main - sw $t5, 0($v0) + la $t2, Main + sw $t2, 0($v0) #Executing DefaultValue - li $t2, 0 - sw $t2, 4($fp) + li $t5, 0 + sw $t5, 4($fp) #Executing SetAttr - lw $t5, 0($fp) - lw $t1, 4($fp) - sw $t1, 4($t5) + lw $t9, 0($fp) + lw $t2, 4($fp) + sw $t2, 4($t9) #Executing DefaultValue li $t9, 0 sw $t9, 8($fp) #Executing SetAttr lw $t9, 0($fp) - lw $t2, 8($fp) - sw $t2, 8($t9) + lw $t1, 8($fp) + sw $t1, 8($t9) #Executing DefaultValue - li $t5, 0 - sw $t5, 12($fp) + li $t3, 0 + sw $t3, 12($fp) #Executing SetAttr - lw $t5, 0($fp) - lw $t9, 12($fp) - sw $t9, 12($t5) + lw $t9, 0($fp) + lw $t2, 12($fp) + sw $t2, 12($t9) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -672,7 +1094,7 @@ Main_constructor: #Return jump jalr $ra Main_main: - move $t1 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -681,37 +1103,37 @@ Main_main: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t1, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Assign lw $t2, -4($fp) sw $t2, 4($fp) #Executing typeof - lw $t9, 4($fp) - lw $t9, 0($t9) - sw $t9, 8($fp) + lw $t5, 4($fp) + lw $t5, 0($t5) + sw $t5, 8($fp) #Executing GetAttr lw $t1, -4($fp) - lw $t3, 4($t1) - sw $t3, 16($fp) + lw $t9, 4($t1) + sw $t9, 16($fp) #Executing Int Complement - lw $t2, 16($fp) - not $t4, $t2 - addi $t4, $t4, 1 - sw $t4, 12($fp) + lw $t3, 16($fp) + not $t9, $t3 + addi $t9, $t9, 1 + sw $t9, 12($fp) #Receiving Arg local_Main_main_internal_1 lw $t1, 4($fp) sw $t1, 0($sp) addi $sp, $sp, 4 #Receiving Arg local_Main_main_internal_3 - lw $t9, 12($fp) - sw $t9, 0($sp) + lw $t0, 12($fp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing Dynamic Call - lw $t2, 8($fp) - lw $t5, 16($t2) - jalr $t5 + lw $t1, 8($fp) + lw $t2, 16($t1) + jalr $t2 sw $a1, 0($fp) addi $sp, $sp, -8 #Executing Return diff --git a/tests/code_gen/while.mips b/tests/code_gen/while.mips index 8325b1480..0931a66e2 100644 --- a/tests/code_gen/while.mips +++ b/tests/code_gen/while.mips @@ -2,15 +2,15 @@ Object : .word, Object_abort, Object_copy, Object_type_name Object_cname : .asciiz, "Object" -IO : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int +IO : .word, Object_abort, IO_copy, IO_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int IO_cname : .asciiz, "IO" -String : .word, Object_abort, Object_copy, Object_type_name, String_length, String_concat, String_substr +String : .word, Object_abort, String_copy, String_type_name, String_length, String_concat, String_substr String_cname : .asciiz, "String" -Int : .word, Object_abort, Object_copy, Object_type_name +Int : .word, Object_abort, Int_copy, Int_type_name Int_cname : .asciiz, "Int" -Bool : .word, Object_abort, Object_copy, Object_type_name +Bool : .word, Object_abort, Bool_copy, Bool_type_name Bool_cname : .asciiz, "Bool" -Main : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int, Main_main, Main_constructor +Main : .word, Object_abort, Main_copy, Main_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int, Main_main, Main_constructor Main_cname : .asciiz, "Main" void : .word, -1 empty_string : .asciiz, "" @@ -22,21 +22,27 @@ dispatch_on_void : .asciiz, "Dispatch on void" division_by_zero : .asciiz, "Division by zero" substr_out_of_range : .asciiz, "Substring out of range" heap_overflow : .asciiz, "Heap overflow" +type_name_Object : .asciiz, "Object" +type_name_IO : .asciiz, "IO" +type_name_String : .asciiz, "String" +type_name_Int : .asciiz, "Int" +type_name_Bool : .asciiz, "Bool" +type_name_Main : .asciiz, "Main" string_1 : .asciiz, "iteration \n" .text .globl main length: - li $t1, 0 + li $t2, 0 length_loop: - lb $t5, 0($a0) - beq $zero, $t5, length_end - add $t1, $t1, 1 + lb $t1, 0($a0) + beq $zero, $t1, length_end + add $t2, $t2, 1 add $a0, $a0, 1 j length_loop length_end: - move $a0 $t1 + move $a0 $t2 j $ra copy: copy_loop: @@ -49,12 +55,12 @@ copy: j copy_loop copy_end: j $ra -Object_abort: +main: move $t3 $fp #New $fp move $fp $sp #Reserving space for locals - addi $sp, $sp, 0 + addi $sp, $sp, 8 #Pushing $ra sw $ra, 0($sp) addi $sp, $sp, 4 @@ -62,6 +68,33 @@ Object_abort: sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions + #Executing Static Call + jal Main_constructor + sw $a1, 0($fp) + addi $sp, $sp, 0 + #Receiving Arg local_main_internal_0 + lw $t0, 0($fp) + sw $t0, 0($sp) + addi $sp, $sp, 4 + #Executing Static Call + jal Main_main + sw $a1, 4($fp) + addi $sp, $sp, -4 + li $v0, 10 + syscall +Object_abort: + move $t2 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 0 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t2, 0($sp) + addi $sp, $sp, 4 + #Executing instructions #Executing RuntimeError #Printing Abort Message la $a0, abort_signal @@ -71,7 +104,7 @@ Object_abort: li $v0, 10 syscall Object_copy: - move $t4 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -80,9 +113,16 @@ Object_copy: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t0, Object + sw $t0, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -96,7 +136,53 @@ Object_copy: #Return jump jalr $ra Object_type_name: - move $t9 $fp + move $t4 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t4, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t0, String + sw $t0, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t0, String + sw $t0, 0($v0) + li $t0, 6 + sw $t0, 4($v0) + la $t0, type_name_Object + sw $t0, 8($v0) + #Executing Assign + lw $t9, 4($fp) + sw $t9, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra +IO_copy: + move $t2 $fp #New $fp move $fp $sp #Reserving space for locals @@ -105,9 +191,16 @@ Object_type_name: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t2, 0($sp) addi $sp, $sp, 4 #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t9, IO + sw $t9, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -120,8 +213,54 @@ Object_type_name: addi $sp, $sp, -4 #Return jump jalr $ra +IO_type_name: + move $t5 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t5, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t5, String + sw $t5, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t0, String + sw $t0, 0($v0) + li $t0, 2 + sw $t0, 4($v0) + la $t0, type_name_IO + sw $t0, 8($v0) + #Executing Assign + lw $t5, 4($fp) + sw $t5, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra IO_out_string: - move $t4 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -130,7 +269,7 @@ IO_out_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintStringNode @@ -151,7 +290,7 @@ IO_out_string: #Return jump jalr $ra IO_out_int: - move $t4 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -160,7 +299,7 @@ IO_out_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #PrintIntNode @@ -180,7 +319,7 @@ IO_out_int: #Return jump jalr $ra IO_in_string: - move $t5 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -189,7 +328,7 @@ IO_in_string: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t5, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #ReadStrNode @@ -206,8 +345,8 @@ IO_in_string: li $v0, 9 syscall move $t6 $v0 - move $t4 $v0 - move $t3 $a0 + move $t2 $v0 + move $t9 $a0 #Copying bytes from one char array to another jal copy #Null-terminating the string @@ -217,11 +356,11 @@ IO_in_string: li $a0, 12 syscall sw $v0, 0($fp) - la $t2, String - sw $t2, 0($v0) + la $t0, String + sw $t0, 0($v0) #Storing length and reference to char array - sw $t3, 4($v0) - sw $t4, 8($v0) + sw $t9, 4($v0) + sw $t2, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -235,7 +374,7 @@ IO_in_string: #Return jump jalr $ra IO_in_int: - move $t2 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -244,39 +383,91 @@ IO_in_int: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions - #ReadStrNode - #Reading String to buffer - la $a0, input_str_buffer - li $a1, 1024 - li $v0, 8 + #ReadIntNode + li $v0, 5 syscall - #Saving reference to read string - move $t7 $a0 - #Calculating str length - jal length - #Allocating char array for new string + sw $v0, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_copy: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate li $v0, 9 + li $a0, 12 syscall - move $t6 $v0 - move $t4 $v0 - move $t9 $a0 - #Copying bytes from one char array to another - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance + sw $v0, 0($fp) + la $t1, String + sw $t1, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +String_type_name: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate li $v0, 9 li $a0, 12 syscall sw $v0, 0($fp) - la $t5, String - sw $t5, 0($v0) - #Storing length and reference to char array - sw $t9, 4($v0) - sw $t4, 8($v0) + la $t0, String + sw $t0, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t2, String + sw $t2, 0($v0) + li $t2, 6 + sw $t2, 4($v0) + la $t2, type_name_String + sw $t2, 8($v0) + #Executing Assign + lw $t9, 4($fp) + sw $t9, 0($fp) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -286,11 +477,11 @@ IO_in_int: addi $sp, $sp, -4 lw $ra, 0($sp) #Cleaning stack after call - addi $sp, $sp, -4 + addi $sp, $sp, -8 #Return jump jalr $ra String_length: - move $t9 $fp + move $t4 $fp #New $fp move $fp $sp #Reserving space for locals @@ -299,13 +490,13 @@ String_length: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t9, 0($sp) + sw $t4, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Length - lw $t1, -4($fp) - lw $t1, 4($t1) - sw $t1, 0($fp) + lw $t4, -4($fp) + lw $t4, 4($t4) + sw $t4, 0($fp) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -319,7 +510,7 @@ String_length: #Return jump jalr $ra String_concat: - move $t2 $fp + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals @@ -328,7 +519,7 @@ String_concat: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions #Loading length @@ -343,7 +534,7 @@ String_concat: li $v0, 9 syscall move $t6 $v0 - move $t5 $v0 + move $t9 $v0 #Copying bytes from first string lw $t7, -8($fp) lw $t7, 8($t7) @@ -361,11 +552,11 @@ String_concat: li $a0, 12 syscall sw $v0, 0($fp) - la $t2, String - sw $t2, 0($v0) + la $t4, String + sw $t4, 0($v0) #Storing length and reference to char array sw $t3, 4($v0) - sw $t5, 8($v0) + sw $t9, 8($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -379,7 +570,7 @@ String_concat: #Return jump jalr $ra String_substr: - move $t4 $fp + move $t0 $fp #New $fp move $fp $sp #Reserving space for locals @@ -388,7 +579,7 @@ String_substr: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t4, 0($sp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Substring @@ -408,14 +599,14 @@ String_substr: move $a0 $s0 jal copy #Null-terminating the string - sb $zero, 0($t0) + sb $zero, 0($t6) #Allocating new String instance li $v0, 9 li $a0, 12 syscall sw $v0, 0($fp) - la $t5, String - sw $t5, 0($v0) + la $t4, String + sw $t4, 0($v0) #Storing length and reference to char array lw $s0, -4($fp) sw $s0, 4($v0) @@ -432,7 +623,7 @@ String_substr: addi $sp, $sp, -4 #Return jump jalr $ra -Object_constructor: +Int_copy: move $t0 $fp #New $fp move $fp $sp @@ -447,11 +638,11 @@ Object_constructor: #Executing instructions #Executing Allocate li $v0, 9 - li $a0, 4 + li $a0, 8 syscall sw $v0, 0($fp) - la $t4, Object - sw $t4, 0($v0) + la $t3, Int + sw $t3, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -464,8 +655,54 @@ Object_constructor: addi $sp, $sp, -4 #Return jump jalr $ra -IO_constructor: - move $t0 $fp +Int_type_name: + move $t3 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t9, String + sw $t9, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t1, String + sw $t1, 0($v0) + li $t1, 3 + sw $t1, 4($v0) + la $t1, type_name_Int + sw $t1, 8($v0) + #Executing Assign + lw $t3, 4($fp) + sw $t3, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra +Bool_copy: + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -474,7 +711,85 @@ IO_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 8 + syscall + sw $v0, 0($fp) + la $t5, Bool + sw $t5, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra +Bool_type_name: + move $t3 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t3, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t9, String + sw $t9, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t0, String + sw $t0, 0($v0) + li $t0, 4 + sw $t0, 4($v0) + la $t0, type_name_Bool + sw $t0, 8($v0) + #Executing Assign + lw $t0, 4($fp) + sw $t0, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra +Object_constructor: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -482,7 +797,7 @@ IO_constructor: li $a0, 4 syscall sw $v0, 0($fp) - la $t0, IO + la $t0, Object sw $t0, 0($v0) #Executing Return lw $a1, 0($fp) @@ -496,8 +811,40 @@ IO_constructor: addi $sp, $sp, -4 #Return jump jalr $ra +IO_constructor: + move $t9 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 4 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t9, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 4 + syscall + sw $v0, 0($fp) + la $t5, IO + sw $t5, 0($v0) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -4 + #Return jump + jalr $ra Int_constructor: - move $t0 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -506,7 +853,7 @@ Int_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t0, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -514,8 +861,8 @@ Int_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t3, Int - sw $t3, 0($v0) + la $t1, Int + sw $t1, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -546,8 +893,8 @@ Bool_constructor: li $a0, 8 syscall sw $v0, 0($fp) - la $t1, Bool - sw $t1, 0($v0) + la $t9, Bool + sw $t9, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -561,7 +908,7 @@ Bool_constructor: #Return jump jalr $ra String_constructor: - move $t2 $fp + move $t3 $fp #New $fp move $fp $sp #Reserving space for locals @@ -570,7 +917,7 @@ String_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t3, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -578,8 +925,8 @@ String_constructor: li $a0, 12 syscall sw $v0, 0($fp) - la $t3, String - sw $t3, 0($v0) + la $t9, String + sw $t9, 0($v0) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -592,35 +939,102 @@ String_constructor: addi $sp, $sp, -4 #Return jump jalr $ra -main: - move $t2 $fp +Main_copy: + move $t5 $fp #New $fp move $fp $sp #Reserving space for locals - addi $sp, $sp, 8 + addi $sp, $sp, 12 #Pushing $ra sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t5, 0($sp) addi $sp, $sp, 4 #Executing instructions - #Executing Static Call - jal Main_constructor - sw $a1, 0($fp) - addi $sp, $sp, 0 - #Receiving Arg local_main_internal_0 - lw $t3, 0($fp) - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing Static Call - jal Main_main - sw $a1, 4($fp) + #Executing Allocate + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 0($fp) + la $t1, Main + sw $t1, 0($v0) + #Executing GetAttr + lw $t9, -4($fp) + lw $t3, 4($t9) + sw $t3, 4($fp) + #Executing SetAttr + lw $t0, 0($fp) + lw $t5, 4($fp) + sw $t5, 4($t0) + #Executing GetAttr + lw $t1, -4($fp) + lw $t5, 8($t1) + sw $t5, 8($fp) + #Executing SetAttr + lw $t9, 0($fp) + lw $t2, 8($fp) + sw $t2, 8($t9) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp addi $sp, $sp, -4 - li $v0, 10 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -12 + #Return jump + jalr $ra +Main_type_name: + move $t1 $fp + #New $fp + move $fp $sp + #Reserving space for locals + addi $sp, $sp, 8 + #Pushing $ra + sw $ra, 0($sp) + addi $sp, $sp, 4 + #Saving $fp + sw $t1, 0($sp) + addi $sp, $sp, 4 + #Executing instructions + #Executing Allocate + li $v0, 9 + li $a0, 12 syscall + sw $v0, 0($fp) + la $t2, String + sw $t2, 0($v0) + #Executing Load + li $v0, 9 + li $a0, 12 + syscall + sw $v0, 4($fp) + la $t3, String + sw $t3, 0($v0) + li $t3, 4 + sw $t3, 4($v0) + la $t3, type_name_Main + sw $t3, 8($v0) + #Executing Assign + lw $t9, 4($fp) + sw $t9, 0($fp) + #Executing Return + lw $a1, 0($fp) + #Restoring saved $fp + addi $sp, $sp, -4 + lw $fp, 0($sp) + #Restoring saved $ra + addi $sp, $sp, -4 + lw $ra, 0($sp) + #Cleaning stack after call + addi $sp, $sp, -8 + #Return jump + jalr $ra Main_constructor: - move $t2 $fp + move $t1 $fp #New $fp move $fp $sp #Reserving space for locals @@ -629,7 +1043,7 @@ Main_constructor: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t1, 0($sp) addi $sp, $sp, 4 #Executing instructions #Executing Allocate @@ -637,36 +1051,36 @@ Main_constructor: li $a0, 12 syscall sw $v0, 0($fp) - la $t3, Main - sw $t3, 0($v0) + la $t9, Main + sw $t9, 0($v0) #Executing DefaultValue - li $t1, 0 - sw $t1, 4($fp) + li $t2, 0 + sw $t2, 4($fp) #Executing SetAttr - lw $t4, 0($fp) - lw $t1, 4($fp) - sw $t1, 4($t4) + lw $t9, 0($fp) + lw $t0, 4($fp) + sw $t0, 4($t9) #Executing DefaultValue - li $t1, 0 - sw $t1, 8($fp) + li $t2, 0 + sw $t2, 8($fp) #Executing SetAttr - lw $t3, 0($fp) - lw $t1, 8($fp) - sw $t1, 8($t3) + lw $t0, 0($fp) + lw $t2, 8($fp) + sw $t2, 8($t0) #Executing Assign - li $t2, 0 - sw $t2, 12($fp) + li $t3, 0 + sw $t3, 12($fp) #Executing SetAttr - lw $t9, 0($fp) - lw $t1, 12($fp) - sw $t1, 4($t9) + lw $t2, 0($fp) + lw $t3, 12($fp) + sw $t3, 4($t2) #Executing Assign - li $t4, 3 - sw $t4, 16($fp) + li $t9, 3 + sw $t9, 16($fp) #Executing SetAttr - lw $t4, 0($fp) - lw $t2, 16($fp) - sw $t2, 8($t4) + lw $t5, 0($fp) + lw $t1, 16($fp) + sw $t1, 8($t5) #Executing Return lw $a1, 0($fp) #Restoring saved $fp @@ -680,7 +1094,7 @@ Main_constructor: #Return jump jalr $ra Main_main: - move $t2 $fp + move $t9 $fp #New $fp move $fp $sp #Reserving space for locals @@ -689,56 +1103,56 @@ Main_main: sw $ra, 0($sp) addi $sp, $sp, 4 #Saving $fp - sw $t2, 0($sp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing instructions WHILE_1: #Executing GetAttr - lw $t4, -4($fp) - lw $t1, 4($t4) - sw $t1, 8($fp) + lw $t1, -4($fp) + lw $t5, 4($t1) + sw $t5, 8($fp) #Executing GetAttr - lw $t9, -4($fp) - lw $t0, 8($t9) - sw $t0, 12($fp) + lw $t5, -4($fp) + lw $t3, 8($t5) + sw $t3, 12($fp) #Executing Less Operation lw $t9, 8($fp) - lw $t0, 12($fp) - slt $t3, $t9, $t0 - sw $t3, 4($fp) - lw $t1, 4($fp) - bnez $t1, BODY_2 + lw $t5, 12($fp) + slt $t0, $t9, $t5 + sw $t0, 4($fp) + lw $t5, 4($fp) + bnez $t5, BODY_2 #Executing Goto j END_WHILE_3 BODY_2: #Executing Assign - lw $t0, -4($fp) - sw $t0, 20($fp) + lw $t1, -4($fp) + sw $t1, 20($fp) #Executing typeof - lw $t9, 20($fp) - lw $t9, 0($t9) - sw $t9, 24($fp) + lw $t0, 20($fp) + lw $t0, 0($t0) + sw $t0, 24($fp) #Executing GetAttr - lw $t2, -4($fp) - lw $t1, 4($t2) - sw $t1, 28($fp) + lw $t9, -4($fp) + lw $t0, 4($t9) + sw $t0, 28($fp) #Receiving Arg local_Main_main_internal_5 lw $t9, 20($fp) sw $t9, 0($sp) addi $sp, $sp, 4 #Receiving Arg local_Main_main_internal_7 - lw $t4, 28($fp) - sw $t4, 0($sp) + lw $t0, 28($fp) + sw $t0, 0($sp) addi $sp, $sp, 4 #Executing Dynamic Call - lw $t1, 24($fp) - lw $t9, 16($t1) - jalr $t9 + lw $t9, 24($fp) + lw $t1, 16($t9) + jalr $t1 sw $a1, 16($fp) addi $sp, $sp, -8 #Executing Assign - lw $t3, -4($fp) - sw $t3, 32($fp) + lw $t5, -4($fp) + sw $t5, 32($fp) #Executing typeof lw $t0, 32($fp) lw $t0, 0($t0) @@ -748,48 +1162,48 @@ Main_main: li $a0, 12 syscall sw $v0, 40($fp) - la $t1, String - sw $t1, 0($v0) - li $t1, 12 - sw $t1, 4($v0) - la $t1, string_1 - sw $t1, 8($v0) + la $t5, String + sw $t5, 0($v0) + li $t5, 12 + sw $t5, 4($v0) + la $t5, string_1 + sw $t5, 8($v0) #Receiving Arg local_Main_main_internal_8 lw $t1, 32($fp) sw $t1, 0($sp) addi $sp, $sp, 4 #Receiving Arg local_Main_main_internal_10 - lw $t2, 40($fp) - sw $t2, 0($sp) + lw $t9, 40($fp) + sw $t9, 0($sp) addi $sp, $sp, 4 #Executing Dynamic Call - lw $t4, 36($fp) - lw $t9, 12($t4) - jalr $t9 + lw $t2, 36($fp) + lw $t3, 12($t2) + jalr $t3 sw $a1, 16($fp) addi $sp, $sp, -8 #Executing GetAttr lw $t1, -4($fp) - lw $t9, 4($t1) - sw $t9, 44($fp) + lw $t3, 4($t1) + sw $t3, 44($fp) #Executing Assign - li $t2, 1 - sw $t2, 48($fp) + li $t1, 1 + sw $t1, 48($fp) #Executing Plus Operation - lw $t1, 44($fp) - lw $t4, 48($fp) - add $t0, $t1, $t4 - sw $t0, 16($fp) + lw $t2, 44($fp) + lw $t0, 48($fp) + add $t1, $t2, $t0 + sw $t1, 16($fp) #Executing SetAttr - lw $t3, -4($fp) - lw $t9, 16($fp) - sw $t9, 4($t3) + lw $t0, -4($fp) + lw $t3, 16($fp) + sw $t3, 4($t0) #Executing Goto j WHILE_1 END_WHILE_3: #Executing DefaultValue - la $t4, void - sw $t4, 0($fp) + la $t0, void + sw $t0, 0($fp) #Executing Return lw $a1, 0($fp) #Restoring saved $fp From 028d8a5b43d9149d356fb048e24e705afc80fc6c Mon Sep 17 00:00:00 2001 From: gabriela Date: Wed, 9 Mar 2022 02:59:57 -0500 Subject: [PATCH 135/162] First Readme scratch. --- Readme.md | 149 ++------------------------------------------------ doc/Readme.md | 38 ++++++------- doc/Report.md | 130 +++++++++++++++++++++++++++++++++++++++++++ doc/team.yml | 4 +- src/Readme.md | 9 +-- 5 files changed, 155 insertions(+), 175 deletions(-) create mode 100644 doc/Report.md diff --git a/Readme.md b/Readme.md index a47d48b9e..663062365 100644 --- a/Readme.md +++ b/Readme.md @@ -1,6 +1,6 @@ # COOL: Proyecto de Compilación -> Proyecto base para el compilador de 4to año en Ciencia de la Computación. +> Forked from: https://github.com/matcom/cool-compiler-2021, proyecto base para el compilador de 4to año en Ciencia de la Computación. ## Generalidades @@ -10,158 +10,19 @@ funcional para el lenguaje _COOL_. _COOL (Classroom Object-Oriented Language)_ es un pequeño lenguaje que puede ser implementado con un esfuerzo razonable en un semestre del curso. Aun así, _COOL_ mantiene muchas de las características de los lenguajes de programación modernos, incluyendo orientación a objetos, tipado estático y manejo automático de memoria. -## Cómo comenzar (o terminar) - -El proyecto de Compilación será recogido y evaluado **únicamente** a través de Github. Es imprescindible tener una cuenta de Github para cada participante, y que su proyecto esté correctamente hosteado en esta plataforma. A continuación le damos las instrucciones mínimas necesarias para ello: - -### 1. Si no lo han hecho ya, regístrense en [Github](https://github.com) todos los miembros del equipo (es gratis). - -![](img/img1.png) - -### 2. Haga click en el botón **Fork** para hacer una copia del proyecto en el perfil de Github de uno de los miembros. - -Opcionalmente pueden [crear una organización](https://github.com/organizations/new) y copiar el proyecto en el perfil de la misma. - -![](img/img2.png) - -### 3. Una vez hecho esto, tendrá un nuevo repositorio en `github/`. - -Revise que el repositorio de su equipo está en su perfil. -En este ejemplo se ha copiado a la cuenta de `github.com/apiad`. - -Debe indicar bajo el nombre del repositorio: `"forked from matcom/cool-compiler-2021"`. - -![](img/img3.png) - -### 4. Clone este proyecto en un repositorio local. - -Busque la URL de su proyecto en la interfaz web de Github. - -Asegúrese de clonar **su copia** y no el proyecto original en `matcom/cool-compiler-2021`. - -![](img/img4.png) - -```bash -$ git clone git@github.com:/cool-compiler-2021.git -``` - -> Donde `` es posiblemente el nombre de su equipo o del miembro donde se hizo el _fork_. - -A partir de este punto debe tener un proyecto `cool-compiler-2021` local. -El siguiente paso depende de si usted ya tiene su código versionado con `git` o no. - -### 5.A. Si tiene su proyecto en git (y no quiere perder la historia): - -#### 5.1. Mezcle hacia el nuevo respositorio su repositorio anterior: - -```bash -$ cd cool-compiler-2021 -$ git pull --allow-unrelated-histories master -``` - -#### 5.2. Organice su proyecto, código fuente y documentación, de acuerdo a las instrucciones de este documento, y vuelva a hacer `commit`. - -```bash -$ mv src/ -$ git add . -$ git commit -a -m "Mezclado con el proyecto base" -``` - -#### 5.3. A partir de este punto puede hacer `push` cada vez que tenga cambios que subir. - -```bash -$ git push origin master -``` - -### 5.B Si aún no tiene su proyecto en git (o no le importa la historia): - -#### 5.1. Simplemente copie el código de su proyecto en la carpeta correspondiente `src` y haga su primer commit. - -```bash -$ mv src/ -$ git commit -a -m "Hello Git!" -``` - -#### 5.2. A partir de este punto asegúrese de hacer `commit` de forma regular para mantener su repositorio actualizado. - -Si necesita saber más sobre `git`, todo lo imprescindible está en [esta guía](doc/github-git-cheat-sheet.pdf). - -#### 5.3. A partir de este punto puede hacer `push` cada vez que tenga cambios que subir. - -```bash -$ git push origin master -``` - -## Entregas - -En este proyecto se realizarán entregas parciales a lo largo del curso. Para realizar una entrega, siga los siguientes pasos. - -### 1. Cree un pull request al proyecto original desde su copia. - -![](img/img5.png) - -### 2. Asegúrese de tener la siguiente configuración antes de hacer click en **Create pull request**. - -- **base repository**: `matcom/cool-compiler-2021` (repositorio original) - - **branch**: `master` -- **head repository**: `/cool-compiler-2021` (repositorio propio) - - **branch**: `master` (o la que corresponda) - -> Asegúrese que se indica **Able to merge**. De lo contrario, existen cambios en el repositorio original que usted no tiene, y debe actualizarlos. - -> **NOTA**: Asegúrese que el _pull request_ se hace a la rama `master`. - -![](img/img6.png) - -### 3. Introduzca un título y descripción adecuados, y haga click en **Create pull request**. - -![](img/img7.png) - -### 4. Espere mientras se ejecutan las pruebas. - -Verá la indicación **Some checks haven't completed yet**. - -![](img/img8.png) - -Es posible que tenga que actualizar los cambios que se hayan hecho en el repositorio original, por ejemplo, si se han agregado nuevos tests. En este caso obtendrá el siguiente mensaje: - -> **This branch is out-of-date with base branch** - -Haga click en **Update branch** y siga las instrucciones. -### 5. Verifique que no hubo errores en las pruebas. - -Si ve el mensaje **(All | Some) checks have failed**, significa que su código no pasó las pruebas. - -![](img/img9.png) - -Para ver los resultados de las pruebas haga click en el link **Details**. - -![](img/img10.png) - - -### 6. Arregle los errores y repita el paso 5 hasta que todas las pruebas pasen. - -Para cualquier modificación que haga a su proyecto, haga _commit_ y _push_ para **su repositorio personal** y automáticamente se actualizará el estado del _pull request_ y se volverán a ejecutar las pruebas. **No es necesario** abrir un _pull request_ nuevo por cada entrega, sino actualizar el anterior. - -> **Por favor asegúrese de mantener un solo _pull request_ activo por equipo**. En caso de abrir uno nuevo, cerrar el anterior. - ## Sobre la implementación -Ponga todo su código e instrucciones necesarias en la carpeta `src`. Más información en [`src/Readme.md`](src/Readme.md). +Todo el código e instrucciones necesarias se encuentran en la carpeta `src`. Más información en [`src/Readme.md`](src/Readme.md). ## Sobre la documentación -Usted debe presentar un reporte escrito documentando el proceso de construcción de su compilador y los detalles más importantes de su funcionamiento. Más información en [`doc/Readme.md`](doc/Readme.md). - -## Sobre los equipos de desarrollo - -Para desarrollar el compilador del lenguaje COOL se trabajará en equipos de 2 o 3 integrantes. +Se presenta un reporte escrito documentando el proceso de construcción del compilador y los detalles más importantes de su funcionamiento. Más información en [`doc/Readme.md`](doc/Readme.md). ## Sobre los casos de prueba -La carpeta `tests` contiene todos los casos de prueba que son obligatorios de pasar para que su proyecto tenga derecho a ser evaluado. +La carpeta `tests` contiene casos de prueba. -Estos tests se ejecutan automáticamente cada vez que hace un _pull request_ al repositorio `matcom/cool-compiler-2021`. Solo aquellos proyectos que pasen todas las pruebas con éxito serán evaluados. +Estos tests se ejecutan automáticamente cada vez que hace un _pull request_ al repositorio `matcom/cool-compiler-2021`. Para ejecutar las pruebas localmente, debe tener instalado `Python 3.7`, `pip` y `make` (normalmente viene con Linux). Ejecute: diff --git a/doc/Readme.md b/doc/Readme.md index 3b2569f5c..0f99e034c 100644 --- a/doc/Readme.md +++ b/doc/Readme.md @@ -1,33 +1,29 @@ # Documentación -## Readme - -Modifique el contenido de este documento para documentar de forma clara y concisa los siguientes aspectos: +En el archivo report.md se explican los detalles de la implementación del proyecto. A continuación se pueden encontrar indicaciones para su uso. -- Cómo ejecutar (y compilar si es necesario) su compilador. -- Requisitos adicionales, dependencias, configuración, etc. -- Opciones adicionales que tenga su compilador. - -## Sobre los Equipos de Desarrollo +## Readme -Para desarrollar el compilador del lenguaje COOL se trabajará en equipos de 2 o 3 integrantes. El proyecto de Compilación será recogido y evaluado únicamente a través de Github. Es imprescindible tener una cuenta de Github para cada participante, y que su proyecto esté correctamente hosteado en esta plataforma. +Para ejecutar el compilador de Cool que aquí se presenta existen ciertos requerimientos a tener en cuenta. En el archivo *requirements.py* que se encuentra en el directorio raiz del proyecto se encuentran listados los mismos. -**⚠️ NOTA**: Debe completar el archivo `team.yml` con los datos correctos de cada miembro de su equipo. +Para una rápida instalación de todas estas dependencias se debe ejecutar el siguiente comando: -## Sobre los Materiales a Entregar +```bash +$ pip install -r requirements.txt +``` -Para la evaluación del proyecto Ud. debe entregar un informe en formato PDF (`report.pdf`) en esta carpeta, que resuma de manera organizada y comprensible la arquitectura e implementación de su compilador. -El documento no tiene límite de extensión. -En él explicará en más detalle su solución a los problemas que, durante la implementación de cada una de las fases del proceso de compilación, hayan requerido de Ud. especial atención. +Una vez añadidas las mismas se puede proceder a compilador un código dado en Cool a ensamblador. Con este fin, ejecute: -## Estructura del reporte +```bash +$ ./coolc.sh +``` -Usted es libre de estructurar su reporte escrito como más conveniente le parezca. A continuación le sugerimos algunas secciones que no deberían faltar, aunque puede mezclar, renombrar y organizarlas de la manera que mejor le parezca: +en una consola centrada en el directorio *src* que se encuentra en la raiz del proyecto. Aquí sería un archivo escrito en cool. -- **Uso del compilador**: detalles sobre las opciones de líneas de comando, si tiene opciones adicionales (e.j., `--ast` genera un AST en JSON, etc.). Básicamente lo mismo que pondrá en este Readme. -- **Arquitectura del compilador**: una explicación general de la arquitectura, en cuántos módulos se divide el proyecto, cuantas fases tiene, qué tipo de gramática se utiliza, y en general, como se organiza el proyecto. Una buena imagen siempre ayuda. -- **Problemas técnicos**: detalles sobre cualquier problema teórico o técnico interesante que haya necesitado resolver de forma particular. +El *output* esperado es un archivo con el mismo nombre pero en .mips, el cual debe correrse con el correspondiente intérprete: -## Sobre la Fecha de Entrega +```bash +$ spim -file +``` -Se realizarán recogidas parciales del proyecto a lo largo del curso. En el Canal de Telegram se anunciará la fecha y requisitos de cada entrega. +que finalmente nos mostrará el resultado correspondiente al programa de entrada. \ No newline at end of file diff --git a/doc/Report.md b/doc/Report.md new file mode 100644 index 000000000..3b862bcdd --- /dev/null +++ b/doc/Report.md @@ -0,0 +1,130 @@ +## Introducción + +Cool(Classroom Object-Oriented Language) es un lenguaje de programación orientado a +objetos que, aunque pequeño, tiene muchas caracterı́sticas relevantes de lenguajes modernos. Su orientación a objetos, su tipado dinámico y el resto de sus features lo hacen muy atractivo e ideal para un primer acercamiento al mundo de los Compiladores. + +En el presente trabajo se muestra una implementación de un Compilador funcional para Cool en el lenguaje de programación python: *El Compi*. + +En las próximas secciones se explican en detalle cada una de las fases en las que se divide el trabajo del mismo, como fue abordada cada una, las instrucciones para su uso y algunos otros detalles importantes a resaltar. + + +## Instrucciones para la ejecución + +Para utilizar *El Compi* y ejecutar un programa en el lenguaje cool se han de seguir los siguientes pasos: + +1- Primero se debe verificar que se cuente con todas las dependencias necesarias. Para una rápida instalación de estas se puede ejecutar el comando: + +```bash +$ pip install -r requirements.txt +``` + +2- Para compilador un código dado en Cool a ensamblador, ejecute: + +```bash +$ ./coolc.sh +``` +en una consola centrada en el directorio *src* que se encuentra en la raiz del proyecto. Aquí sería un archivo escrito en cool. + +3- El *output* esperado es un archivo con el mismo nombre pero en .mips, el cual debe correrse con el correspondiente intérprete: + +```bash +$ spim -file +``` +que finalmente nos mostrará el resultado correspondiente al programa de entrada (spim se encuentra entre los requirements especificados). + + +## Arquitectura del compilador: + +*El Compi*, para tener la funcionalidad completa de un compilador, transita por las fases fundamentales de: + +-Análisis sintáctico (Análisis léxico y parsing) + +-Análisis semántico + +-Generación de código (Generación de un lenguaje intermedio y traducción a mips) + +Más adelante se analizan con más profundidad cada una. + +El código fuente del proyecto se encuentra en la carpeta *src*. En esta se hallan distribuidos los scripts según su funcionalidad. + +**FOTO de los archivos del proyecto** + +Si lo miramos como módulos, podemos decir que el módulo de lexe... en *code_gen* encontramos todo lo referente al proceso de generación de código... + +**COMPLETAR** + +Analicemos ahora los prometidos detalles de implementacion y diseño del compilador tan anunciados. + +## Gramática +El primer paso para acercarnos al lenguaje objeto de análisis fue definir una gramática adecuada. Siguiendo lo referido por el manual de Cool (el cual se encuentra adjunto en la carpeta *doc*, con el resto de la documentación), se utilizó una gramática que respetara la precedencia necesaria de los operadores y la estructura requerida. En el archivo cool grammar.py puede observarse como fue modelada la misma. + +Como ahí se puede apreciar, un programa de Cool +consiste en una serie de definiciones de clases. Cada +clase a su vez posee un conjunto de atributos y de fun- +ciones. Las expresiones que pueden formar parte de +dichas funciones son el corazón del lenguaje. +En la imagen *1* se pueden apreciar varios niveles intermedios de la gramática que precisamente definen diferentes tipos de expresiones: + +1. , que representa las operaciones donde se +comparan elementos. + +2. , que engloba a las operaciones de suma y +resta. + +3. , para la multiplicación y división. + +4. , como representación de los operadores +unarios isvoid, opuesto y new. + +5. para las expresiones entre paréntsis, +los block y las llamadas a funciones. + +6. como el nivel más básico, donde se ex- +cuentran los números, ids, las expresiones boolea- +nas y los strings. + +**IMAGEN** Figura 1: Fragmento de la gramática de Cool. + +## Análisis sintáctico + +### Tokenizer +Para tokenizar la entrada se utilizó una herramienta bastante útil y práctica: PLY (https://www.dabeaz.com/ply/ply.html), el cual consiste en una implementación en python de las herramientas de parsing les y yaxx. Mediante el módulo lex que esta provee, es posible acceder a un analizador léxico ya implementado. + +Para utilizar esta herramienta se definieron una serie de reglas que orientaran al tokenizador como trabajar en las cadenas de entrada. En el archivo +token rules se pueden observar dichas reglas, las cuáles consisten fundamentalmente en definiciones de los patrones que sigue cada token deseado, con la ayuda de expresiones regulares. En este sentido, se +trabajó fundamentalmente con el módulo re de python, el cual permite definir dichas expresiones. + +HABLAR DE COMO SE DEFINEN LSO COMENTARIOS +PONER UNA FOTO DE ALGUNA REGLA + +Es importante destacar que los tokens de *lex* registran la posición que ocupan en el texto de entrada, considerando el mismo como una array de caracterres. Esto, con la ayuda de una regla para la detección de saltos de línea nos permite tener bien identificada la fila y la columna de un caracter en el script inicial, lo cual es sumamente importante en futuras fases del compilador para ubicar y reportar los errores detectados. + +### Parser + +En cambio, para el parser, no fue la variante de ycc la que se decidió utilizar. En este caso, nos mantuvimos fieles a la implementación efectuada por el equipo en proyectos pasados, la cual se puede apreciar en el archivo *shift_reduce* parsers. Este cuenta con las modificaciones pertinentes para adaptarse a los nuevos requerimientos, por ejemplo, para la detección de fila y columna se realiza ahora el parseo sobre tokens del lenguaje, en lugar de sobre simples lexemas. + +Con el uso del parser LR1 que aquí se provee y la gramática atributada de *cool_grammar* es posible parsear un texto en cool y obtener un árbol correspondiente a una derivación de extrema derecha. + +La construcción de este árbol o ast ($abstract syntax tree$) es la base del resto del análisis que se efectúa por el compilador. A lo largo de la ejecución del proyecto se utilizan una serie de estos árboles, pero primero que se menciona está formado por los nodos que se encuentran en el archivo $ast_nodes.py$. + +## Chequeo semántico: + +Una vez se tenga un ast con la sintaxis adecuada en mano, la fase siguiente consiste en verificar que el programa en cuestión esté correcto semánticamente. + +Con este fin se realizan 3 recorridos sobre el árbol, apoyándonos en el patrón visitor propuesto: + +HABLAR DEL CONTEXTO Y DE COMO SE DEFINE +COMO SE REFGISTRA UNA CLASE CON SUS TIPOS BLABLABLA +-TypeCollector: Cuyo objetivo es registrar los tipos definidos por el programa. Aquí sólo se lanza un error cuando se intenta redefinir un tipo, o sea cuando aparece su definición más de una vez en el script propuesto. + +-TypeBuilder: Recorrido que busca asignar los métodos y definiciones de atributos a sus clases correspondientes, y detectar errores relacionados con referencias a tipos inexistentes. En este caso es necesario notar que, como Cool permite la herencia, se debe asegurar en este recorrido que no existan ciclos entre las definiciones de clases. Además, para poder garantizar que no se redefinan métodos ni atributos, se asegura que en el momento de definición de un hijo ya se haya visitado al padre, de modo que se tenga constancia de los valores heredados para el análisis. + +-TypeChecker: En este último recorrido sí se visitan la totalidad de nodos del ast creado, no sólo los correspondientes a definiciones de clases, métodos o atributos como en las pasadas anteriores. A medida que se recorre el árbol, con el contexto ya populado con las tipos correspondientes al programa y sus propiedades, se va chequeando que se haga un uso correcto de tipos a lo largo de las expresiones utilizadas, que no se referencien variables o atributos inexistentes o fuera de scope, etc, reportando siempre los errores encontrados. + +## Generación de código: + +### Paso de Cool a CIL: + +... +### De CIL de MIPS: + ... \ No newline at end of file diff --git a/doc/team.yml b/doc/team.yml index 213e106cc..2639b83fc 100644 --- a/doc/team.yml +++ b/doc/team.yml @@ -1,8 +1,8 @@ members: - - name: Amalia Ibarra Rodriguez + - name: Amalia Ibarra Rodríguez github: amaliaibarra group: C412 - - name: Gabriela Martinez Giraldo + - name: Gabriela B. Martínez Giraldo github: matcom-chacha group: C412 - name: Sandra Martos Llanes diff --git a/src/Readme.md b/src/Readme.md index 1200371b5..bf4934828 100644 --- a/src/Readme.md +++ b/src/Readme.md @@ -1,14 +1,7 @@ # COOL: Proyecto de Compilación - -La evaluación de la asignatura Complementos de Compilación, inscrita en el programa del 4to año de la Licenciatura en Ciencia de la Computación de la Facultad de Matemática y Computación de la -Universidad de La Habana, consiste este curso en la implementación de un compilador completamente -funcional para el lenguaje _COOL_. - -_COOL (Classroom Object-Oriented Language)_ es un pequeño lenguaje que puede ser implementado con un esfuerzo razonable en un semestre del curso. Aun así, _COOL_ mantiene muchas de las características de los lenguajes de programación modernos, incluyendo orientación a objetos, tipado estático y manejo automático de memoria. - ### Sobre el Lenguaje COOL -Ud. podrá encontrar la especificación formal del lenguaje COOL en el documento _"COOL Language Reference Manual"_, que se distribuye junto con el presente texto. +Ud. podrá encontrar la especificación formal del lenguaje COOL en el documento _"COOL Language Reference Manual"_, en la carpeta *doc* en el directorio raiz del proyecto. ## Código Fuente From c9105264be2bdb17a366a5ec8532dc0169e912f1 Mon Sep 17 00:00:00 2001 From: smartos99 Date: Wed, 9 Mar 2022 12:17:00 -0500 Subject: [PATCH 136/162] Merge before testing --- src/code_gen/cil_builder.py | 9 +- tests/code_gen/comparison.cl | 11 +- tests/code_gen/comparison.mips | 794 --------------------- tests/code_gen/comparison_output.txt | 2 +- tests/code_gen/hello_world.mips | 710 ------------------ tests/code_gen/object_methods.cl | 13 + tests/code_gen/object_methods_input.txt | 0 tests/code_gen/object_methods_output.txt | 2 + tests/code_gen/point.mips | 814 --------------------- tests/code_gen/read_string.mips | 738 ------------------- tests/code_gen/string_methods _output.cl | 1 - tests/code_gen/string_methods.mips | 868 ----------------------- tests/code_gen/test_goto_if.mips | 780 -------------------- tests/code_gen/unary_nodes.mips | 728 ------------------- tests/code_gen/while.mips | 804 --------------------- 15 files changed, 28 insertions(+), 6246 deletions(-) delete mode 100644 tests/code_gen/comparison.mips delete mode 100644 tests/code_gen/hello_world.mips create mode 100644 tests/code_gen/object_methods.cl create mode 100644 tests/code_gen/object_methods_input.txt create mode 100644 tests/code_gen/object_methods_output.txt delete mode 100644 tests/code_gen/point.mips delete mode 100644 tests/code_gen/read_string.mips delete mode 100644 tests/code_gen/string_methods _output.cl delete mode 100644 tests/code_gen/string_methods.mips delete mode 100644 tests/code_gen/test_goto_if.mips delete mode 100644 tests/code_gen/unary_nodes.mips delete mode 100644 tests/code_gen/while.mips diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index cf80af71a..1789abc24 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -141,7 +141,6 @@ def is_attribute(self, vname): return vname not in [var.name for var in self.current_function.localvars] and ( vname not in [param.name for param in self.current_function.params] ) - def add_builtin_constructors(self): builtin_types = ["Object", "IO", "Int", "Bool", "String"] for typex in builtin_types: @@ -224,6 +223,7 @@ def add_builtin_functions(self): io_type.methods = obj_functions + functions # String + self.attrs["String"] = {"length": (0, "Int"), "str_ref": (1,"String")} functions = [ self.cil_predef_method("copy", "String", self.object_copy), self.cil_predef_method("type_name", "String", self.object_type_name), @@ -239,6 +239,7 @@ def add_builtin_functions(self): string_type.methods = obj_functions + functions # Int + #self.attrs["Int"] = {"value": (0, "Int")} int_type = TypeNode("Int") int_type.attributes = [VariableInfo("value", is_attr=True).name] int_type.methods = obj_functions + [ @@ -247,6 +248,7 @@ def add_builtin_functions(self): ] # Bool + #self.attrs["Bool"] = {"value": (0, "Int")} bool_type = TypeNode("Bool") bool_type.attributes = [VariableInfo("value", is_attr=True).name] bool_type.methods = obj_functions + [ @@ -331,18 +333,19 @@ def object_copy(self): for attr in self.attrs[self.current_type.name].keys(): attr_copy_local = self.define_internal_local() + attr_name = self.to_attr_name(self.current_type.name, attr) if self.current_type.name not in ["Int", "String", "Bool"] else attr self.register_instruction( GetAttribNode( attr_copy_local, "self", - self.to_attr_name(self.current_type.name, attr), + attr_name, self.current_type.name, ) ) self.register_instruction( SetAttribNode( copy_local, - self.to_attr_name(self.current_type.name, attr), + attr_name, attr_copy_local, self.current_type.name, ) diff --git a/tests/code_gen/comparison.cl b/tests/code_gen/comparison.cl index 26635d9db..74f8ee15a 100644 --- a/tests/code_gen/comparison.cl +++ b/tests/code_gen/comparison.cl @@ -1,14 +1,15 @@ class Main inherits IO{ - a : Int; - b : Int; + a : Int <- 5; + b : Int <- 4; main (): Object { { - a < b; - a <= b; + a < b; + a <= b; a = b; - out_string(if a <= b then "a<=b" else "a>b" fi); + + out_string(if a < b then "a=b" fi); } }; }; diff --git a/tests/code_gen/comparison.mips b/tests/code_gen/comparison.mips deleted file mode 100644 index b387e1c2a..000000000 --- a/tests/code_gen/comparison.mips +++ /dev/null @@ -1,794 +0,0 @@ -.data - -Object : .word, Object_abort, Object_copy, Object_type_name -Object_cname : .asciiz, "Object" -IO : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int -IO_cname : .asciiz, "IO" -String : .word, Object_abort, Object_copy, Object_type_name, String_length, String_concat, String_substr -String_cname : .asciiz, "String" -Int : .word, Object_abort, Object_copy, Object_type_name -Int_cname : .asciiz, "Int" -Bool : .word, Object_abort, Object_copy, Object_type_name -Bool_cname : .asciiz, "Bool" -Main : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int, Main_main, Main_constructor -Main_cname : .asciiz, "Main" -void : .word, -1 -empty_string : .asciiz, "" -input_str_buffer : .space, 1024 -abort_signal : .asciiz, "Program execution aborted" -case_missmatch : .asciiz, "Execution of a case statement without a matching branch" -case_on_void : .asciiz, "Case on void" -dispatch_on_void : .asciiz, "Dispatch on void" -division_by_zero : .asciiz, "Division by zero" -substr_out_of_range : .asciiz, "Substring out of range" -heap_overflow : .asciiz, "Heap overflow" -string_1 : .asciiz, "a>b" -string_2 : .asciiz, "a<=b" - -.text -.globl main - -length: - li $t9, 0 - length_loop: - lb $t2, 0($a0) - beq $zero, $t2, length_end - add $t9, $t9, 1 - add $a0, $a0, 1 - j length_loop - length_end: - move $a0 $t9 - j $ra -copy: - copy_loop: - beq $zero, $a0, copy_end - lb $t8, 0($t7) - sb $t8, 0($t6) - addi $t6, $t6, 1 - addi $t7, $t7, 1 - addi $a0, $a0, -1 - j copy_loop - copy_end: - j $ra -Object_abort: - move $t5 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 0 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing RuntimeError - #Printing Abort Message - la $a0, abort_signal - li $v0, 4 - syscall - #Aborting execution - li $v0, 10 - syscall -Object_copy: - move $t2 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t2, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Object_type_name: - move $t4 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -IO_out_string: - move $t9 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 0 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t9, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #PrintStringNode - lw $a0, -4($fp) - lw $a0, 8($a0) - li $v0, 4 - syscall - #Executing Return - lw $a1, -8($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, 0 - #Return jump - jalr $ra -IO_out_int: - move $t9 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 0 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t9, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #PrintIntNode - lw $a0, -4($fp) - li $v0, 1 - syscall - #Executing Return - lw $a1, -8($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, 0 - #Return jump - jalr $ra -IO_in_string: - move $t4 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #ReadStrNode - #Reading String to buffer - la $a0, input_str_buffer - li $a1, 1024 - li $v0, 8 - syscall - #Saving reference to read string - move $t7 $a0 - #Calculating str length - jal length - #Allocating char array for new string - li $v0, 9 - syscall - move $t6 $v0 - move $t1 $v0 - move $t5 $a0 - #Copying bytes from one char array to another - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t0, String - sw $t0, 0($v0) - #Storing length and reference to char array - sw $t5, 4($v0) - sw $t1, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -IO_in_int: - move $t3 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #ReadStrNode - #Reading String to buffer - la $a0, input_str_buffer - li $a1, 1024 - li $v0, 8 - syscall - #Saving reference to read string - move $t7 $a0 - #Calculating str length - jal length - #Allocating char array for new string - li $v0, 9 - syscall - move $t6 $v0 - move $t5 $v0 - move $t0 $a0 - #Copying bytes from one char array to another - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t9, String - sw $t9, 0($v0) - #Storing length and reference to char array - sw $t0, 4($v0) - sw $t5, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_length: - move $t5 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Length - lw $t0, -4($fp) - lw $t0, 4($t0) - sw $t0, 0($fp) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_concat: - move $t1 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Loading length - lw $s1, -8($fp) - lw $s1, 4($s1) - lw $s2, -4($fp) - lw $s2, 4($s2) - add $t2, $s1, $s2 - #Allocating new char array - move $a0 $t2 - addi $a0, $a0, 1 - li $v0, 9 - syscall - move $t6 $v0 - move $t9 $v0 - #Copying bytes from first string - lw $t7, -8($fp) - lw $t7, 8($t7) - move $a0 $s1 - jal copy - #Copying bytes from second string - lw $t7, -4($fp) - lw $t7, 8($t7) - move $a0 $s2 - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t5, String - sw $t5, 0($v0) - #Storing length and reference to char array - sw $t2, 4($v0) - sw $t9, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_substr: - move $t9 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t9, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Substring - lw $s0, -4($fp) - move $a0 $s0 - addi $a0, $a0, 1 - li $v0, 9 - syscall - move $t6 $v0 - #Loading reference to char array of source string - lw $t7, -12($fp) - lw $t7, 8($t7) - lw $s2, -8($fp) - add $t7, $t7, $s2 - move $s1 $t6 - #Copying bytes from one char array to another - move $a0 $s0 - jal copy - #Null-terminating the string - sb $zero, 0($t0) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t9, String - sw $t9, 0($v0) - #Storing length and reference to char array - lw $s0, -4($fp) - sw $s0, 4($v0) - sw $s1, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Object_constructor: - move $t3 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 4 - syscall - sw $v0, 0($fp) - la $t1, Object - sw $t1, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -IO_constructor: - move $t1 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 4 - syscall - sw $v0, 0($fp) - la $t1, IO - sw $t1, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Int_constructor: - move $t3 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 8 - syscall - sw $v0, 0($fp) - la $t1, Int - sw $t1, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Bool_constructor: - move $t5 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 8 - syscall - sw $v0, 0($fp) - la $t2, Bool - sw $t2, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_constructor: - move $t2 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t2, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t4, String - sw $t4, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -main: - move $t5 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 8 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Static Call - jal Main_constructor - sw $a1, 0($fp) - addi $sp, $sp, 0 - #Receiving Arg local_main_internal_0 - lw $t5, 0($fp) - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Executing Static Call - jal Main_main - sw $a1, 4($fp) - addi $sp, $sp, -4 - li $v0, 10 - syscall -Main_constructor: - move $t3 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 12 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t3, Main - sw $t3, 0($v0) - #Executing DefaultValue - li $t2, 0 - sw $t2, 4($fp) - #Executing SetAttr - lw $t5, 0($fp) - lw $t0, 4($fp) - sw $t0, 4($t5) - #Executing DefaultValue - li $t3, 0 - sw $t3, 8($fp) - #Executing SetAttr - lw $t0, 0($fp) - lw $t5, 8($fp) - sw $t5, 8($t0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -12 - #Return jump - jalr $ra -Main_main: - move $t4 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 52 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing GetAttr - lw $t3, -4($fp) - lw $t4, 4($t3) - sw $t4, 4($fp) - #Executing GetAttr - lw $t4, -4($fp) - lw $t5, 8($t4) - sw $t5, 8($fp) - #Executing Less Operation - lw $t1, 4($fp) - lw $t5, 8($fp) - slt $t3, $t1, $t5 - sw $t3, 0($fp) - #Executing GetAttr - lw $t2, -4($fp) - lw $t4, 4($t2) - sw $t4, 12($fp) - #Executing GetAttr - lw $t0, -4($fp) - lw $t5, 8($t0) - sw $t5, 16($fp) - #Executing Less Equal Operation - lw $t3, 12($fp) - lw $t5, 16($fp) - sle $t1, $t3, $t5 - sw $t1, 0($fp) - #Executing GetAttr - lw $t2, -4($fp) - lw $t4, 4($t2) - sw $t4, 20($fp) - #Executing GetAttr - lw $t0, -4($fp) - lw $t2, 8($t0) - sw $t2, 24($fp) - #Executing Equal Operation - lw $t3, 20($fp) - lw $t1, 24($fp) - seq $t4, $t3, $t1 - sw $t4, 0($fp) - #Executing Assign - lw $t2, -4($fp) - sw $t2, 28($fp) - #Executing typeof - lw $t2, 28($fp) - lw $t2, 0($t2) - sw $t2, 32($fp) - #Executing GetAttr - lw $t0, -4($fp) - lw $t5, 4($t0) - sw $t5, 44($fp) - #Executing GetAttr - lw $t5, -4($fp) - lw $t0, 8($t5) - sw $t0, 48($fp) - #Executing Less Equal Operation - lw $t0, 44($fp) - lw $t4, 48($fp) - sle $t1, $t0, $t4 - sw $t1, 40($fp) - lw $t2, 40($fp) - bnez $t2, THEN_1 - #Executing Load - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 36($fp) - la $t2, String - sw $t2, 0($v0) - li $t2, 3 - sw $t2, 4($v0) - la $t2, string_1 - sw $t2, 8($v0) - #Executing Goto - j END_IF_2 - THEN_1: - #Executing Load - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 36($fp) - la $t2, String - sw $t2, 0($v0) - li $t2, 4 - sw $t2, 4($v0) - la $t2, string_2 - sw $t2, 8($v0) - END_IF_2: - #Receiving Arg local_Main_main_internal_7 - lw $t5, 28($fp) - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Receiving Arg local_Main_main_internal_9 - lw $t2, 36($fp) - sw $t2, 0($sp) - addi $sp, $sp, 4 - #Executing Dynamic Call - lw $t2, 32($fp) - lw $t1, 12($t2) - jalr $t1 - sw $a1, 0($fp) - addi $sp, $sp, -8 - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -52 - #Return jump - jalr $ra diff --git a/tests/code_gen/comparison_output.txt b/tests/code_gen/comparison_output.txt index 80ac762d5..39a2cc94e 100644 --- a/tests/code_gen/comparison_output.txt +++ b/tests/code_gen/comparison_output.txt @@ -1 +1 @@ -a<=b \ No newline at end of file +a>=b \ No newline at end of file diff --git a/tests/code_gen/hello_world.mips b/tests/code_gen/hello_world.mips deleted file mode 100644 index 1bb10b206..000000000 --- a/tests/code_gen/hello_world.mips +++ /dev/null @@ -1,710 +0,0 @@ -.data - -Object : .word, Object_abort, Object_copy, Object_type_name -Object_cname : .asciiz, "Object" -IO : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int -IO_cname : .asciiz, "IO" -String : .word, Object_abort, Object_copy, Object_type_name, String_length, String_concat, String_substr -String_cname : .asciiz, "String" -Int : .word, Object_abort, Object_copy, Object_type_name -Int_cname : .asciiz, "Int" -Bool : .word, Object_abort, Object_copy, Object_type_name -Bool_cname : .asciiz, "Bool" -Main : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int, Main_main, Main_constructor -Main_cname : .asciiz, "Main" -void : .word, -1 -empty_string : .asciiz, "" -input_str_buffer : .space, 1024 -abort_signal : .asciiz, "Program execution aborted" -case_missmatch : .asciiz, "Execution of a case statement without a matching branch" -case_on_void : .asciiz, "Case on void" -dispatch_on_void : .asciiz, "Dispatch on void" -division_by_zero : .asciiz, "Division by zero" -substr_out_of_range : .asciiz, "Substring out of range" -heap_overflow : .asciiz, "Heap overflow" -string_1 : .asciiz, "Hello, World.\n" - -.text -.globl main - -length: - li $t9, 0 - length_loop: - lb $t0, 0($a0) - beq $zero, $t0, length_end - add $t9, $t9, 1 - add $a0, $a0, 1 - j length_loop - length_end: - move $a0 $t9 - j $ra -copy: - copy_loop: - beq $zero, $a0, copy_end - lb $t8, 0($t7) - sb $t8, 0($t6) - addi $t6, $t6, 1 - addi $t7, $t7, 1 - addi $a0, $a0, -1 - j copy_loop - copy_end: - j $ra -Object_abort: - move $t0 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 0 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t0, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing RuntimeError - #Printing Abort Message - la $a0, abort_signal - li $v0, 4 - syscall - #Aborting execution - li $v0, 10 - syscall -Object_copy: - move $t1 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Object_type_name: - move $t5 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -IO_out_string: - move $t1 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 0 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #PrintStringNode - lw $a0, -4($fp) - lw $a0, 8($a0) - li $v0, 4 - syscall - #Executing Return - lw $a1, -8($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, 0 - #Return jump - jalr $ra -IO_out_int: - move $t4 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 0 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #PrintIntNode - lw $a0, -4($fp) - li $v0, 1 - syscall - #Executing Return - lw $a1, -8($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, 0 - #Return jump - jalr $ra -IO_in_string: - move $t3 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #ReadStrNode - #Reading String to buffer - la $a0, input_str_buffer - li $a1, 1024 - li $v0, 8 - syscall - #Saving reference to read string - move $t7 $a0 - #Calculating str length - jal length - #Allocating char array for new string - li $v0, 9 - syscall - move $t6 $v0 - move $t1 $v0 - move $t0 $a0 - #Copying bytes from one char array to another - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t9, String - sw $t9, 0($v0) - #Storing length and reference to char array - sw $t0, 4($v0) - sw $t1, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -IO_in_int: - move $t5 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #ReadStrNode - #Reading String to buffer - la $a0, input_str_buffer - li $a1, 1024 - li $v0, 8 - syscall - #Saving reference to read string - move $t7 $a0 - #Calculating str length - jal length - #Allocating char array for new string - li $v0, 9 - syscall - move $t6 $v0 - move $t1 $v0 - move $t2 $a0 - #Copying bytes from one char array to another - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t3, String - sw $t3, 0($v0) - #Storing length and reference to char array - sw $t2, 4($v0) - sw $t1, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_length: - move $t9 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t9, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Length - lw $t2, -4($fp) - lw $t2, 4($t2) - sw $t2, 0($fp) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_concat: - move $t0 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t0, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Loading length - lw $s1, -8($fp) - lw $s1, 4($s1) - lw $s2, -4($fp) - lw $s2, 4($s2) - add $t2, $s1, $s2 - #Allocating new char array - move $a0 $t2 - addi $a0, $a0, 1 - li $v0, 9 - syscall - move $t6 $v0 - move $t1 $v0 - #Copying bytes from first string - lw $t7, -8($fp) - lw $t7, 8($t7) - move $a0 $s1 - jal copy - #Copying bytes from second string - lw $t7, -4($fp) - lw $t7, 8($t7) - move $a0 $s2 - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t0, String - sw $t0, 0($v0) - #Storing length and reference to char array - sw $t2, 4($v0) - sw $t1, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_substr: - move $t0 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t0, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Substring - lw $s0, -4($fp) - move $a0 $s0 - addi $a0, $a0, 1 - li $v0, 9 - syscall - move $t6 $v0 - #Loading reference to char array of source string - lw $t7, -12($fp) - lw $t7, 8($t7) - lw $s2, -8($fp) - add $t7, $t7, $s2 - move $s1 $t6 - #Copying bytes from one char array to another - move $a0 $s0 - jal copy - #Null-terminating the string - sb $zero, 0($t0) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t9, String - sw $t9, 0($v0) - #Storing length and reference to char array - lw $s0, -4($fp) - sw $s0, 4($v0) - sw $s1, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Object_constructor: - move $t4 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 4 - syscall - sw $v0, 0($fp) - la $t2, Object - sw $t2, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -IO_constructor: - move $t0 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t0, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 4 - syscall - sw $v0, 0($fp) - la $t2, IO - sw $t2, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Int_constructor: - move $t1 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 8 - syscall - sw $v0, 0($fp) - la $t3, Int - sw $t3, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Bool_constructor: - move $t2 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t2, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 8 - syscall - sw $v0, 0($fp) - la $t2, Bool - sw $t2, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_constructor: - move $t1 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t1, String - sw $t1, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -main: - move $t4 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 8 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Static Call - jal Main_constructor - sw $a1, 0($fp) - addi $sp, $sp, 0 - #Receiving Arg local_main_internal_0 - lw $t1, 0($fp) - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Executing Static Call - jal Main_main - sw $a1, 4($fp) - addi $sp, $sp, -4 - li $v0, 10 - syscall -Main_constructor: - move $t4 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 4 - syscall - sw $v0, 0($fp) - la $t3, Main - sw $t3, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Main_main: - move $t4 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 16 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Assign - lw $t2, -4($fp) - sw $t2, 4($fp) - #Executing typeof - lw $t2, 4($fp) - lw $t2, 0($t2) - sw $t2, 8($fp) - #Executing Load - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 12($fp) - la $t5, String - sw $t5, 0($v0) - li $t5, 15 - sw $t5, 4($v0) - la $t5, string_1 - sw $t5, 8($v0) - #Receiving Arg local_Main_main_internal_1 - lw $t1, 4($fp) - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Receiving Arg local_Main_main_internal_3 - lw $t5, 12($fp) - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Executing Dynamic Call - lw $t0, 8($fp) - lw $t2, 12($t0) - jalr $t2 - sw $a1, 0($fp) - addi $sp, $sp, -8 - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -16 - #Return jump - jalr $ra diff --git a/tests/code_gen/object_methods.cl b/tests/code_gen/object_methods.cl new file mode 100644 index 000000000..41dbc160a --- /dev/null +++ b/tests/code_gen/object_methods.cl @@ -0,0 +1,13 @@ + +class Main inherits IO{ + c : String <- "First sentence.\n"; + d : Int <- 1; + main (): Object { + { + out_string(c.copy()); + out_string(c.type_name()); + + + } + }; +}; diff --git a/tests/code_gen/object_methods_input.txt b/tests/code_gen/object_methods_input.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/code_gen/object_methods_output.txt b/tests/code_gen/object_methods_output.txt new file mode 100644 index 000000000..0c61dbc68 --- /dev/null +++ b/tests/code_gen/object_methods_output.txt @@ -0,0 +1,2 @@ +First sentence. +String \ No newline at end of file diff --git a/tests/code_gen/point.mips b/tests/code_gen/point.mips deleted file mode 100644 index d4f4676de..000000000 --- a/tests/code_gen/point.mips +++ /dev/null @@ -1,814 +0,0 @@ -.data - -Object : .word, Object_abort, Object_copy, Object_type_name -Object_cname : .asciiz, "Object" -IO : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int -IO_cname : .asciiz, "IO" -String : .word, Object_abort, Object_copy, Object_type_name, String_length, String_concat, String_substr -String_cname : .asciiz, "String" -Int : .word, Object_abort, Object_copy, Object_type_name -Int_cname : .asciiz, "Int" -Bool : .word, Object_abort, Object_copy, Object_type_name -Bool_cname : .asciiz, "Bool" -Main : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int, Main_main, Main_constructor -Main_cname : .asciiz, "Main" -Point : .word, Object_abort, Object_copy, Object_type_name, Point_init, Point_constructor -Point_cname : .asciiz, "Point" -void : .word, -1 -empty_string : .asciiz, "" -input_str_buffer : .space, 1024 -abort_signal : .asciiz, "Program execution aborted" -case_missmatch : .asciiz, "Execution of a case statement without a matching branch" -case_on_void : .asciiz, "Case on void" -dispatch_on_void : .asciiz, "Dispatch on void" -division_by_zero : .asciiz, "Division by zero" -substr_out_of_range : .asciiz, "Substring out of range" -heap_overflow : .asciiz, "Heap overflow" - -.text -.globl main - -length: - li $t4, 0 - length_loop: - lb $t5, 0($a0) - beq $zero, $t5, length_end - add $t4, $t4, 1 - add $a0, $a0, 1 - j length_loop - length_end: - move $a0 $t4 - j $ra -copy: - copy_loop: - beq $zero, $a0, copy_end - lb $t8, 0($t7) - sb $t8, 0($t6) - addi $t6, $t6, 1 - addi $t7, $t7, 1 - addi $a0, $a0, -1 - j copy_loop - copy_end: - j $ra -Object_abort: - move $t4 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 0 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing RuntimeError - #Printing Abort Message - la $a0, abort_signal - li $v0, 4 - syscall - #Aborting execution - li $v0, 10 - syscall -Object_copy: - move $t1 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Object_type_name: - move $t2 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t2, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -IO_out_string: - move $t9 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 0 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t9, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #PrintStringNode - lw $a0, -4($fp) - lw $a0, 8($a0) - li $v0, 4 - syscall - #Executing Return - lw $a1, -8($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, 0 - #Return jump - jalr $ra -IO_out_int: - move $t9 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 0 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t9, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #PrintIntNode - lw $a0, -4($fp) - li $v0, 1 - syscall - #Executing Return - lw $a1, -8($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, 0 - #Return jump - jalr $ra -IO_in_string: - move $t1 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #ReadStrNode - #Reading String to buffer - la $a0, input_str_buffer - li $a1, 1024 - li $v0, 8 - syscall - #Saving reference to read string - move $t7 $a0 - #Calculating str length - jal length - #Allocating char array for new string - li $v0, 9 - syscall - move $t6 $v0 - move $t0 $v0 - move $t4 $a0 - #Copying bytes from one char array to another - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t3, String - sw $t3, 0($v0) - #Storing length and reference to char array - sw $t4, 4($v0) - sw $t0, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -IO_in_int: - move $t4 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #ReadStrNode - #Reading String to buffer - la $a0, input_str_buffer - li $a1, 1024 - li $v0, 8 - syscall - #Saving reference to read string - move $t7 $a0 - #Calculating str length - jal length - #Allocating char array for new string - li $v0, 9 - syscall - move $t6 $v0 - move $t5 $v0 - move $t0 $a0 - #Copying bytes from one char array to another - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t1, String - sw $t1, 0($v0) - #Storing length and reference to char array - sw $t0, 4($v0) - sw $t5, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_length: - move $t5 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Length - lw $t3, -4($fp) - lw $t3, 4($t3) - sw $t3, 0($fp) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_concat: - move $t3 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Loading length - lw $s1, -8($fp) - lw $s1, 4($s1) - lw $s2, -4($fp) - lw $s2, 4($s2) - add $t9, $s1, $s2 - #Allocating new char array - move $a0 $t9 - addi $a0, $a0, 1 - li $v0, 9 - syscall - move $t6 $v0 - move $t4 $v0 - #Copying bytes from first string - lw $t7, -8($fp) - lw $t7, 8($t7) - move $a0 $s1 - jal copy - #Copying bytes from second string - lw $t7, -4($fp) - lw $t7, 8($t7) - move $a0 $s2 - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t2, String - sw $t2, 0($v0) - #Storing length and reference to char array - sw $t9, 4($v0) - sw $t4, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_substr: - move $t3 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Substring - lw $s0, -4($fp) - move $a0 $s0 - addi $a0, $a0, 1 - li $v0, 9 - syscall - move $t6 $v0 - #Loading reference to char array of source string - lw $t7, -12($fp) - lw $t7, 8($t7) - lw $s2, -8($fp) - add $t7, $t7, $s2 - move $s1 $t6 - #Copying bytes from one char array to another - move $a0 $s0 - jal copy - #Null-terminating the string - sb $zero, 0($t0) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t4, String - sw $t4, 0($v0) - #Storing length and reference to char array - lw $s0, -4($fp) - sw $s0, 4($v0) - sw $s1, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Object_constructor: - move $t5 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 4 - syscall - sw $v0, 0($fp) - la $t1, Object - sw $t1, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -IO_constructor: - move $t9 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t9, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 4 - syscall - sw $v0, 0($fp) - la $t1, IO - sw $t1, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Int_constructor: - move $t1 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 8 - syscall - sw $v0, 0($fp) - la $t0, Int - sw $t0, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Bool_constructor: - move $t3 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 8 - syscall - sw $v0, 0($fp) - la $t3, Bool - sw $t3, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_constructor: - move $t9 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t9, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t5, String - sw $t5, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -main: - move $t3 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 8 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Static Call - jal Main_constructor - sw $a1, 0($fp) - addi $sp, $sp, 0 - #Receiving Arg local_main_internal_0 - lw $t3, 0($fp) - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing Static Call - jal Main_main - sw $a1, 4($fp) - addi $sp, $sp, -4 - li $v0, 10 - syscall -Main_constructor: - move $t2 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t2, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 4 - syscall - sw $v0, 0($fp) - la $t2, Main - sw $t2, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Main_main: - move $t3 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 32 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Assign - lw $t5, -4($fp) - sw $t5, 4($fp) - #Executing typeof - lw $t9, 4($fp) - lw $t9, 0($t9) - sw $t9, 8($fp) - #Executing Static Call - jal Point_constructor - sw $a1, 16($fp) - addi $sp, $sp, 0 - #Executing typeof - lw $t9, 16($fp) - lw $t9, 0($t9) - sw $t9, 20($fp) - #Executing Assign - li $t1, 5 - sw $t1, 24($fp) - #Executing Assign - li $t3, 6 - sw $t3, 28($fp) - #Receiving Arg local_Main_main_internal_4 - lw $t1, 16($fp) - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Receiving Arg local_Main_main_internal_6 - lw $t0, 24($fp) - sw $t0, 0($sp) - addi $sp, $sp, 4 - #Receiving Arg local_Main_main_internal_7 - lw $t3, 28($fp) - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing Dynamic Call - lw $t5, 20($fp) - lw $t2, 12($t5) - jalr $t2 - sw $a1, 12($fp) - addi $sp, $sp, -12 - #Receiving Arg local_Main_main_internal_1 - lw $t0, 4($fp) - sw $t0, 0($sp) - addi $sp, $sp, 4 - #Receiving Arg local_Main_main_internal_3 - lw $t3, 12($fp) - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing Dynamic Call - lw $t3, 8($fp) - lw $t5, 16($t3) - jalr $t5 - sw $a1, 0($fp) - addi $sp, $sp, -8 - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -32 - #Return jump - jalr $ra -Point_constructor: - move $t1 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 12 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t2, Point - sw $t2, 0($v0) - #Executing DefaultValue - li $t1, 0 - sw $t1, 4($fp) - #Executing SetAttr - lw $t9, 0($fp) - lw $t1, 4($fp) - sw $t1, 4($t9) - #Executing DefaultValue - li $t9, 0 - sw $t9, 8($fp) - #Executing SetAttr - lw $t9, 0($fp) - lw $t2, 8($fp) - sw $t2, 8($t9) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -12 - #Return jump - jalr $ra -Point_init: - move $t1 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 12 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Assign - lw $t1, -8($fp) - sw $t1, 4($fp) - #Executing Assign - lw $t0, -4($fp) - sw $t0, 8($fp) - #Executing Plus Operation - lw $t0, 4($fp) - lw $t9, 8($fp) - add $t1, $t0, $t9 - sw $t1, 0($fp) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -12 - #Return jump - jalr $ra diff --git a/tests/code_gen/read_string.mips b/tests/code_gen/read_string.mips deleted file mode 100644 index d8d334862..000000000 --- a/tests/code_gen/read_string.mips +++ /dev/null @@ -1,738 +0,0 @@ -.data - -Object : .word, Object_abort, Object_copy, Object_type_name -Object_cname : .asciiz, "Object" -IO : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int -IO_cname : .asciiz, "IO" -String : .word, Object_abort, Object_copy, Object_type_name, String_length, String_concat, String_substr -String_cname : .asciiz, "String" -Int : .word, Object_abort, Object_copy, Object_type_name -Int_cname : .asciiz, "Int" -Bool : .word, Object_abort, Object_copy, Object_type_name -Bool_cname : .asciiz, "Bool" -Main : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int, Main_main, Main_constructor -Main_cname : .asciiz, "Main" -void : .word, -1 -empty_string : .asciiz, "" -input_str_buffer : .space, 1024 -abort_signal : .asciiz, "Program execution aborted" -case_missmatch : .asciiz, "Execution of a case statement without a matching branch" -case_on_void : .asciiz, "Case on void" -dispatch_on_void : .asciiz, "Dispatch on void" -division_by_zero : .asciiz, "Division by zero" -substr_out_of_range : .asciiz, "Substring out of range" -heap_overflow : .asciiz, "Heap overflow" - -.text -.globl main - -length: - li $t2, 0 - length_loop: - lb $t0, 0($a0) - beq $zero, $t0, length_end - add $t2, $t2, 1 - add $a0, $a0, 1 - j length_loop - length_end: - move $a0 $t2 - j $ra -copy: - copy_loop: - beq $zero, $a0, copy_end - lb $t8, 0($t7) - sb $t8, 0($t6) - addi $t6, $t6, 1 - addi $t7, $t7, 1 - addi $a0, $a0, -1 - j copy_loop - copy_end: - j $ra -Object_abort: - move $t4 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 0 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing RuntimeError - #Printing Abort Message - la $a0, abort_signal - li $v0, 4 - syscall - #Aborting execution - li $v0, 10 - syscall -Object_copy: - move $t4 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Object_type_name: - move $t1 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -IO_out_string: - move $t1 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 0 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #PrintStringNode - lw $a0, -4($fp) - lw $a0, 8($a0) - li $v0, 4 - syscall - #Executing Return - lw $a1, -8($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, 0 - #Return jump - jalr $ra -IO_out_int: - move $t9 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 0 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t9, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #PrintIntNode - lw $a0, -4($fp) - li $v0, 1 - syscall - #Executing Return - lw $a1, -8($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, 0 - #Return jump - jalr $ra -IO_in_string: - move $t4 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #ReadStrNode - #Reading String to buffer - la $a0, input_str_buffer - li $a1, 1024 - li $v0, 8 - syscall - #Saving reference to read string - move $t7 $a0 - #Calculating str length - jal length - #Allocating char array for new string - li $v0, 9 - syscall - move $t6 $v0 - move $t4 $v0 - move $t2 $a0 - #Copying bytes from one char array to another - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t5, String - sw $t5, 0($v0) - #Storing length and reference to char array - sw $t2, 4($v0) - sw $t4, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -IO_in_int: - move $t3 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #ReadStrNode - #Reading String to buffer - la $a0, input_str_buffer - li $a1, 1024 - li $v0, 8 - syscall - #Saving reference to read string - move $t7 $a0 - #Calculating str length - jal length - #Allocating char array for new string - li $v0, 9 - syscall - move $t6 $v0 - move $t4 $v0 - move $t1 $a0 - #Copying bytes from one char array to another - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t5, String - sw $t5, 0($v0) - #Storing length and reference to char array - sw $t1, 4($v0) - sw $t4, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_length: - move $t3 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Length - lw $t0, -4($fp) - lw $t0, 4($t0) - sw $t0, 0($fp) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_concat: - move $t2 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t2, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Loading length - lw $s1, -8($fp) - lw $s1, 4($s1) - lw $s2, -4($fp) - lw $s2, 4($s2) - add $t1, $s1, $s2 - #Allocating new char array - move $a0 $t1 - addi $a0, $a0, 1 - li $v0, 9 - syscall - move $t6 $v0 - move $t3 $v0 - #Copying bytes from first string - lw $t7, -8($fp) - lw $t7, 8($t7) - move $a0 $s1 - jal copy - #Copying bytes from second string - lw $t7, -4($fp) - lw $t7, 8($t7) - move $a0 $s2 - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t4, String - sw $t4, 0($v0) - #Storing length and reference to char array - sw $t1, 4($v0) - sw $t3, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_substr: - move $t5 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Substring - lw $s0, -4($fp) - move $a0 $s0 - addi $a0, $a0, 1 - li $v0, 9 - syscall - move $t6 $v0 - #Loading reference to char array of source string - lw $t7, -12($fp) - lw $t7, 8($t7) - lw $s2, -8($fp) - add $t7, $t7, $s2 - move $s1 $t6 - #Copying bytes from one char array to another - move $a0 $s0 - jal copy - #Null-terminating the string - sb $zero, 0($t0) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t0, String - sw $t0, 0($v0) - #Storing length and reference to char array - lw $s0, -4($fp) - sw $s0, 4($v0) - sw $s1, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Object_constructor: - move $t4 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 4 - syscall - sw $v0, 0($fp) - la $t1, Object - sw $t1, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -IO_constructor: - move $t3 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 4 - syscall - sw $v0, 0($fp) - la $t1, IO - sw $t1, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Int_constructor: - move $t3 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 8 - syscall - sw $v0, 0($fp) - la $t1, Int - sw $t1, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Bool_constructor: - move $t3 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 8 - syscall - sw $v0, 0($fp) - la $t3, Bool - sw $t3, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_constructor: - move $t5 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t5, String - sw $t5, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -main: - move $t3 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 8 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Static Call - jal Main_constructor - sw $a1, 0($fp) - addi $sp, $sp, 0 - #Receiving Arg local_main_internal_0 - lw $t4, 0($fp) - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing Static Call - jal Main_main - sw $a1, 4($fp) - addi $sp, $sp, -4 - li $v0, 10 - syscall -Main_constructor: - move $t1 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 8 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 8 - syscall - sw $v0, 0($fp) - la $t9, Main - sw $t9, 0($v0) - #Executing DefaultValue - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 4($fp) - la $t2, String - sw $t2, 0($v0) - li $t2, 0 - sw $t2, 4($v0) - la $t2, empty_string - sw $t2, 8($v0) - #Executing SetAttr - lw $t5, 0($fp) - lw $t1, 4($fp) - sw $t1, 4($t5) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -8 - #Return jump - jalr $ra -Main_main: - move $t4 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 24 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Assign - lw $t4, -4($fp) - sw $t4, 4($fp) - #Executing typeof - lw $t9, 4($fp) - lw $t9, 0($t9) - sw $t9, 8($fp) - #Receiving Arg local_Main_main_internal_1 - lw $t5, 4($fp) - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Executing Dynamic Call - lw $t9, 8($fp) - lw $t1, 20($t9) - jalr $t1 - sw $a1, 0($fp) - addi $sp, $sp, -4 - #Executing SetAttr - lw $t4, -4($fp) - lw $t2, 0($fp) - sw $t2, 4($t4) - #Executing Assign - lw $t9, -4($fp) - sw $t9, 12($fp) - #Executing typeof - lw $t3, 12($fp) - lw $t3, 0($t3) - sw $t3, 16($fp) - #Executing GetAttr - lw $t9, -4($fp) - lw $t3, 4($t9) - sw $t3, 20($fp) - #Receiving Arg local_Main_main_internal_3 - lw $t5, 12($fp) - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Receiving Arg local_Main_main_internal_5 - lw $t9, 20($fp) - sw $t9, 0($sp) - addi $sp, $sp, 4 - #Executing Dynamic Call - lw $t9, 16($fp) - lw $t1, 12($t9) - jalr $t1 - sw $a1, 0($fp) - addi $sp, $sp, -8 - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -24 - #Return jump - jalr $ra diff --git a/tests/code_gen/string_methods _output.cl b/tests/code_gen/string_methods _output.cl deleted file mode 100644 index 42bc7029f..000000000 --- a/tests/code_gen/string_methods _output.cl +++ /dev/null @@ -1 +0,0 @@ -First sentence.Second sentence.First sentence. \ No newline at end of file diff --git a/tests/code_gen/string_methods.mips b/tests/code_gen/string_methods.mips deleted file mode 100644 index 6b2c949ae..000000000 --- a/tests/code_gen/string_methods.mips +++ /dev/null @@ -1,868 +0,0 @@ -.data - -Object : .word, Object_abort, Object_copy, Object_type_name -Object_cname : .asciiz, "Object" -IO : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int -IO_cname : .asciiz, "IO" -String : .word, Object_abort, Object_copy, Object_type_name, String_length, String_concat, String_substr -String_cname : .asciiz, "String" -Int : .word, Object_abort, Object_copy, Object_type_name -Int_cname : .asciiz, "Int" -Bool : .word, Object_abort, Object_copy, Object_type_name -Bool_cname : .asciiz, "Bool" -Main : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int, Main_main, Main_constructor -Main_cname : .asciiz, "Main" -void : .word, -1 -empty_string : .asciiz, "" -input_str_buffer : .space, 1024 -abort_signal : .asciiz, "Program execution aborted" -case_missmatch : .asciiz, "Execution of a case statement without a matching branch" -case_on_void : .asciiz, "Case on void" -dispatch_on_void : .asciiz, "Dispatch on void" -division_by_zero : .asciiz, "Division by zero" -substr_out_of_range : .asciiz, "Substring out of range" -heap_overflow : .asciiz, "Heap overflow" -string_1 : .asciiz, "First sentence." -string_2 : .asciiz, "Second sentence." - -.text -.globl main - -length: - li $t0, 0 - length_loop: - lb $t2, 0($a0) - beq $zero, $t2, length_end - add $t0, $t0, 1 - add $a0, $a0, 1 - j length_loop - length_end: - move $a0 $t0 - j $ra -copy: - copy_loop: - beq $zero, $a0, copy_end - lb $t8, 0($t7) - sb $t8, 0($t6) - addi $t6, $t6, 1 - addi $t7, $t7, 1 - addi $a0, $a0, -1 - j copy_loop - copy_end: - j $ra -Object_abort: - move $t1 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 0 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing RuntimeError - #Printing Abort Message - la $a0, abort_signal - li $v0, 4 - syscall - #Aborting execution - li $v0, 10 - syscall -Object_copy: - move $t0 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t0, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Object_type_name: - move $t1 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -IO_out_string: - move $t0 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 0 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t0, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #PrintStringNode - lw $a0, -4($fp) - lw $a0, 8($a0) - li $v0, 4 - syscall - #Executing Return - lw $a1, -8($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, 0 - #Return jump - jalr $ra -IO_out_int: - move $t3 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 0 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #PrintIntNode - lw $a0, -4($fp) - li $v0, 1 - syscall - #Executing Return - lw $a1, -8($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, 0 - #Return jump - jalr $ra -IO_in_string: - move $t4 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #ReadStrNode - #Reading String to buffer - la $a0, input_str_buffer - li $a1, 1024 - li $v0, 8 - syscall - #Saving reference to read string - move $t7 $a0 - #Calculating str length - jal length - #Allocating char array for new string - li $v0, 9 - syscall - move $t6 $v0 - move $t9 $v0 - move $t0 $a0 - #Copying bytes from one char array to another - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t1, String - sw $t1, 0($v0) - #Storing length and reference to char array - sw $t0, 4($v0) - sw $t9, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -IO_in_int: - move $t2 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t2, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #ReadStrNode - #Reading String to buffer - la $a0, input_str_buffer - li $a1, 1024 - li $v0, 8 - syscall - #Saving reference to read string - move $t7 $a0 - #Calculating str length - jal length - #Allocating char array for new string - li $v0, 9 - syscall - move $t6 $v0 - move $t9 $v0 - move $t0 $a0 - #Copying bytes from one char array to another - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t1, String - sw $t1, 0($v0) - #Storing length and reference to char array - sw $t0, 4($v0) - sw $t9, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_length: - move $t2 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t2, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Length - lw $t9, -4($fp) - lw $t9, 4($t9) - sw $t9, 0($fp) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_concat: - move $t4 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Loading length - lw $s1, -8($fp) - lw $s1, 4($s1) - lw $s2, -4($fp) - lw $s2, 4($s2) - add $t5, $s1, $s2 - #Allocating new char array - move $a0 $t5 - addi $a0, $a0, 1 - li $v0, 9 - syscall - move $t6 $v0 - move $t0 $v0 - #Copying bytes from first string - lw $t7, -8($fp) - lw $t7, 8($t7) - move $a0 $s1 - jal copy - #Copying bytes from second string - lw $t7, -4($fp) - lw $t7, 8($t7) - move $a0 $s2 - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t9, String - sw $t9, 0($v0) - #Storing length and reference to char array - sw $t5, 4($v0) - sw $t0, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_substr: - move $t3 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Substring - lw $s0, -4($fp) - move $a0 $s0 - addi $a0, $a0, 1 - li $v0, 9 - syscall - move $t6 $v0 - #Loading reference to char array of source string - lw $t7, -12($fp) - lw $t7, 8($t7) - lw $s2, -8($fp) - add $t7, $t7, $s2 - move $s1 $t6 - #Copying bytes from one char array to another - move $a0 $s0 - jal copy - #Null-terminating the string - sb $zero, 0($t0) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t1, String - sw $t1, 0($v0) - #Storing length and reference to char array - lw $s0, -4($fp) - sw $s0, 4($v0) - sw $s1, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Object_constructor: - move $t3 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 4 - syscall - sw $v0, 0($fp) - la $t4, Object - sw $t4, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -IO_constructor: - move $t4 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 4 - syscall - sw $v0, 0($fp) - la $t4, IO - sw $t4, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Int_constructor: - move $t9 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t9, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 8 - syscall - sw $v0, 0($fp) - la $t3, Int - sw $t3, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Bool_constructor: - move $t2 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t2, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 8 - syscall - sw $v0, 0($fp) - la $t9, Bool - sw $t9, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_constructor: - move $t5 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t3, String - sw $t3, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -main: - move $t0 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 8 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t0, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Static Call - jal Main_constructor - sw $a1, 0($fp) - addi $sp, $sp, 0 - #Receiving Arg local_main_internal_0 - lw $t5, 0($fp) - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Executing Static Call - jal Main_main - sw $a1, 4($fp) - addi $sp, $sp, -4 - li $v0, 10 - syscall -Main_constructor: - move $t9 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 28 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t9, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 20 - syscall - sw $v0, 0($fp) - la $t5, Main - sw $t5, 0($v0) - #Executing DefaultValue - li $t5, 0 - sw $t5, 4($fp) - #Executing SetAttr - lw $t5, 0($fp) - lw $t0, 4($fp) - sw $t0, 4($t5) - #Executing DefaultValue - li $t9, 0 - sw $t9, 8($fp) - #Executing SetAttr - lw $t0, 0($fp) - lw $t4, 8($fp) - sw $t4, 8($t0) - #Executing DefaultValue - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 12($fp) - la $t3, String - sw $t3, 0($v0) - li $t3, 0 - sw $t3, 4($v0) - la $t3, empty_string - sw $t3, 8($v0) - #Executing SetAttr - lw $t4, 0($fp) - lw $t9, 12($fp) - sw $t9, 12($t4) - #Executing DefaultValue - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 16($fp) - la $t2, String - sw $t2, 0($v0) - li $t2, 0 - sw $t2, 4($v0) - la $t2, empty_string - sw $t2, 8($v0) - #Executing SetAttr - lw $t5, 0($fp) - lw $t4, 16($fp) - sw $t4, 16($t5) - #Executing Load - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 20($fp) - la $t5, String - sw $t5, 0($v0) - li $t5, 15 - sw $t5, 4($v0) - la $t5, string_1 - sw $t5, 8($v0) - #Executing SetAttr - lw $t5, 0($fp) - lw $t0, 20($fp) - sw $t0, 12($t5) - #Executing Load - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 24($fp) - la $t0, String - sw $t0, 0($v0) - li $t0, 16 - sw $t0, 4($v0) - la $t0, string_2 - sw $t0, 8($v0) - #Executing SetAttr - lw $t0, 0($fp) - lw $t5, 24($fp) - sw $t5, 16($t0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -28 - #Return jump - jalr $ra -Main_main: - move $t0 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 64 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t0, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Assign - lw $t3, -4($fp) - sw $t3, 4($fp) - #Executing typeof - lw $t5, 4($fp) - lw $t5, 0($t5) - sw $t5, 8($fp) - #Executing GetAttr - lw $t0, -4($fp) - lw $t4, 12($t0) - sw $t4, 16($fp) - #Executing typeof - lw $t3, 16($fp) - lw $t3, 0($t3) - sw $t3, 20($fp) - #Executing GetAttr - lw $t2, -4($fp) - lw $t4, 16($t2) - sw $t4, 24($fp) - #Receiving Arg local_Main_main_internal_4 - lw $t5, 16($fp) - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Receiving Arg local_Main_main_internal_6 - lw $t2, 24($fp) - sw $t2, 0($sp) - addi $sp, $sp, 4 - #Executing Dynamic Call - lw $t3, 20($fp) - lw $t9, 16($t3) - jalr $t9 - sw $a1, 12($fp) - addi $sp, $sp, -8 - #Receiving Arg local_Main_main_internal_1 - lw $t2, 4($fp) - sw $t2, 0($sp) - addi $sp, $sp, 4 - #Receiving Arg local_Main_main_internal_3 - lw $t2, 12($fp) - sw $t2, 0($sp) - addi $sp, $sp, 4 - #Executing Dynamic Call - lw $t5, 8($fp) - lw $t4, 12($t5) - jalr $t4 - sw $a1, 0($fp) - addi $sp, $sp, -8 - #Executing Assign - lw $t4, -4($fp) - sw $t4, 28($fp) - #Executing typeof - lw $t3, 28($fp) - lw $t3, 0($t3) - sw $t3, 32($fp) - #Executing GetAttr - lw $t3, -4($fp) - lw $t5, 12($t3) - sw $t5, 40($fp) - #Executing typeof - lw $t4, 40($fp) - lw $t4, 0($t4) - sw $t4, 44($fp) - #Executing Assign - li $t0, 0 - sw $t0, 48($fp) - #Executing GetAttr - lw $t2, -4($fp) - lw $t9, 12($t2) - sw $t9, 56($fp) - #Executing typeof - lw $t0, 56($fp) - lw $t0, 0($t0) - sw $t0, 60($fp) - #Receiving Arg local_Main_main_internal_14 - lw $t5, 56($fp) - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Executing Dynamic Call - lw $t9, 60($fp) - lw $t5, 12($t9) - jalr $t5 - sw $a1, 52($fp) - addi $sp, $sp, -4 - #Receiving Arg local_Main_main_internal_10 - lw $t3, 40($fp) - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Receiving Arg local_Main_main_internal_12 - lw $t3, 48($fp) - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Receiving Arg local_Main_main_internal_13 - lw $t3, 52($fp) - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing Dynamic Call - lw $t3, 44($fp) - lw $t0, 20($t3) - jalr $t0 - sw $a1, 36($fp) - addi $sp, $sp, -12 - #Receiving Arg local_Main_main_internal_7 - lw $t5, 28($fp) - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Receiving Arg local_Main_main_internal_9 - lw $t4, 36($fp) - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing Dynamic Call - lw $t3, 32($fp) - lw $t4, 12($t3) - jalr $t4 - sw $a1, 0($fp) - addi $sp, $sp, -8 - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -64 - #Return jump - jalr $ra diff --git a/tests/code_gen/test_goto_if.mips b/tests/code_gen/test_goto_if.mips deleted file mode 100644 index 9a48c5b12..000000000 --- a/tests/code_gen/test_goto_if.mips +++ /dev/null @@ -1,780 +0,0 @@ -.data - -Object : .word, Object_abort, Object_copy, Object_type_name -Object_cname : .asciiz, "Object" -IO : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int -IO_cname : .asciiz, "IO" -String : .word, Object_abort, Object_copy, Object_type_name, String_length, String_concat, String_substr -String_cname : .asciiz, "String" -Int : .word, Object_abort, Object_copy, Object_type_name -Int_cname : .asciiz, "Int" -Bool : .word, Object_abort, Object_copy, Object_type_name -Bool_cname : .asciiz, "Bool" -Main : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int, Main_main, Main_constructor -Main_cname : .asciiz, "Main" -void : .word, -1 -empty_string : .asciiz, "" -input_str_buffer : .space, 1024 -abort_signal : .asciiz, "Program execution aborted" -case_missmatch : .asciiz, "Execution of a case statement without a matching branch" -case_on_void : .asciiz, "Case on void" -dispatch_on_void : .asciiz, "Dispatch on void" -division_by_zero : .asciiz, "Division by zero" -substr_out_of_range : .asciiz, "Substring out of range" -heap_overflow : .asciiz, "Heap overflow" - -.text -.globl main - -length: - li $t1, 0 - length_loop: - lb $t0, 0($a0) - beq $zero, $t0, length_end - add $t1, $t1, 1 - add $a0, $a0, 1 - j length_loop - length_end: - move $a0 $t1 - j $ra -copy: - copy_loop: - beq $zero, $a0, copy_end - lb $t8, 0($t7) - sb $t8, 0($t6) - addi $t6, $t6, 1 - addi $t7, $t7, 1 - addi $a0, $a0, -1 - j copy_loop - copy_end: - j $ra -Object_abort: - move $t5 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 0 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing RuntimeError - #Printing Abort Message - la $a0, abort_signal - li $v0, 4 - syscall - #Aborting execution - li $v0, 10 - syscall -Object_copy: - move $t1 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Object_type_name: - move $t5 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -IO_out_string: - move $t9 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 0 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t9, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #PrintStringNode - lw $a0, -4($fp) - lw $a0, 8($a0) - li $v0, 4 - syscall - #Executing Return - lw $a1, -8($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, 0 - #Return jump - jalr $ra -IO_out_int: - move $t2 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 0 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t2, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #PrintIntNode - lw $a0, -4($fp) - li $v0, 1 - syscall - #Executing Return - lw $a1, -8($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, 0 - #Return jump - jalr $ra -IO_in_string: - move $t9 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t9, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #ReadStrNode - #Reading String to buffer - la $a0, input_str_buffer - li $a1, 1024 - li $v0, 8 - syscall - #Saving reference to read string - move $t7 $a0 - #Calculating str length - jal length - #Allocating char array for new string - li $v0, 9 - syscall - move $t6 $v0 - move $t3 $v0 - move $t2 $a0 - #Copying bytes from one char array to another - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t5, String - sw $t5, 0($v0) - #Storing length and reference to char array - sw $t2, 4($v0) - sw $t3, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -IO_in_int: - move $t2 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t2, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #ReadStrNode - #Reading String to buffer - la $a0, input_str_buffer - li $a1, 1024 - li $v0, 8 - syscall - #Saving reference to read string - move $t7 $a0 - #Calculating str length - jal length - #Allocating char array for new string - li $v0, 9 - syscall - move $t6 $v0 - move $t3 $v0 - move $t0 $a0 - #Copying bytes from one char array to another - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t2, String - sw $t2, 0($v0) - #Storing length and reference to char array - sw $t0, 4($v0) - sw $t3, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_length: - move $t9 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t9, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Length - lw $t4, -4($fp) - lw $t4, 4($t4) - sw $t4, 0($fp) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_concat: - move $t2 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t2, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Loading length - lw $s1, -8($fp) - lw $s1, 4($s1) - lw $s2, -4($fp) - lw $s2, 4($s2) - add $t0, $s1, $s2 - #Allocating new char array - move $a0 $t0 - addi $a0, $a0, 1 - li $v0, 9 - syscall - move $t6 $v0 - move $t9 $v0 - #Copying bytes from first string - lw $t7, -8($fp) - lw $t7, 8($t7) - move $a0 $s1 - jal copy - #Copying bytes from second string - lw $t7, -4($fp) - lw $t7, 8($t7) - move $a0 $s2 - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t3, String - sw $t3, 0($v0) - #Storing length and reference to char array - sw $t0, 4($v0) - sw $t9, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_substr: - move $t2 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t2, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Substring - lw $s0, -4($fp) - move $a0 $s0 - addi $a0, $a0, 1 - li $v0, 9 - syscall - move $t6 $v0 - #Loading reference to char array of source string - lw $t7, -12($fp) - lw $t7, 8($t7) - lw $s2, -8($fp) - add $t7, $t7, $s2 - move $s1 $t6 - #Copying bytes from one char array to another - move $a0 $s0 - jal copy - #Null-terminating the string - sb $zero, 0($t0) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t3, String - sw $t3, 0($v0) - #Storing length and reference to char array - lw $s0, -4($fp) - sw $s0, 4($v0) - sw $s1, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Object_constructor: - move $t1 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 4 - syscall - sw $v0, 0($fp) - la $t4, Object - sw $t4, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -IO_constructor: - move $t5 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 4 - syscall - sw $v0, 0($fp) - la $t9, IO - sw $t9, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Int_constructor: - move $t0 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t0, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 8 - syscall - sw $v0, 0($fp) - la $t1, Int - sw $t1, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Bool_constructor: - move $t0 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t0, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 8 - syscall - sw $v0, 0($fp) - la $t1, Bool - sw $t1, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_constructor: - move $t0 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t0, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t9, String - sw $t9, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -main: - move $t1 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 8 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Static Call - jal Main_constructor - sw $a1, 0($fp) - addi $sp, $sp, 0 - #Receiving Arg local_main_internal_0 - lw $t4, 0($fp) - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing Static Call - jal Main_main - sw $a1, 4($fp) - addi $sp, $sp, -4 - li $v0, 10 - syscall -Main_constructor: - move $t4 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 20 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t4, Main - sw $t4, 0($v0) - #Executing DefaultValue - li $t2, 0 - sw $t2, 4($fp) - #Executing SetAttr - lw $t0, 0($fp) - lw $t9, 4($fp) - sw $t9, 4($t0) - #Executing DefaultValue - li $t4, 0 - sw $t4, 8($fp) - #Executing SetAttr - lw $t2, 0($fp) - lw $t4, 8($fp) - sw $t4, 8($t2) - #Executing Assign - li $t1, 1 - sw $t1, 12($fp) - #Executing SetAttr - lw $t1, 0($fp) - lw $t5, 12($fp) - sw $t5, 4($t1) - #Executing Assign - li $t5, 2 - sw $t5, 16($fp) - #Executing SetAttr - lw $t2, 0($fp) - lw $t9, 16($fp) - sw $t9, 8($t2) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -20 - #Return jump - jalr $ra -Main_main: - move $t1 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 48 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing GetAttr - lw $t0, -4($fp) - lw $t9, 4($t0) - sw $t9, 4($fp) - #Executing GetAttr - lw $t4, -4($fp) - lw $t9, 8($t4) - sw $t9, 8($fp) - #Executing Plus Operation - lw $t0, 4($fp) - lw $t2, 8($fp) - add $t9, $t0, $t2 - sw $t9, 0($fp) - #Executing GetAttr - lw $t0, -4($fp) - lw $t1, 4($t0) - sw $t1, 12($fp) - #Executing GetAttr - lw $t2, -4($fp) - lw $t0, 8($t2) - sw $t0, 16($fp) - #Executing Minus Operation - lw $t1, 12($fp) - lw $t4, 16($fp) - sub $t2, $t1, $t4 - sw $t2, 0($fp) - #Executing GetAttr - lw $t9, -4($fp) - lw $t1, 4($t9) - sw $t1, 20($fp) - #Executing GetAttr - lw $t1, -4($fp) - lw $t2, 8($t1) - sw $t2, 24($fp) - #Executing Div Operation - lw $t2, 20($fp) - lw $t4, 24($fp) - div $t2, $t4 - mflo $t2 - sw $t2, 0($fp) - #Executing Assign - lw $t5, -4($fp) - sw $t5, 28($fp) - #Executing typeof - lw $t5, 28($fp) - lw $t5, 0($t5) - sw $t5, 32($fp) - #Executing GetAttr - lw $t0, -4($fp) - lw $t4, 8($t0) - sw $t4, 40($fp) - #Executing GetAttr - lw $t1, -4($fp) - lw $t2, 4($t1) - sw $t2, 44($fp) - #Executing Star Operation - lw $t1, 40($fp) - lw $t9, 44($fp) - mult $t1, $t9 - mflo $t1 - sw $t1, 36($fp) - #Receiving Arg local_Main_main_internal_7 - lw $t4, 28($fp) - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Receiving Arg local_Main_main_internal_9 - lw $t5, 36($fp) - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Executing Dynamic Call - lw $t9, 32($fp) - lw $t1, 16($t9) - jalr $t1 - sw $a1, 0($fp) - addi $sp, $sp, -8 - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -48 - #Return jump - jalr $ra diff --git a/tests/code_gen/unary_nodes.mips b/tests/code_gen/unary_nodes.mips deleted file mode 100644 index d526b9076..000000000 --- a/tests/code_gen/unary_nodes.mips +++ /dev/null @@ -1,728 +0,0 @@ -.data - -Object : .word, Object_abort, Object_copy, Object_type_name -Object_cname : .asciiz, "Object" -IO : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int -IO_cname : .asciiz, "IO" -String : .word, Object_abort, Object_copy, Object_type_name, String_length, String_concat, String_substr -String_cname : .asciiz, "String" -Int : .word, Object_abort, Object_copy, Object_type_name -Int_cname : .asciiz, "Int" -Bool : .word, Object_abort, Object_copy, Object_type_name -Bool_cname : .asciiz, "Bool" -Main : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int, Main_main, Main_constructor -Main_cname : .asciiz, "Main" -void : .word, -1 -empty_string : .asciiz, "" -input_str_buffer : .space, 1024 -abort_signal : .asciiz, "Program execution aborted" -case_missmatch : .asciiz, "Execution of a case statement without a matching branch" -case_on_void : .asciiz, "Case on void" -dispatch_on_void : .asciiz, "Dispatch on void" -division_by_zero : .asciiz, "Division by zero" -substr_out_of_range : .asciiz, "Substring out of range" -heap_overflow : .asciiz, "Heap overflow" - -.text -.globl main - -length: - li $t0, 0 - length_loop: - lb $t2, 0($a0) - beq $zero, $t2, length_end - add $t0, $t0, 1 - add $a0, $a0, 1 - j length_loop - length_end: - move $a0 $t0 - j $ra -copy: - copy_loop: - beq $zero, $a0, copy_end - lb $t8, 0($t7) - sb $t8, 0($t6) - addi $t6, $t6, 1 - addi $t7, $t7, 1 - addi $a0, $a0, -1 - j copy_loop - copy_end: - j $ra -Object_abort: - move $t5 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 0 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing RuntimeError - #Printing Abort Message - la $a0, abort_signal - li $v0, 4 - syscall - #Aborting execution - li $v0, 10 - syscall -Object_copy: - move $t2 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t2, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Object_type_name: - move $t3 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -IO_out_string: - move $t9 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 0 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t9, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #PrintStringNode - lw $a0, -4($fp) - lw $a0, 8($a0) - li $v0, 4 - syscall - #Executing Return - lw $a1, -8($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, 0 - #Return jump - jalr $ra -IO_out_int: - move $t3 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 0 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #PrintIntNode - lw $a0, -4($fp) - li $v0, 1 - syscall - #Executing Return - lw $a1, -8($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, 0 - #Return jump - jalr $ra -IO_in_string: - move $t5 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #ReadStrNode - #Reading String to buffer - la $a0, input_str_buffer - li $a1, 1024 - li $v0, 8 - syscall - #Saving reference to read string - move $t7 $a0 - #Calculating str length - jal length - #Allocating char array for new string - li $v0, 9 - syscall - move $t6 $v0 - move $t3 $v0 - move $t5 $a0 - #Copying bytes from one char array to another - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t1, String - sw $t1, 0($v0) - #Storing length and reference to char array - sw $t5, 4($v0) - sw $t3, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -IO_in_int: - move $t0 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t0, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #ReadStrNode - #Reading String to buffer - la $a0, input_str_buffer - li $a1, 1024 - li $v0, 8 - syscall - #Saving reference to read string - move $t7 $a0 - #Calculating str length - jal length - #Allocating char array for new string - li $v0, 9 - syscall - move $t6 $v0 - move $t2 $v0 - move $t0 $a0 - #Copying bytes from one char array to another - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t3, String - sw $t3, 0($v0) - #Storing length and reference to char array - sw $t0, 4($v0) - sw $t2, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_length: - move $t1 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Length - lw $t4, -4($fp) - lw $t4, 4($t4) - sw $t4, 0($fp) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_concat: - move $t3 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Loading length - lw $s1, -8($fp) - lw $s1, 4($s1) - lw $s2, -4($fp) - lw $s2, 4($s2) - add $t2, $s1, $s2 - #Allocating new char array - move $a0 $t2 - addi $a0, $a0, 1 - li $v0, 9 - syscall - move $t6 $v0 - move $t4 $v0 - #Copying bytes from first string - lw $t7, -8($fp) - lw $t7, 8($t7) - move $a0 $s1 - jal copy - #Copying bytes from second string - lw $t7, -4($fp) - lw $t7, 8($t7) - move $a0 $s2 - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t0, String - sw $t0, 0($v0) - #Storing length and reference to char array - sw $t2, 4($v0) - sw $t4, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_substr: - move $t2 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t2, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Substring - lw $s0, -4($fp) - move $a0 $s0 - addi $a0, $a0, 1 - li $v0, 9 - syscall - move $t6 $v0 - #Loading reference to char array of source string - lw $t7, -12($fp) - lw $t7, 8($t7) - lw $s2, -8($fp) - add $t7, $t7, $s2 - move $s1 $t6 - #Copying bytes from one char array to another - move $a0 $s0 - jal copy - #Null-terminating the string - sb $zero, 0($t0) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t0, String - sw $t0, 0($v0) - #Storing length and reference to char array - lw $s0, -4($fp) - sw $s0, 4($v0) - sw $s1, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Object_constructor: - move $t2 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t2, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 4 - syscall - sw $v0, 0($fp) - la $t5, Object - sw $t5, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -IO_constructor: - move $t3 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 4 - syscall - sw $v0, 0($fp) - la $t9, IO - sw $t9, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Int_constructor: - move $t3 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 8 - syscall - sw $v0, 0($fp) - la $t2, Int - sw $t2, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Bool_constructor: - move $t1 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 8 - syscall - sw $v0, 0($fp) - la $t9, Bool - sw $t9, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_constructor: - move $t4 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t2, String - sw $t2, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -main: - move $t2 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 8 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t2, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Static Call - jal Main_constructor - sw $a1, 0($fp) - addi $sp, $sp, 0 - #Receiving Arg local_main_internal_0 - lw $t9, 0($fp) - sw $t9, 0($sp) - addi $sp, $sp, 4 - #Executing Static Call - jal Main_main - sw $a1, 4($fp) - addi $sp, $sp, -4 - li $v0, 10 - syscall -Main_constructor: - move $t3 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 16 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 16 - syscall - sw $v0, 0($fp) - la $t5, Main - sw $t5, 0($v0) - #Executing DefaultValue - li $t2, 0 - sw $t2, 4($fp) - #Executing SetAttr - lw $t5, 0($fp) - lw $t1, 4($fp) - sw $t1, 4($t5) - #Executing DefaultValue - li $t9, 0 - sw $t9, 8($fp) - #Executing SetAttr - lw $t9, 0($fp) - lw $t2, 8($fp) - sw $t2, 8($t9) - #Executing DefaultValue - li $t5, 0 - sw $t5, 12($fp) - #Executing SetAttr - lw $t5, 0($fp) - lw $t9, 12($fp) - sw $t9, 12($t5) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -16 - #Return jump - jalr $ra -Main_main: - move $t1 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 20 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Assign - lw $t2, -4($fp) - sw $t2, 4($fp) - #Executing typeof - lw $t9, 4($fp) - lw $t9, 0($t9) - sw $t9, 8($fp) - #Executing GetAttr - lw $t1, -4($fp) - lw $t3, 4($t1) - sw $t3, 16($fp) - #Executing Int Complement - lw $t2, 16($fp) - not $t4, $t2 - addi $t4, $t4, 1 - sw $t4, 12($fp) - #Receiving Arg local_Main_main_internal_1 - lw $t1, 4($fp) - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Receiving Arg local_Main_main_internal_3 - lw $t9, 12($fp) - sw $t9, 0($sp) - addi $sp, $sp, 4 - #Executing Dynamic Call - lw $t2, 8($fp) - lw $t5, 16($t2) - jalr $t5 - sw $a1, 0($fp) - addi $sp, $sp, -8 - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -20 - #Return jump - jalr $ra diff --git a/tests/code_gen/while.mips b/tests/code_gen/while.mips deleted file mode 100644 index 8325b1480..000000000 --- a/tests/code_gen/while.mips +++ /dev/null @@ -1,804 +0,0 @@ -.data - -Object : .word, Object_abort, Object_copy, Object_type_name -Object_cname : .asciiz, "Object" -IO : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int -IO_cname : .asciiz, "IO" -String : .word, Object_abort, Object_copy, Object_type_name, String_length, String_concat, String_substr -String_cname : .asciiz, "String" -Int : .word, Object_abort, Object_copy, Object_type_name -Int_cname : .asciiz, "Int" -Bool : .word, Object_abort, Object_copy, Object_type_name -Bool_cname : .asciiz, "Bool" -Main : .word, Object_abort, Object_copy, Object_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int, Main_main, Main_constructor -Main_cname : .asciiz, "Main" -void : .word, -1 -empty_string : .asciiz, "" -input_str_buffer : .space, 1024 -abort_signal : .asciiz, "Program execution aborted" -case_missmatch : .asciiz, "Execution of a case statement without a matching branch" -case_on_void : .asciiz, "Case on void" -dispatch_on_void : .asciiz, "Dispatch on void" -division_by_zero : .asciiz, "Division by zero" -substr_out_of_range : .asciiz, "Substring out of range" -heap_overflow : .asciiz, "Heap overflow" -string_1 : .asciiz, "iteration \n" - -.text -.globl main - -length: - li $t1, 0 - length_loop: - lb $t5, 0($a0) - beq $zero, $t5, length_end - add $t1, $t1, 1 - add $a0, $a0, 1 - j length_loop - length_end: - move $a0 $t1 - j $ra -copy: - copy_loop: - beq $zero, $a0, copy_end - lb $t8, 0($t7) - sb $t8, 0($t6) - addi $t6, $t6, 1 - addi $t7, $t7, 1 - addi $a0, $a0, -1 - j copy_loop - copy_end: - j $ra -Object_abort: - move $t3 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 0 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing RuntimeError - #Printing Abort Message - la $a0, abort_signal - li $v0, 4 - syscall - #Aborting execution - li $v0, 10 - syscall -Object_copy: - move $t4 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Object_type_name: - move $t9 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t9, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -IO_out_string: - move $t4 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 0 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #PrintStringNode - lw $a0, -4($fp) - lw $a0, 8($a0) - li $v0, 4 - syscall - #Executing Return - lw $a1, -8($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, 0 - #Return jump - jalr $ra -IO_out_int: - move $t4 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 0 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #PrintIntNode - lw $a0, -4($fp) - li $v0, 1 - syscall - #Executing Return - lw $a1, -8($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, 0 - #Return jump - jalr $ra -IO_in_string: - move $t5 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #ReadStrNode - #Reading String to buffer - la $a0, input_str_buffer - li $a1, 1024 - li $v0, 8 - syscall - #Saving reference to read string - move $t7 $a0 - #Calculating str length - jal length - #Allocating char array for new string - li $v0, 9 - syscall - move $t6 $v0 - move $t4 $v0 - move $t3 $a0 - #Copying bytes from one char array to another - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t2, String - sw $t2, 0($v0) - #Storing length and reference to char array - sw $t3, 4($v0) - sw $t4, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -IO_in_int: - move $t2 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t2, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #ReadStrNode - #Reading String to buffer - la $a0, input_str_buffer - li $a1, 1024 - li $v0, 8 - syscall - #Saving reference to read string - move $t7 $a0 - #Calculating str length - jal length - #Allocating char array for new string - li $v0, 9 - syscall - move $t6 $v0 - move $t4 $v0 - move $t9 $a0 - #Copying bytes from one char array to another - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t5, String - sw $t5, 0($v0) - #Storing length and reference to char array - sw $t9, 4($v0) - sw $t4, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_length: - move $t9 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t9, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Length - lw $t1, -4($fp) - lw $t1, 4($t1) - sw $t1, 0($fp) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_concat: - move $t2 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t2, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Loading length - lw $s1, -8($fp) - lw $s1, 4($s1) - lw $s2, -4($fp) - lw $s2, 4($s2) - add $t3, $s1, $s2 - #Allocating new char array - move $a0 $t3 - addi $a0, $a0, 1 - li $v0, 9 - syscall - move $t6 $v0 - move $t5 $v0 - #Copying bytes from first string - lw $t7, -8($fp) - lw $t7, 8($t7) - move $a0 $s1 - jal copy - #Copying bytes from second string - lw $t7, -4($fp) - lw $t7, 8($t7) - move $a0 $s2 - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t2, String - sw $t2, 0($v0) - #Storing length and reference to char array - sw $t3, 4($v0) - sw $t5, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_substr: - move $t4 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Substring - lw $s0, -4($fp) - move $a0 $s0 - addi $a0, $a0, 1 - li $v0, 9 - syscall - move $t6 $v0 - #Loading reference to char array of source string - lw $t7, -12($fp) - lw $t7, 8($t7) - lw $s2, -8($fp) - add $t7, $t7, $s2 - move $s1 $t6 - #Copying bytes from one char array to another - move $a0 $s0 - jal copy - #Null-terminating the string - sb $zero, 0($t0) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t5, String - sw $t5, 0($v0) - #Storing length and reference to char array - lw $s0, -4($fp) - sw $s0, 4($v0) - sw $s1, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Object_constructor: - move $t0 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t0, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 4 - syscall - sw $v0, 0($fp) - la $t4, Object - sw $t4, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -IO_constructor: - move $t0 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t0, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 4 - syscall - sw $v0, 0($fp) - la $t0, IO - sw $t0, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Int_constructor: - move $t0 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t0, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 8 - syscall - sw $v0, 0($fp) - la $t3, Int - sw $t3, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Bool_constructor: - move $t2 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t2, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 8 - syscall - sw $v0, 0($fp) - la $t1, Bool - sw $t1, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_constructor: - move $t2 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t2, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t3, String - sw $t3, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -main: - move $t2 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 8 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t2, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Static Call - jal Main_constructor - sw $a1, 0($fp) - addi $sp, $sp, 0 - #Receiving Arg local_main_internal_0 - lw $t3, 0($fp) - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing Static Call - jal Main_main - sw $a1, 4($fp) - addi $sp, $sp, -4 - li $v0, 10 - syscall -Main_constructor: - move $t2 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 20 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t2, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t3, Main - sw $t3, 0($v0) - #Executing DefaultValue - li $t1, 0 - sw $t1, 4($fp) - #Executing SetAttr - lw $t4, 0($fp) - lw $t1, 4($fp) - sw $t1, 4($t4) - #Executing DefaultValue - li $t1, 0 - sw $t1, 8($fp) - #Executing SetAttr - lw $t3, 0($fp) - lw $t1, 8($fp) - sw $t1, 8($t3) - #Executing Assign - li $t2, 0 - sw $t2, 12($fp) - #Executing SetAttr - lw $t9, 0($fp) - lw $t1, 12($fp) - sw $t1, 4($t9) - #Executing Assign - li $t4, 3 - sw $t4, 16($fp) - #Executing SetAttr - lw $t4, 0($fp) - lw $t2, 16($fp) - sw $t2, 8($t4) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -20 - #Return jump - jalr $ra -Main_main: - move $t2 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 52 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t2, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - WHILE_1: - #Executing GetAttr - lw $t4, -4($fp) - lw $t1, 4($t4) - sw $t1, 8($fp) - #Executing GetAttr - lw $t9, -4($fp) - lw $t0, 8($t9) - sw $t0, 12($fp) - #Executing Less Operation - lw $t9, 8($fp) - lw $t0, 12($fp) - slt $t3, $t9, $t0 - sw $t3, 4($fp) - lw $t1, 4($fp) - bnez $t1, BODY_2 - #Executing Goto - j END_WHILE_3 - BODY_2: - #Executing Assign - lw $t0, -4($fp) - sw $t0, 20($fp) - #Executing typeof - lw $t9, 20($fp) - lw $t9, 0($t9) - sw $t9, 24($fp) - #Executing GetAttr - lw $t2, -4($fp) - lw $t1, 4($t2) - sw $t1, 28($fp) - #Receiving Arg local_Main_main_internal_5 - lw $t9, 20($fp) - sw $t9, 0($sp) - addi $sp, $sp, 4 - #Receiving Arg local_Main_main_internal_7 - lw $t4, 28($fp) - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing Dynamic Call - lw $t1, 24($fp) - lw $t9, 16($t1) - jalr $t9 - sw $a1, 16($fp) - addi $sp, $sp, -8 - #Executing Assign - lw $t3, -4($fp) - sw $t3, 32($fp) - #Executing typeof - lw $t0, 32($fp) - lw $t0, 0($t0) - sw $t0, 36($fp) - #Executing Load - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 40($fp) - la $t1, String - sw $t1, 0($v0) - li $t1, 12 - sw $t1, 4($v0) - la $t1, string_1 - sw $t1, 8($v0) - #Receiving Arg local_Main_main_internal_8 - lw $t1, 32($fp) - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Receiving Arg local_Main_main_internal_10 - lw $t2, 40($fp) - sw $t2, 0($sp) - addi $sp, $sp, 4 - #Executing Dynamic Call - lw $t4, 36($fp) - lw $t9, 12($t4) - jalr $t9 - sw $a1, 16($fp) - addi $sp, $sp, -8 - #Executing GetAttr - lw $t1, -4($fp) - lw $t9, 4($t1) - sw $t9, 44($fp) - #Executing Assign - li $t2, 1 - sw $t2, 48($fp) - #Executing Plus Operation - lw $t1, 44($fp) - lw $t4, 48($fp) - add $t0, $t1, $t4 - sw $t0, 16($fp) - #Executing SetAttr - lw $t3, -4($fp) - lw $t9, 16($fp) - sw $t9, 4($t3) - #Executing Goto - j WHILE_1 - END_WHILE_3: - #Executing DefaultValue - la $t4, void - sw $t4, 0($fp) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -52 - #Return jump - jalr $ra From bd892e88d7cf99cdc51c5e9ef5cd6987e9ecd824 Mon Sep 17 00:00:00 2001 From: gabriela Date: Wed, 9 Mar 2022 12:34:13 -0500 Subject: [PATCH 137/162] Update report. --- doc/Report.md | 74 +++++++++++++++++++++++--------------------- img/classdec.png | Bin 0 -> 30924 bytes src/cool_grammar.py | 11 +++---- 3 files changed, 44 insertions(+), 41 deletions(-) create mode 100644 img/classdec.png diff --git a/doc/Report.md b/doc/Report.md index 3b862bcdd..de7cc0b80 100644 --- a/doc/Report.md +++ b/doc/Report.md @@ -3,16 +3,16 @@ Cool(Classroom Object-Oriented Language) es un lenguaje de programación orientado a objetos que, aunque pequeño, tiene muchas caracterı́sticas relevantes de lenguajes modernos. Su orientación a objetos, su tipado dinámico y el resto de sus features lo hacen muy atractivo e ideal para un primer acercamiento al mundo de los Compiladores. -En el presente trabajo se muestra una implementación de un Compilador funcional para Cool en el lenguaje de programación python: *El Compi*. +En el presente trabajo se muestra una implementación de un Compilador funcional para Cool en el lenguaje de programación python; los llamamos: *El Compi*. En las próximas secciones se explican en detalle cada una de las fases en las que se divide el trabajo del mismo, como fue abordada cada una, las instrucciones para su uso y algunos otros detalles importantes a resaltar. -## Instrucciones para la ejecución +## Requerimientos e instrucciones para la ejecución Para utilizar *El Compi* y ejecutar un programa en el lenguaje cool se han de seguir los siguientes pasos: -1- Primero se debe verificar que se cuente con todas las dependencias necesarias. Para una rápida instalación de estas se puede ejecutar el comando: +1- Primero se debe verificar que se cuente con todas las dependencias necesarias. Para una rápida instalación de estas se puede correr el comando: ```bash $ pip install -r requirements.txt @@ -25,13 +25,14 @@ $ ./coolc.sh ``` en una consola centrada en el directorio *src* que se encuentra en la raiz del proyecto. Aquí sería un archivo escrito en cool. -3- El *output* esperado es un archivo con el mismo nombre pero en .mips, el cual debe correrse con el correspondiente intérprete: +3- El *output* esperado (en caso de no haberse detectado ningún error) es un archivo con el mismo nombre pero en .mips, el cual debe correrse con el correspondiente intérprete: ```bash $ spim -file ``` -que finalmente nos mostrará el resultado correspondiente al programa de entrada (spim se encuentra entre los requirements especificados). +que finalmente nos mostrará el resultado generado por el programa de entrada (spim se encuentra entre los requirements especificados). +Si se encuentran errores en el código de Cool proporcionado, el compilador los listará en consola, proporcionando detalles sobre su localización y tipo. Para más información sobre los errores de Cool manejados remitirse al README.md de la carpeta *src*. ## Arquitectura del compilador: @@ -39,9 +40,9 @@ que finalmente nos mostrará el resultado correspondiente al programa de entrada -Análisis sintáctico (Análisis léxico y parsing) --Análisis semántico +-Análisis semántico (Recolección, creación y chequeo de tipos) --Generación de código (Generación de un lenguaje intermedio y traducción a mips) +-Generación de código (Traducción a un lenguaje intermedio y generación del correspondiente código mips) Más adelante se analizan con más profundidad cada una. @@ -49,37 +50,34 @@ El código fuente del proyecto se encuentra en la carpeta *src*. En esta se hall **FOTO de los archivos del proyecto** -Si lo miramos como módulos, podemos decir que el módulo de lexe... en *code_gen* encontramos todo lo referente al proceso de generación de código... +Si lo miramos como módulos, podemos decir que el módulo de lexe... en *code_gen* encontramos todo lo referente al proceso de generación de código... en tools todo los utils para... **COMPLETAR** -Analicemos ahora los prometidos detalles de implementacion y diseño del compilador tan anunciados. +Analicemos ahora los prometidos detalles de implementacion y diseño tan anunciados. ## Gramática -El primer paso para acercarnos al lenguaje objeto de análisis fue definir una gramática adecuada. Siguiendo lo referido por el manual de Cool (el cual se encuentra adjunto en la carpeta *doc*, con el resto de la documentación), se utilizó una gramática que respetara la precedencia necesaria de los operadores y la estructura requerida. En el archivo cool grammar.py puede observarse como fue modelada la misma. +El primer paso para acercarnos al lenguaje objeto de análisis fue definir una gramática adecuada. Siguiendo lo referido por el manual de Cool (el cual se encuentra adjunto en la carpeta *doc*, con el resto de la documentación), se diseñó una gramática que respetara la precedencia necesaria de los operadores y la estructura requerida. En el archivo cool grammar.py puede observarse como fue modelada la misma. Como ahí se puede apreciar, un programa de Cool consiste en una serie de definiciones de clases. Cada -clase a su vez posee un conjunto de atributos y de fun- -ciones. Las expresiones que pueden formar parte de +clase a su vez posee un conjunto de atributos y de funciones. Las expresiones que pueden formar parte de dichas funciones son el corazón del lenguaje. -En la imagen *1* se pueden apreciar varios niveles intermedios de la gramática que precisamente definen diferentes tipos de expresiones: +En la imagen *1* se pueden apreciar varios niveles intermedios de esta gramática, lo cuales, precisamente, definen diferentes tipos de expresiones: -1. , que representa las operaciones donde se -comparan elementos. +1. $$, que representa las operaciones de comparación entre elementos. -2. , que engloba a las operaciones de suma y +2. $$, que engloba a las operaciones de suma y resta. -3. , para la multiplicación y división. +3. $$, para la multiplicación y división. -4. , como representación de los operadores -unarios isvoid, opuesto y new. +4. $$, como representación de los operadores +unarios isvoid y opuesto. -5. para las expresiones entre paréntsis, -los block y las llamadas a funciones. +5. $$ para las condicionales (*if-then-else*, *while* y *case*), la instanciación con *new*, las expresiones entre paréntsis, los block, los dispatch. -6. como el nivel más básico, donde se ex- +6. $$ como el nivel más básico, donde se ex- cuentran los números, ids, las expresiones boolea- nas y los strings. @@ -88,14 +86,15 @@ nas y los strings. ## Análisis sintáctico ### Tokenizer -Para tokenizar la entrada se utilizó una herramienta bastante útil y práctica: PLY (https://www.dabeaz.com/ply/ply.html), el cual consiste en una implementación en python de las herramientas de parsing les y yaxx. Mediante el módulo lex que esta provee, es posible acceder a un analizador léxico ya implementado. +Para tokenizar la entrada se utilizó una herramienta bastante útil y práctica: PLY (https://www.dabeaz.com/ply/ply.html), la cual consiste en una implementación en python de las herramientas de parsing *Lex* y *Yacc*. Mediante el módulo lex que esta provee, es posible acceder a un analizador léxico ya implementado. -Para utilizar esta herramienta se definieron una serie de reglas que orientaran al tokenizador como trabajar en las cadenas de entrada. En el archivo -token rules se pueden observar dichas reglas, las cuáles consisten fundamentalmente en definiciones de los patrones que sigue cada token deseado, con la ayuda de expresiones regulares. En este sentido, se +Para utilizarlo, se definieron una serie de reglas que orientaran al tokenizador como trabajar en las cadenas de entrada. En el archivo +token rules se pueden observar las reglas utilizadas, las cuáles consisten fundamentalmente en definiciones de los patrones que sigue cada token deseado, con la ayuda de expresiones regulares. En este sentido, se trabajó fundamentalmente con el módulo re de python, el cual permite definir dichas expresiones. -HABLAR DE COMO SE DEFINEN LSO COMENTARIOS -PONER UNA FOTO DE ALGUNA REGLA +Nótese que los *keywords* no requieren de una regla específica para su detección, listarlos es suficiente para que *lex* los tenga en cuenta en su análisis, pues son frases que se toman *as is*. Sin embargo, cabe destacar que para ser capaces de detectarlos independientemente del uso o no de mayúsculas y no confundirlos con types o identificadores, en las reglas de estos dos últimos se verifica la posibilidad de que la frase matcheada perteneza a la familia de palabras claves del lenguaje y se actúa acorde. + +Para la especificación de comentarios de más de una línea se arpvechó la facilidad de *lex* de definir estados alternativos al *INITIAL* o por defecto. Así fue posible asegurar que los símbolos de inicio - (* - y cierre -*)- estuvieran balanceados con reglas específicas al estado *Comments*. Es importante destacar que los tokens de *lex* registran la posición que ocupan en el texto de entrada, considerando el mismo como una array de caracterres. Esto, con la ayuda de una regla para la detección de saltos de línea nos permite tener bien identificada la fila y la columna de un caracter en el script inicial, lo cual es sumamente importante en futuras fases del compilador para ubicar y reportar los errores detectados. @@ -103,24 +102,29 @@ Es importante destacar que los tokens de *lex* registran la posición que ocupan En cambio, para el parser, no fue la variante de ycc la que se decidió utilizar. En este caso, nos mantuvimos fieles a la implementación efectuada por el equipo en proyectos pasados, la cual se puede apreciar en el archivo *shift_reduce* parsers. Este cuenta con las modificaciones pertinentes para adaptarse a los nuevos requerimientos, por ejemplo, para la detección de fila y columna se realiza ahora el parseo sobre tokens del lenguaje, en lugar de sobre simples lexemas. -Con el uso del parser LR1 que aquí se provee y la gramática atributada de *cool_grammar* es posible parsear un texto en cool y obtener un árbol correspondiente a una derivación de extrema derecha. +Con el uso del parser LR1 que aquí se provee y la gramática atributada de *cool_grammar.py*, es posible parsear un texto en cool y obtener un árbol correspondiente a una derivación de extrema derecha. + +La construcción de este árbol o ast (*abstract syntax tree*) es la base del resto del análisis que se efectúa por el compilador. A lo largo de la ejecución del proyecto se utilizan variaciones de estos árboles, pero este primero que se menciona está formado por los nodos que se encuentran en el archivo *ast_nodes.py* y no es más que una representación bastante general de la jeraquía que sigue el programa parseado. -La construcción de este árbol o ast ($abstract syntax tree$) es la base del resto del análisis que se efectúa por el compilador. A lo largo de la ejecución del proyecto se utilizan una serie de estos árboles, pero primero que se menciona está formado por los nodos que se encuentran en el archivo $ast_nodes.py$. +Cada nodo posee los elementos que lo caracterizan, por ejemplo el *ClassDeclarationNode* cuenta con tokens como: el *id* que representa el nombre de la clase, un *parent* o tipo del que hereda (que puede ser *None* en caso de no existir), y la lista de *features*, o sea de definiciones de los métodos y atributos que posee. Además se añade un *token* que permita ubicar el inicio de la declaración en el código de entrada. + +![](../img/classdec.png) ## Chequeo semántico: -Una vez se tenga un ast con la sintaxis adecuada en mano, la fase siguiente consiste en verificar que el programa en cuestión esté correcto semánticamente. +Una vez cosntruido el ast con la sintaxis adecuada, la fase siguiente consiste en verificar que el programa en cuestión esté correcto semánticamente. Con este fin se realizan 3 recorridos sobre el árbol, apoyándonos en el patrón visitor propuesto: -HABLAR DEL CONTEXTO Y DE COMO SE DEFINE -COMO SE REFGISTRA UNA CLASE CON SUS TIPOS BLABLABLA --TypeCollector: Cuyo objetivo es registrar los tipos definidos por el programa. Aquí sólo se lanza un error cuando se intenta redefinir un tipo, o sea cuando aparece su definición más de una vez en el script propuesto. +-TypeCollector: Cuyo objetivo es registrar los tipos definidos por el programa. Aquí sólo se lanza un error cuando se intenta redefinir un tipo, o sea cuando aparece su definición más de una vez en el script de entrada. + +-TypeBuilder: Recorrido que busca asignar los métodos y definiciones de atributos a sus clases correspondientes, y detectar errores relacionados con referencias a tipos inexistentes. En este caso es necesario notar que, como Cool permite la herencia, se debe asegurar en este recorrido que no existan ciclos entre las definiciones de clases. Además, para poder garantizar que no se redefinan métodos ni atributos, se asegura que en el momento de definición de un hijo ya se haya visitado al padre, de modo que se tenga constancia de los valores heredados para el análisis. En esta pasada se verifica también que se cumplan los requerimientos de la definición de una clase *Main* con su método *main* que no reciba parámetros, la cual funciona como punto de inicio de cualquier programa en Cool. --TypeBuilder: Recorrido que busca asignar los métodos y definiciones de atributos a sus clases correspondientes, y detectar errores relacionados con referencias a tipos inexistentes. En este caso es necesario notar que, como Cool permite la herencia, se debe asegurar en este recorrido que no existan ciclos entre las definiciones de clases. Además, para poder garantizar que no se redefinan métodos ni atributos, se asegura que en el momento de definición de un hijo ya se haya visitado al padre, de modo que se tenga constancia de los valores heredados para el análisis. +-TypeChecker: En este último recorrido sí se visitan la totalidad de nodos del ast creado, no sólo los correspondientes a definiciones de clases, métodos o atributos como en las pasadas anteriores. A medida que se recorre el árbol (con el contexto ya populado con las tipos correspondientes al programa y sus propiedades), se va chequeando que se haga un uso correcto de tipos a lo largo de las expresiones utilizadas, que no se referencien variables o atributos inexistentes o fuera de scope, etc, reportando siempre los errores encontrados. --TypeChecker: En este último recorrido sí se visitan la totalidad de nodos del ast creado, no sólo los correspondientes a definiciones de clases, métodos o atributos como en las pasadas anteriores. A medida que se recorre el árbol, con el contexto ya populado con las tipos correspondientes al programa y sus propiedades, se va chequeando que se haga un uso correcto de tipos a lo largo de las expresiones utilizadas, que no se referencien variables o atributos inexistentes o fuera de scope, etc, reportando siempre los errores encontrados. +Cada tipo con sus atributos y métodos se registra a partir de la clase *Context*. A su vez, para poder ubicar cada definición de variable en un contexto específico se utiliza la clase *Scope* que nos permite ir registrando scopes anidados. +Si tras terminar estos recorridos no se encuentran errores es posible afirmar que el código .cl de entrada describe un programa correcto de Cool, o al menos hasta que un runtime error indique lo contrario ; ). Para poder obtener la salida esperada de este, es necesario entonces pasar a la última fase del proceso de compilación. ## Generación de código: ### Paso de Cool a CIL: diff --git a/img/classdec.png b/img/classdec.png new file mode 100644 index 0000000000000000000000000000000000000000..657c513735b5cf41a323d8de7fbecea504ab0e5e GIT binary patch literal 30924 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Ë)kb=E03Pi-O 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 literal 0 HcmV?d00001 diff --git a/src/cool_grammar.py b/src/cool_grammar.py index d375edbc6..1bdc2a8c1 100644 --- a/src/cool_grammar.py +++ b/src/cool_grammar.py @@ -75,7 +75,7 @@ def define_cool_grammar(print_grammar=False): ) def_class %= ( classx + type_id + inherits + type_id + ocur + feature_list + ccur + semi, - lambda h, s: ClassDeclarationNode(s[2], s[6], s[1], s[4]), # aqui hay que buscar otra alternativa a simplemente pasar el lexema pues a la hora de dar errores estaria bien decir que el tipo que se refencia noe sta definido + lambda h, s: ClassDeclarationNode(s[2], s[6], s[1], s[4]), ) feature_list %= def_attr + semi + feature_list, lambda h, s: [s[1]] + s[3] @@ -83,12 +83,12 @@ def define_cool_grammar(print_grammar=False): feature_list %= G.Epsilon, lambda h, s: [] def_attr %= ( - idx + colon + type_id + larrow + expr, # el token podria ser el del id en estos 3 + idx + colon + type_id + larrow + expr, lambda h, s: AttrDeclarationNode(s[1], s[3], s[5], s[4]), ) def_attr %= idx + colon + type_id, lambda h, s: AttrDeclarationNode(s[1], s[3], token = s[2]) - def_func %= (#verificar el token que se manda + def_func %= ( idx + opar + param_list + cpar + colon + type_id + ocur + expr + ccur, lambda h, s: FuncDeclarationNode(s[1], s[3], s[6], s[8], s[2]), ) @@ -99,7 +99,6 @@ def define_cool_grammar(print_grammar=False): param_list_rest %= comma + param + param_list_rest, lambda h, s: [s[2]] + s[3] param_list_rest %= comma + param, lambda h, s: [s[2]] - #aqui podria ser conveniente annadir un token para registrar la pos ante un error param %= idx + colon + type_id, lambda h, s: (s[1], s[3]) expr %= idx + larrow + expr, lambda h, s: AssignNode(s[1], s[3], s[2]) @@ -119,7 +118,7 @@ def define_cool_grammar(print_grammar=False): ) identifier_init %= idx + colon + type_id, lambda h, s: VarDeclarationNode(s[1], s[3]) - comp %= comp + less + arith, lambda h, s: LessNode(s[1], s[3], s[2]) + comp %= comp + less + arith, lambda h, s: LessNode(s[1], s[3], s[2]) # this expression do not associate, so call comp instead of arith comp %= comp + less + notx + arith, lambda h, s: LessNode(s[1], NotNode(s[4], s[3]) , s[2]) comp %= comp + equal + arith, lambda h, s: EqualNode(s[1], s[3], s[2]) comp %= comp + equal + notx + arith, lambda h, s: EqualNode(s[1], NotNode(s[4], s[3]) , s[2]) @@ -148,7 +147,7 @@ def define_cool_grammar(print_grammar=False): element %= new + type_id, lambda h, s: InstantiateNode(s[2], s[1]) element %= opar + expr + cpar, lambda h, s: s[2] element %= ocur + block + ccur, lambda h, s: BlockNode(s[2], s[1]) - element %= (element + dot + func_call, lambda h, s: CallNode(*s[3], obj=s[1], token = s[2]))#arreglar + element %= (element + dot + func_call, lambda h, s: CallNode(*s[3], obj=s[1], token = s[2])) element %= ( element + at + type_id + dot + func_call, lambda h, s: CallNode(*s[5], obj=s[1], at_type=s[3], token = s[2]), From d87a2fb341676548e35632efa387c43d12176734 Mon Sep 17 00:00:00 2001 From: gabriela Date: Wed, 9 Mar 2022 12:43:39 -0500 Subject: [PATCH 138/162] Add grammar pic to report. --- doc/Report.md | 5 ++++- img/grammar.png | Bin 0 -> 28220 bytes 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 img/grammar.png diff --git a/doc/Report.md b/doc/Report.md index de7cc0b80..5216d719e 100644 --- a/doc/Report.md +++ b/doc/Report.md @@ -81,7 +81,10 @@ unarios isvoid y opuesto. cuentran los números, ids, las expresiones boolea- nas y los strings. -**IMAGEN** Figura 1: Fragmento de la gramática de Cool. +![](../img/grammar.png) + +Figura 1: Fragmento de la gramática de Cool. + ## Análisis sintáctico diff --git a/img/grammar.png b/img/grammar.png new file mode 100644 index 0000000000000000000000000000000000000000..f0e19e68c9b2b9268c0f272234acec7a7387522c GIT binary patch literal 28220 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 Date: Wed, 9 Mar 2022 15:00:10 -0500 Subject: [PATCH 139/162] Edit report's images description. --- doc/Report.md | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/doc/Report.md b/doc/Report.md index 5216d719e..829919c93 100644 --- a/doc/Report.md +++ b/doc/Report.md @@ -65,31 +65,29 @@ clase a su vez posee un conjunto de atributos y de funciones. Las expresiones qu dichas funciones son el corazón del lenguaje. En la imagen *1* se pueden apreciar varios niveles intermedios de esta gramática, lo cuales, precisamente, definen diferentes tipos de expresiones: -1. $$, que representa las operaciones de comparación entre elementos. +1. **< comp >** , que representa las operaciones de comparación entre elementos. -2. $$, que engloba a las operaciones de suma y +2. **< arith >** , que engloba a las operaciones de suma y resta. -3. $$, para la multiplicación y división. +3. **< term >** , para la multiplicación y división. -4. $$, como representación de los operadores +4. **< factor >** , como representación de los operadores unarios isvoid y opuesto. -5. $$ para las condicionales (*if-then-else*, *while* y *case*), la instanciación con *new*, las expresiones entre paréntsis, los block, los dispatch. +5. **< element >** para las condicionales (*if-then-else*, *while* y *case*), la instanciación con *new*, las expresiones entre paréntsis, los block, los dispatch. -6. $$ como el nivel más básico, donde se ex- +6. **< atom >** como el nivel más básico, donde se ex- cuentran los números, ids, las expresiones boolea- nas y los strings. -![](../img/grammar.png) - -Figura 1: Fragmento de la gramática de Cool. +![Figura 1.!](../img/grammar.png "Fragmento de la gramática de Cool.") ## Análisis sintáctico ### Tokenizer -Para tokenizar la entrada se utilizó una herramienta bastante útil y práctica: PLY (https://www.dabeaz.com/ply/ply.html), la cual consiste en una implementación en python de las herramientas de parsing *Lex* y *Yacc*. Mediante el módulo lex que esta provee, es posible acceder a un analizador léxico ya implementado. +Para tokenizar la entrada se utilizó una herramienta bastante útil y práctica: [PLY](https://www.dabeaz.com/ply/ply.html), la cual consiste en una implementación en python de las herramientas de parsing *Lex* y *Yacc*. Mediante el módulo lex que esta provee, es posible acceder a un analizador léxico ya implementado. Para utilizarlo, se definieron una serie de reglas que orientaran al tokenizador como trabajar en las cadenas de entrada. En el archivo token rules se pueden observar las reglas utilizadas, las cuáles consisten fundamentalmente en definiciones de los patrones que sigue cada token deseado, con la ayuda de expresiones regulares. En este sentido, se @@ -111,7 +109,7 @@ La construcción de este árbol o ast (*abstract syntax tree*) es la base del re Cada nodo posee los elementos que lo caracterizan, por ejemplo el *ClassDeclarationNode* cuenta con tokens como: el *id* que representa el nombre de la clase, un *parent* o tipo del que hereda (que puede ser *None* en caso de no existir), y la lista de *features*, o sea de definiciones de los métodos y atributos que posee. Además se añade un *token* que permita ubicar el inicio de la declaración en el código de entrada. -![](../img/classdec.png) +![Ast Nodes.](../img/classdec.png "ClassDeclarationNode in cool ast") ## Chequeo semántico: From 2582ff678f6db1b4cf5b41792d5856ed9499c5a1 Mon Sep 17 00:00:00 2001 From: smartos99 Date: Wed, 9 Mar 2022 18:03:00 -0500 Subject: [PATCH 140/162] Add StrEqual --- src/cmp/cil.py | 6 ++++ src/code_gen/cil_builder.py | 9 ++++-- src/code_gen/mips_builder.py | 55 ++++++++++++++++++++++++++++++++++++ src/code_gen/mips_nodes.py | 17 +++++++++++ 4 files changed, 85 insertions(+), 2 deletions(-) diff --git a/src/cmp/cil.py b/src/cmp/cil.py index e9a8200a7..716c510f9 100644 --- a/src/cmp/cil.py +++ b/src/cmp/cil.py @@ -92,6 +92,8 @@ class LessEqualNode(ArithmeticNode): class EqualNode(ArithmeticNode): pass +class StrEqualNode(ArithmeticNode): + pass class UnaryNode(InstructionNode): def __init__(self, dest, expr): @@ -326,6 +328,10 @@ def visit(self, node): @visitor.when(EqualNode) def visit(self, node): return f"{node.dest} = {node.left} == {node.right}" + + @visitor.when(StrEqualNode) + def visit(self, node): + return f"{node.dest} = {node.left} == {node.right}" @visitor.when(NotNode) def visit(self, node): diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index 1789abc24..c70b6a222 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -1,3 +1,4 @@ + import cmp.nbpackage import cmp.visitor as visitor @@ -37,6 +38,7 @@ LessNode, LessEqualNode, EqualNode, + StrEqualNode, RuntimeErrorNode, CopyNode, TypeNameNode, @@ -800,8 +802,11 @@ def visit(self, node, return_var): right = self.define_internal_local() self.visit(node.right, right) - - self.register_instruction(EqualNode(return_var, left, right)) + + if node.left.static_type.name == "String": + self.register_instruction(StrEqualNode(return_var, left, right)) + else: + self.register_instruction(EqualNode(return_var, left, right)) # Unary operators @visitor.when(cool.InstantiateNode) # NewNode diff --git a/src/code_gen/mips_builder.py b/src/code_gen/mips_builder.py index 89a6dc281..a8d207b2a 100644 --- a/src/code_gen/mips_builder.py +++ b/src/code_gen/mips_builder.py @@ -3,6 +3,7 @@ # from operator import le # from tkinter.tix import Select # from soupsieve import select +from re import S import cmp.visitor as visitor import cmp.cil as cil import random @@ -229,9 +230,50 @@ def generate_copy(self): self.text.append(self.current_procedure) + def generate_str_cmp(self): + self.current_procedure = mips.ProcedureNode(STR_CMP) + + #comparing lengths + self.register_instruction(mips.CommentNode, "Comparing lengths") + self.register_instruction(mips.LoadWordNode, s0, LENGTH_ATTR_OFFSET, t6) #length offset + self.register_instruction(mips.LoadWordNode, s1, LENGTH_ATTR_OFFSET, t7) + self.register_instruction(mips.SetEq,a0,s0,s1) + + self.register_instruction(mips.BranchOnEqZero,a0,"end_loop") + + #comparing char by char + self.register_instruction(mips.CommentNode, "Comparing char by char") + self.register_instruction(mips.LoadWordNode, s0, CHARS_ATTR_OFFSET, t6) #char array pointer offset + self.register_instruction(mips.LoadWordNode, s1, CHARS_ATTR_OFFSET, t7) + + #char by char loop + self.register_instruction(mips.Label, "strcmp_loop") + self.register_instruction(mips.LoadInmediate,s2,0) + self.register_instruction(mips.LoadByteNode, s2, 0, s0) + + self.register_instruction(mips.LoadInmediate,s3,0) + self.register_instruction(mips.LoadByteNode, s3, 0, s1) + + self.register_instruction(mips.SetEq,a0,s2,s3) + self.register_instruction(mips.BranchOnEqZero,a0,"end_loop") + + + self.register_instruction(mips.BranchOnEqZero,s3, "end_loop") + self.register_instruction(mips.BranchOnEqZero,s2, "end_loop") + self.register_instruction(mips.AddiNode,s0,s0,1) + self.register_instruction(mips.AddiNode,s1,s1,1) + + self.register_instruction(mips.Jump, "strcmp_loop") + + self.register_instruction(mips.Label, "end_loop") + self.register_instruction(mips.JumpRegister, ra) + + self.text.append(self.current_procedure) + def generate_auxiliar_procedures(self): self.generate_str_length() self.generate_copy() + self.generate_str_cmp() @visitor.on("node") def visit(self, node=None): @@ -750,6 +792,19 @@ def visit(self,node): self.register_instruction(mips.StoreWordNode,r_dest,dest_off,fp) self.memo.clean() + + @visitor.when(cil.StrEqualNode) + def visit(self,node): + self.register_instruction(mips.CommentNode,"Executing StrEqual Operation") + left_off = self.get_offset(node.left) + right_off = self.get_offset(node.right) + self.register_instruction(mips.LoadWordNode, t6, left_off, fp) + self.register_instruction(mips.LoadWordNode, t7, right_off, fp) + + self.register_instruction(mips.JumpAndLink, STR_CMP) + dest_off = self.get_offset(node.dest) + self.register_instruction(mips.StoreWordNode, a0, dest_off, fp) + @visitor.when(cil.SubstringNode) def visit(self, node): diff --git a/src/code_gen/mips_nodes.py b/src/code_gen/mips_nodes.py index 20217547a..9c41da371 100644 --- a/src/code_gen/mips_nodes.py +++ b/src/code_gen/mips_nodes.py @@ -107,6 +107,15 @@ def __init__(self, dest, source): def __str__(self): return f"not {self.dest}, {self.source}" + + +class NegNode(InstructionNode): + def __init__(self, dest, source): + self.dest = dest + self.source = source + + def __str__(self): + return f"neg {self.dest}, {self.source}" class ArithAnfLogicNode(InstructionNode): def __init__(self, destination, left, right): @@ -205,6 +214,14 @@ def __init__(self,reg,label): def __str__(self): return f'bnez {self.reg}, {self.label}' + +class BranchOnEqZero(InstructionNode): + def __init__(self,reg,label): + self.reg = reg + self.label = label + + def __str__(self): + return f'beqz {self.reg}, {self.label}' From 6f51f012e35290e6bed4cd618e39301fb65dd411 Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Wed, 9 Mar 2022 18:11:15 -0500 Subject: [PATCH 141/162] feat: add case and let scope. --- src/cmp/cil.py | 10 +- src/cmp/semantic.py | 10 +- src/code_gen/cil_builder.py | 211 +++--- tests/code_gen.py | 12 +- tests/code_gen/case.cl | 29 + tests/code_gen/case_input.txt | 0 tests/code_gen/case_output.txt | 1 + tests/code_gen/is_void.mips | 1237 -------------------------------- 8 files changed, 171 insertions(+), 1339 deletions(-) create mode 100644 tests/code_gen/case.cl create mode 100644 tests/code_gen/case_input.txt create mode 100644 tests/code_gen/case_output.txt delete mode 100644 tests/code_gen/is_void.mips diff --git a/src/cmp/cil.py b/src/cmp/cil.py index e9a8200a7..d880361bb 100644 --- a/src/cmp/cil.py +++ b/src/cmp/cil.py @@ -207,13 +207,15 @@ class ReadStringNode(InstructionNode): def __init__(self, dest): self.dest = dest + class ReadIntNode(InstructionNode): def __init__(self, dest): self.dest = dest + class RuntimeErrorNode(InstructionNode): - def __init__(self, signal): - self.signal = signal + def __init__(self, msg): + self.msg = msg class CopyNode(InstructionNode): @@ -381,7 +383,7 @@ def visit(self, node): @visitor.when(RuntimeErrorNode) def visit(self, node): - return f"ABORT {node.signal}" + return f"ABORT {node.msg}" @visitor.when(CopyNode) def visit(self, node): @@ -402,7 +404,7 @@ def visit(self, node): @visitor.when(ReadIntNode) def visit(self, node): return f"{node.dest} = READ INT" - + @visitor.when(PrintStrNode) def visit(self, node): return f"PRINT STR{node.str_addr}" diff --git a/src/cmp/semantic.py b/src/cmp/semantic.py index 9300bde53..99118a03d 100644 --- a/src/cmp/semantic.py +++ b/src/cmp/semantic.py @@ -90,9 +90,7 @@ def define_attribute(self, name: str, typex): mssg = "an inherited class" else: mssg = self.name - raise SemanticError( - f'Attribute "{name}" is already defined in {mssg}.' - ) + raise SemanticError(f'Attribute "{name}" is already defined in {mssg}.') def get_method(self, name: str, non_rec=False, visited=None): if visited is None: @@ -267,12 +265,10 @@ def __copy__(self): class VariableInfo: - def __init__(self, name, vtype=None, is_attr=False, data=None): + def __init__(self, name, vtype=None, data=None): self.name = name self.type = vtype self.data = data - self.is_attr = is_attr - self.offset = None def __str__(self): return f"{self.name}: {self.type}" @@ -320,4 +316,4 @@ def __str__(self): output += "PARENT:" output += str(self.parent) output += "\n" - return output \ No newline at end of file + return output diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index 1789abc24..c8adad59a 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -116,11 +116,16 @@ def register_function(self, function_name): self.code.append(function_node) return function_node - def register_local(self, vinfo): - vinfo.name = f"local_{self.current_function.name}_{vinfo.name}_{len(self.current_function.localvars)}" - local_node = LocalNode(vinfo.name) + def get_local(self, name): + return f"local_{name}" + + def register_local(self, name=None): + local_name = ( + f"local_{name}" if name else f"local_{len(self.current_function.localvars)}" + ) + local_node = LocalNode(local_name) self.current_function.localvars.append(local_node) - return vinfo.name + return local_name def register_param(self, vinfo): vinfo.name = self.build_internal_vname(vinfo.name) @@ -128,19 +133,22 @@ def register_param(self, vinfo): self.params.append(arg_node) return vinfo + def get_param(self, name): + return f"param_{name}" + def build_internal_vname(self, vname): - vname = f"{self.internal_count}_{self.current_function.name}_{vname}" + vname = f"param_{vname}" self.internal_count += 1 return vname def define_internal_local(self): - vinfo = VariableInfo("internal", None) - return self.register_local(vinfo) + return self.register_local() def is_attribute(self, vname): return vname not in [var.name for var in self.current_function.localvars] and ( vname not in [param.name for param in self.current_function.params] ) + def add_builtin_constructors(self): builtin_types = ["Object", "IO", "Int", "Bool", "String"] for typex in builtin_types: @@ -223,7 +231,7 @@ def add_builtin_functions(self): io_type.methods = obj_functions + functions # String - self.attrs["String"] = {"length": (0, "Int"), "str_ref": (1,"String")} + self.attrs["String"] = {"length": (0, "Int"), "str_ref": (1, "String")} functions = [ self.cil_predef_method("copy", "String", self.object_copy), self.cil_predef_method("type_name", "String", self.object_type_name), @@ -239,18 +247,18 @@ def add_builtin_functions(self): string_type.methods = obj_functions + functions # Int - #self.attrs["Int"] = {"value": (0, "Int")} + # self.attrs["Int"] = {"value": (0, "Int")} int_type = TypeNode("Int") - int_type.attributes = [VariableInfo("value", is_attr=True).name] + int_type.attributes = [VariableInfo("value").name] int_type.methods = obj_functions + [ self.cil_predef_method("copy", "Int", self.object_copy), self.cil_predef_method("type_name", "Int", self.object_type_name), ] # Bool - #self.attrs["Bool"] = {"value": (0, "Int")} + # self.attrs["Bool"] = {"value": (0, "Int")} bool_type = TypeNode("Bool") - bool_type.attributes = [VariableInfo("value", is_attr=True).name] + bool_type.attributes = [VariableInfo("value").name] bool_type.methods = obj_functions + [ self.cil_predef_method("copy", "Bool", self.object_copy), self.cil_predef_method("type_name", "Bool", self.object_type_name), @@ -333,7 +341,11 @@ def object_copy(self): for attr in self.attrs[self.current_type.name].keys(): attr_copy_local = self.define_internal_local() - attr_name = self.to_attr_name(self.current_type.name, attr) if self.current_type.name not in ["Int", "String", "Bool"] else attr + attr_name = ( + self.to_attr_name(self.current_type.name, attr) + if self.current_type.name not in ["Int", "String", "Bool"] + else attr + ) self.register_instruction( GetAttribNode( attr_copy_local, @@ -365,10 +377,10 @@ def object_type_name(self): LoadNode( type_name, VariableInfo( - f"type_name_{self.current_type.name}", - None, - False, - f"{self.current_type.name}") + f"type_name_{self.current_type.name}", + None, + f"{self.current_type.name}", + ), ) ) self.register_instruction(AssignNode(solve, type_name)) @@ -541,7 +553,7 @@ def visit(self, node, return_var=None): # Add params self.current_function.params.append(ParamNode("self")) for pname, _ in node.params: - self.current_function.params.append(ParamNode(pname)) + self.register_param(VariableInfo(pname)) # Body value = self.define_internal_local() @@ -560,17 +572,24 @@ def visit(self, node, return_var=None): def visit(self, node, return_var): self.visit(node.expr, return_var) - if self.is_attribute(node.id): - self.register_instruction( - SetAttribNode( - "self", - self.to_attr_name(self.current_type.name, node.id), - return_var, - self.current_type.name, - ) + local_id = self.get_local(node.id) + if any(local_id == l.name for l in self.current_function.localvars): + self.register_instruction(AssignNode(local_id, return_var)) + return + + param_id = self.get_param(node.id) + if any(param_id == p.name for p in self.current_function.params): + self.register_instruction(AssignNode(param_id, return_var)) + return + + self.register_instruction( + SetAttribNode( + "self", + self.to_attr_name(self.current_type.name, node.id), + return_var, + self.current_type.name, ) - else: - self.register_instruction(AssignNode(node.id, return_var)) + ) @visitor.when(cool.CallNode) def visit(self, node, return_var): @@ -675,58 +694,69 @@ def visit(self, node, return_var): @visitor.when(cool.VarDeclarationNode) def visit(self, node, return_var=None): # Add LOCAL variable - local = LocalNode(node.id) - self.current_function.localvars.append(local) + idx = self.get_local(node.id) + if not any(idx == l.name for l in self.current_function.localvars): + self.register_local(node.id) # Add Assignment Node if node.expr: - self.visit(node.expr, local.name) + self.visit(node.expr, idx) else: - self.register_instruction(DefaultValueNode(local, node.type)) - - #@visitor.when(cool.CaseNode) - #def visit(self, node, return_var=None): - # def least_type(type_set): - # solve = self.context.get_type(type_set[0]) - # for item in type_set[1:]: - # typex = self.context.get_type(item) - # solve = find_least_type(solve, typex) - - # while solve is not None: - # if type_b.conforms_to(solve): - # return solve - # solve = solve.parent - - # return None - # return solve.name if not solve else "Object" - - # expr_value = self.define_internal_local() - # self.visit(node.expr, expr_value) - - # types = [case_item.type for case_item in node.case_items] - # types.append(node.expr.static_type.name) - - # _least_type = least_type(types) - # print("-----------Least TYpE:", _least_type) - # asserted_item = None - # for case_item in node.case_items: - # if case_item.type == _least_type: - # asserted_item = case_item - # break - - # if not asserted_item: - # self.register_instruction( - # StaticCallNode( - # self.to_function_name("abort", "Object"), - # return_var, - # ) - # ) - # return - - # self.localvars.append(LocalNode(asserted_item.id)) - # self.register_instruction(AssignNode(asserted_item.id, expr_value)) - - # self.visit(asserted_item.expr, return_var) + self.register_instruction(DefaultValueNode(idx, node.type)) + + @visitor.when(cool.CaseNode) + def visit(self, node, return_var=None): + def get_least_type(): + expr_type = node.expr.static_type + conformed_types = [] + for case_item in node.case_items: + case_type = self.context.get_type(case_item.type) + if expr_type.conforms_to(case_type): + conformed_types.append(case_type.name) + + least_type = None + solve = expr_type + while solve is not None: + if solve.name in conformed_types: + least_type = solve.name + break + solve = solve.parent + + return least_type + + expr_value = self.define_internal_local() + self.visit(node.expr, expr_value) + + least_type = get_least_type() + + asserted_item = None + for case_item in node.case_items: + if case_item.type == least_type: + asserted_item = case_item + break + + if not asserted_item: + self.data.append( + DataNode("runtime_error", "No branch can be selected for evaluation") + ) + error = self.define_internal_local() + self.register_instruction( + LoadNode( + error, + VariableInfo( + "runtime_error", + None, + "No branch can be selected for evaluation", + ), + ) + ) + self.register_instruction(RuntimeErrorNode(error)) + return + + new_local = self.register_local(asserted_item.id) + self.register_instruction(AssignNode(new_local, expr_value)) + + self.visit(asserted_item.expr, return_var) @visitor.when(cool.CaseItemNode) def visit(self, node, return_var=None): @@ -839,24 +869,31 @@ def visit(self, node, return_var): @visitor.when(cool.VariableNode) def visit(self, node, return_var): - if self.is_attribute(node.lex): - self.register_instruction( - GetAttribNode( - return_var, - "self", - self.to_attr_name(self.current_type.name, node.lex), - self.current_type.name, - ) + local_id = self.get_local(node.lex) + if any(local_id == l.name for l in self.current_function.localvars): + self.register_instruction(AssignNode(return_var, local_id)) + return + + param_id = self.get_param(node.lex) + if any(param_id == p.name for p in self.current_function.params): + self.register_instruction(AssignNode(return_var, param_id)) + return + + self.register_instruction( + GetAttribNode( + return_var, + "self", + self.to_attr_name(self.current_type.name, node.lex), + self.current_type.name, ) - else: - self.register_instruction(AssignNode(return_var, node.lex)) + ) @visitor.when(cool.StringNode) def visit(self, node, return_var): idx = self.generate_next_string_id() self.data.append(DataNode(idx, node.lex)) self.register_instruction( - LoadNode(return_var, VariableInfo(idx, None, False, node.lex)) + LoadNode(return_var, VariableInfo(idx, None, node.lex)) ) @visitor.when(cool.BooleanNode) diff --git a/tests/code_gen.py b/tests/code_gen.py index 1fb167ad3..3dfbd0c8b 100644 --- a/tests/code_gen.py +++ b/tests/code_gen.py @@ -3,8 +3,8 @@ from utils import compare_outputs -tests_dir = __file__.rpartition('/')[0] + '/code_gen/' -tests = [(file) for file in os.listdir(tests_dir) if file.endswith('.cl')] +tests_dir = __file__.rpartition("/")[0] + "/code_gen/" +tests = [(file) for file in os.listdir(tests_dir) if file.endswith(".cl")] # @pytest.mark.lexer # @pytest.mark.parser @@ -14,5 +14,9 @@ @pytest.mark.run(order=4) @pytest.mark.parametrize("cool_file", tests) def test_codegen(compiler_path, cool_file): - compare_outputs(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_input.txt',\ - tests_dir + cool_file[:-3] + '_output.txt') \ No newline at end of file + compare_outputs( + compiler_path, + tests_dir + cool_file, + tests_dir + cool_file[:-3] + "_input.txt", + tests_dir + cool_file[:-3] + "_output.txt", + ) diff --git a/tests/code_gen/case.cl b/tests/code_gen/case.cl new file mode 100644 index 000000000..b3d42c0ce --- /dev/null +++ b/tests/code_gen/case.cl @@ -0,0 +1,29 @@ + + + +class Main inherits IO{ + a : A <- new A; + b : B <- new B; + c : String <- "First sentence."; + d : String <- "Second sentence."; + g : String <- "Second sentence."; + main (): Object { + { + out_string( + (case c of + h:String => h <- "Modified."; + f:A => d; + esac).concat(d) + ); + } + }; +}; + +class A { + +}; + +class B inherits A{ + +}; + diff --git a/tests/code_gen/case_input.txt b/tests/code_gen/case_input.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/code_gen/case_output.txt b/tests/code_gen/case_output.txt new file mode 100644 index 000000000..419b756dc --- /dev/null +++ b/tests/code_gen/case_output.txt @@ -0,0 +1 @@ +Modified.Second sentence. \ No newline at end of file diff --git a/tests/code_gen/is_void.mips b/tests/code_gen/is_void.mips deleted file mode 100644 index 02c891e36..000000000 --- a/tests/code_gen/is_void.mips +++ /dev/null @@ -1,1237 +0,0 @@ -.data - -Object : .word, Object_abort, Object_copy, Object_type_name -Object_cname : .asciiz, "Object" -IO : .word, Object_abort, IO_copy, IO_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int -IO_cname : .asciiz, "IO" -String : .word, Object_abort, String_copy, String_type_name, String_length, String_concat, String_substr -String_cname : .asciiz, "String" -Int : .word, Object_abort, Int_copy, Int_type_name -Int_cname : .asciiz, "Int" -Bool : .word, Object_abort, Bool_copy, Bool_type_name -Bool_cname : .asciiz, "Bool" -Main : .word, Object_abort, Main_copy, Main_type_name, IO_out_string, IO_out_int, IO_in_string, IO_in_int, Main_main, Main_constructor -Main_cname : .asciiz, "Main" -void : .word, -1 -empty_string : .asciiz, "" -input_str_buffer : .space, 1024 -abort_signal : .asciiz, "Program execution aborted" -case_missmatch : .asciiz, "Execution of a case statement without a matching branch" -case_on_void : .asciiz, "Case on void" -dispatch_on_void : .asciiz, "Dispatch on void" -division_by_zero : .asciiz, "Division by zero" -substr_out_of_range : .asciiz, "Substring out of range" -heap_overflow : .asciiz, "Heap overflow" -type_name_Object : .asciiz, "Object" -type_name_IO : .asciiz, "IO" -type_name_String : .asciiz, "String" -type_name_Int : .asciiz, "Int" -type_name_Bool : .asciiz, "Bool" -type_name_Main : .asciiz, "Main" -string_1 : .asciiz, "Ou nou" -string_2 : .asciiz, "YEI" - -.text -.globl main - -length: - li $t4, 0 - length_loop: - lb $t3, 0($a0) - beq $zero, $t3, length_end - add $t4, $t4, 1 - add $a0, $a0, 1 - j length_loop - length_end: - move $a0 $t4 - j $ra -copy: - copy_loop: - beq $zero, $a0, copy_end - lb $t8, 0($t7) - sb $t8, 0($t6) - addi $t6, $t6, 1 - addi $t7, $t7, 1 - addi $a0, $a0, -1 - j copy_loop - copy_end: - j $ra -main: - move $t9 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 8 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t9, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Static Call - jal Main_constructor - sw $a1, 0($fp) - addi $sp, $sp, 0 - #Receiving Arg local_main_internal_0 - lw $t5, 0($fp) - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Executing Static Call - jal Main_main - sw $a1, 4($fp) - addi $sp, $sp, -4 - li $v0, 10 - syscall -Object_abort: - move $t9 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 0 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t9, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing RuntimeError - #Printing Abort Message - la $a0, abort_signal - li $v0, 4 - syscall - #Aborting execution - li $v0, 10 - syscall -Object_copy: - move $t5 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 4 - syscall - sw $v0, 0($fp) - la $t9, Object - sw $t9, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Object_type_name: - move $t1 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 8 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t2, String - sw $t2, 0($v0) - #Executing Load - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 4($fp) - la $t9, String - sw $t9, 0($v0) - li $t9, 6 - sw $t9, 4($v0) - la $t9, type_name_Object - sw $t9, 8($v0) - #Executing Assign - lw $t3, 4($fp) - sw $t3, 0($fp) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -8 - #Return jump - jalr $ra -IO_copy: - move $t0 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t0, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 4 - syscall - sw $v0, 0($fp) - la $t4, IO - sw $t4, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -IO_type_name: - move $t1 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 8 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t3, String - sw $t3, 0($v0) - #Executing Load - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 4($fp) - la $t3, String - sw $t3, 0($v0) - li $t3, 2 - sw $t3, 4($v0) - la $t3, type_name_IO - sw $t3, 8($v0) - #Executing Assign - lw $t3, 4($fp) - sw $t3, 0($fp) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -8 - #Return jump - jalr $ra -IO_out_string: - move $t5 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 0 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #PrintStringNode - lw $a0, -4($fp) - lw $a0, 8($a0) - li $v0, 4 - syscall - #Executing Return - lw $a1, -8($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, 0 - #Return jump - jalr $ra -IO_out_int: - move $t4 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 0 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #PrintIntNode - lw $a0, -4($fp) - li $v0, 1 - syscall - #Executing Return - lw $a1, -8($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, 0 - #Return jump - jalr $ra -IO_in_string: - move $t2 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t2, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #ReadStrNode - #Reading String to buffer - la $a0, input_str_buffer - li $a1, 1024 - li $v0, 8 - syscall - #Saving reference to read string - move $t7 $a0 - #Calculating str length - jal length - #Allocating char array for new string - li $v0, 9 - syscall - move $t6 $v0 - move $t0 $v0 - move $t3 $a0 - #Copying bytes from one char array to another - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t5, String - sw $t5, 0($v0) - #Storing length and reference to char array - sw $t3, 4($v0) - sw $t0, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -IO_in_int: - move $t1 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #ReadIntNode - li $v0, 5 - syscall - sw $v0, 0($fp) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_copy: - move $t4 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t2, String - sw $t2, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_type_name: - move $t4 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 8 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t3, String - sw $t3, 0($v0) - #Executing Load - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 4($fp) - la $t3, String - sw $t3, 0($v0) - li $t3, 6 - sw $t3, 4($v0) - la $t3, type_name_String - sw $t3, 8($v0) - #Executing Assign - lw $t9, 4($fp) - sw $t9, 0($fp) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -8 - #Return jump - jalr $ra -String_length: - move $t4 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Length - lw $t3, -4($fp) - lw $t3, 4($t3) - sw $t3, 0($fp) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_concat: - move $t1 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Loading length - lw $s1, -8($fp) - lw $s1, 4($s1) - lw $s2, -4($fp) - lw $s2, 4($s2) - add $t2, $s1, $s2 - #Allocating new char array - move $a0 $t2 - addi $a0, $a0, 1 - li $v0, 9 - syscall - move $t6 $v0 - move $t0 $v0 - #Copying bytes from first string - lw $t7, -8($fp) - lw $t7, 8($t7) - move $a0 $s1 - jal copy - #Copying bytes from second string - lw $t7, -4($fp) - lw $t7, 8($t7) - move $a0 $s2 - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t1, String - sw $t1, 0($v0) - #Storing length and reference to char array - sw $t2, 4($v0) - sw $t0, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_substr: - move $t4 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Substring - lw $s0, -4($fp) - move $a0 $s0 - addi $a0, $a0, 1 - li $v0, 9 - syscall - move $t6 $v0 - #Loading reference to char array of source string - lw $t7, -12($fp) - lw $t7, 8($t7) - lw $s2, -8($fp) - add $t7, $t7, $s2 - move $s1 $t6 - #Copying bytes from one char array to another - move $a0 $s0 - jal copy - #Null-terminating the string - sb $zero, 0($t6) - #Allocating new String instance - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t2, String - sw $t2, 0($v0) - #Storing length and reference to char array - lw $s0, -4($fp) - sw $s0, 4($v0) - sw $s1, 8($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Int_copy: - move $t9 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t9, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 8 - syscall - sw $v0, 0($fp) - la $t1, Int - sw $t1, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Int_type_name: - move $t4 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 8 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t3, String - sw $t3, 0($v0) - #Executing Load - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 4($fp) - la $t3, String - sw $t3, 0($v0) - li $t3, 3 - sw $t3, 4($v0) - la $t3, type_name_Int - sw $t3, 8($v0) - #Executing Assign - lw $t9, 4($fp) - sw $t9, 0($fp) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -8 - #Return jump - jalr $ra -Bool_copy: - move $t0 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t0, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 8 - syscall - sw $v0, 0($fp) - la $t0, Bool - sw $t0, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Bool_type_name: - move $t3 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 8 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t1, String - sw $t1, 0($v0) - #Executing Load - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 4($fp) - la $t5, String - sw $t5, 0($v0) - li $t5, 4 - sw $t5, 4($v0) - la $t5, type_name_Bool - sw $t5, 8($v0) - #Executing Assign - lw $t1, 4($fp) - sw $t1, 0($fp) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -8 - #Return jump - jalr $ra -Object_constructor: - move $t5 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 4 - syscall - sw $v0, 0($fp) - la $t1, Object - sw $t1, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -IO_constructor: - move $t3 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 4 - syscall - sw $v0, 0($fp) - la $t0, IO - sw $t0, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Int_constructor: - move $t4 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 8 - syscall - sw $v0, 0($fp) - la $t0, Int - sw $t0, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Bool_constructor: - move $t1 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 8 - syscall - sw $v0, 0($fp) - la $t5, Bool - sw $t5, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -String_constructor: - move $t1 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 4 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t9, String - sw $t9, 0($v0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -4 - #Return jump - jalr $ra -Main_copy: - move $t1 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 12 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t1, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t9, Main - sw $t9, 0($v0) - #Executing GetAttr - lw $t0, -4($fp) - lw $t5, 4($t0) - sw $t5, 4($fp) - #Executing SetAttr - lw $t3, 0($fp) - lw $t5, 4($fp) - sw $t5, 4($t3) - #Executing GetAttr - lw $t3, -4($fp) - lw $t4, 8($t3) - sw $t4, 8($fp) - #Executing SetAttr - lw $t0, 0($fp) - lw $t9, 8($fp) - sw $t9, 8($t0) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -12 - #Return jump - jalr $ra -Main_type_name: - move $t5 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 8 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t3, String - sw $t3, 0($v0) - #Executing Load - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 4($fp) - la $t4, String - sw $t4, 0($v0) - li $t4, 4 - sw $t4, 4($v0) - la $t4, type_name_Main - sw $t4, 8($v0) - #Executing Assign - lw $t0, 4($fp) - sw $t0, 0($fp) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -8 - #Return jump - jalr $ra -Main_constructor: - move $t4 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 20 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - #Executing Allocate - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 0($fp) - la $t5, Main - sw $t5, 0($v0) - #Executing DefaultValue - li $t0, 0 - sw $t0, 4($fp) - #Executing SetAttr - lw $t3, 0($fp) - lw $t4, 4($fp) - sw $t4, 4($t3) - #Executing DefaultValue - li $t1, 0 - sw $t1, 8($fp) - #Executing SetAttr - lw $t1, 0($fp) - lw $t3, 8($fp) - sw $t3, 8($t1) - #Executing Assign - li $t3, 0 - sw $t3, 12($fp) - #Executing SetAttr - lw $t4, 0($fp) - lw $t0, 12($fp) - sw $t0, 4($t4) - #Executing Assign - li $t1, 3 - sw $t1, 16($fp) - #Executing SetAttr - lw $t3, 0($fp) - lw $t5, 16($fp) - sw $t5, 8($t3) - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -20 - #Return jump - jalr $ra -Main_main: - move $t4 $fp - #New $fp - move $fp $sp - #Reserving space for locals - addi $sp, $sp, 60 - #Pushing $ra - sw $ra, 0($sp) - addi $sp, $sp, 4 - #Saving $fp - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing instructions - WHILE_1: - #Executing GetAttr - lw $t5, -4($fp) - lw $t4, 4($t5) - sw $t4, 16($fp) - #Executing GetAttr - lw $t5, -4($fp) - lw $t9, 8($t5) - sw $t9, 20($fp) - #Executing Less Operation - lw $t0, 16($fp) - lw $t1, 20($fp) - slt $t3, $t0, $t1 - sw $t3, 12($fp) - lw $t4, 12($fp) - bnez $t4, BODY_2 - #Executing Goto - j END_WHILE_3 - BODY_2: - #Executing GetAttr - lw $t5, -4($fp) - lw $t9, 4($t5) - sw $t9, 28($fp) - #Executing Assign - li $t5, 1 - sw $t5, 32($fp) - #Executing Plus Operation - lw $t5, 28($fp) - lw $t1, 32($fp) - add $t9, $t5, $t1 - sw $t9, 24($fp) - #Executing SetAttr - lw $t1, -4($fp) - lw $t0, 24($fp) - sw $t0, 4($t1) - #Executing Goto - j WHILE_1 - END_WHILE_3: - #Executing DefaultValue - la $t5, void - sw $t5, 8($fp) - #Executing IsVoid - lw $t0, 8($fp) - la $t5, void - seq $t0, $t0, $t5 - sw $t0, 4($fp) - lw $t3, 4($fp) - bnez $t3, THEN_4 - #Executing Assign - lw $t4, -4($fp) - sw $t4, 36($fp) - #Executing typeof - lw $t1, 36($fp) - lw $t1, 0($t1) - sw $t1, 40($fp) - #Executing Load - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 44($fp) - la $t0, String - sw $t0, 0($v0) - li $t0, 6 - sw $t0, 4($v0) - la $t0, string_1 - sw $t0, 8($v0) - #Receiving Arg local_Main_main_internal_9 - lw $t4, 36($fp) - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Receiving Arg local_Main_main_internal_11 - lw $t3, 44($fp) - sw $t3, 0($sp) - addi $sp, $sp, 4 - #Executing Dynamic Call - lw $t4, 40($fp) - lw $t9, 12($t4) - jalr $t9 - sw $a1, 0($fp) - addi $sp, $sp, -8 - #Executing Goto - j END_IF_5 - THEN_4: - #Executing Assign - lw $t9, -4($fp) - sw $t9, 48($fp) - #Executing typeof - lw $t5, 48($fp) - lw $t5, 0($t5) - sw $t5, 52($fp) - #Executing Load - li $v0, 9 - li $a0, 12 - syscall - sw $v0, 56($fp) - la $t3, String - sw $t3, 0($v0) - li $t3, 3 - sw $t3, 4($v0) - la $t3, string_2 - sw $t3, 8($v0) - #Receiving Arg local_Main_main_internal_12 - lw $t5, 48($fp) - sw $t5, 0($sp) - addi $sp, $sp, 4 - #Receiving Arg local_Main_main_internal_14 - lw $t4, 56($fp) - sw $t4, 0($sp) - addi $sp, $sp, 4 - #Executing Dynamic Call - lw $t4, 52($fp) - lw $t3, 12($t4) - jalr $t3 - sw $a1, 0($fp) - addi $sp, $sp, -8 - END_IF_5: - #Executing Return - lw $a1, 0($fp) - #Restoring saved $fp - addi $sp, $sp, -4 - lw $fp, 0($sp) - #Restoring saved $ra - addi $sp, $sp, -4 - lw $ra, 0($sp) - #Cleaning stack after call - addi $sp, $sp, -60 - #Return jump - jalr $ra From f3ab47811c7007bb5310f3bc8cf404d3d320003c Mon Sep 17 00:00:00 2001 From: smartos99 Date: Wed, 9 Mar 2022 18:48:57 -0500 Subject: [PATCH 142/162] Fix read string --- src/code_gen/mips_builder.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/code_gen/mips_builder.py b/src/code_gen/mips_builder.py index a8d207b2a..31f54a4e3 100644 --- a/src/code_gen/mips_builder.py +++ b/src/code_gen/mips_builder.py @@ -3,7 +3,7 @@ # from operator import le # from tkinter.tix import Select # from soupsieve import select -from re import S + import cmp.visitor as visitor import cmp.cil as cil import random @@ -958,11 +958,6 @@ def visit(self,node): self.register_instruction(mips.CommentNode, "Saving reference to read string") reg1 = self.memo.get_unused_reg() - # if reg1 != t1: - # if t1 in self.memo.used_reg: - # self.register_instruction(mips.MoveNode,reg1,t1) - # else: - # self.memo.clean() self.register_instruction(mips.MoveNode, t7, a0) self.register_instruction(mips.CommentNode, "Calculating str length") @@ -982,7 +977,7 @@ def visit(self,node): ) # saving pointer to char array reg4 = self.memo.get_unused_reg() - # self.register_instruction(mips.AddNode, a0, a0, -1) + self.register_instruction(mips.AddNode, a0, a0, -1) ####?????????? self.register_instruction(mips.MoveNode, reg4, a0) # saving length self.register_instruction( From c31e5b1cbec726ae9cd7d8eed65acd37a4ebb6e2 Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Wed, 9 Mar 2022 19:00:16 -0500 Subject: [PATCH 143/162] fix: add self to variableNode --- src/code_gen/cil_builder.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index c8adad59a..5324aa5b4 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -869,6 +869,11 @@ def visit(self, node, return_var): @visitor.when(cool.VariableNode) def visit(self, node, return_var): + + if node.lex == "self": + self.register_instruction(AssignNode(return_var, "self")) + return + local_id = self.get_local(node.lex) if any(local_id == l.name for l in self.current_function.localvars): self.register_instruction(AssignNode(return_var, local_id)) From a44ef2d559f50e29d8a31cd0fa50795ab9fc0e81 Mon Sep 17 00:00:00 2001 From: smartos99 Date: Wed, 9 Mar 2022 19:04:15 -0500 Subject: [PATCH 144/162] Remove read string test --- tests/code_gen/read_string.cl | 10 ---------- tests/code_gen/read_string_input.txt | 1 - tests/code_gen/read_string_output.txt | 1 - 3 files changed, 12 deletions(-) delete mode 100644 tests/code_gen/read_string.cl delete mode 100644 tests/code_gen/read_string_input.txt delete mode 100644 tests/code_gen/read_string_output.txt diff --git a/tests/code_gen/read_string.cl b/tests/code_gen/read_string.cl deleted file mode 100644 index 0d1bbe934..000000000 --- a/tests/code_gen/read_string.cl +++ /dev/null @@ -1,10 +0,0 @@ -class Main inherits IO{ - a : String; - main (): Object { - { - a <- in_string(); - out_string(a); - } - - }; -}; \ No newline at end of file diff --git a/tests/code_gen/read_string_input.txt b/tests/code_gen/read_string_input.txt deleted file mode 100644 index 43e0c3c8b..000000000 --- a/tests/code_gen/read_string_input.txt +++ /dev/null @@ -1 +0,0 @@ -Feliz dia de la mujer \ No newline at end of file diff --git a/tests/code_gen/read_string_output.txt b/tests/code_gen/read_string_output.txt deleted file mode 100644 index 43e0c3c8b..000000000 --- a/tests/code_gen/read_string_output.txt +++ /dev/null @@ -1 +0,0 @@ -Feliz dia de la mujer \ No newline at end of file From 6b3e5c07a8043f946d35ec8f69246b1c16d5901c Mon Sep 17 00:00:00 2001 From: smartos99 Date: Thu, 10 Mar 2022 02:21:00 -0500 Subject: [PATCH 145/162] Modify Default Node --- src/code_gen/cil_builder.py | 8 ++++---- src/code_gen/mips_builder.py | 12 +++++++++++- tests/code_gen/unary_nodes.cl | 2 +- tests/code_gen/unary_nodes_output.txt | 2 +- tests/{codegen => tests_ok}/atoi.cl | 0 tests/{codegen => tests_ok}/atoi_input.txt | 0 tests/{codegen => tests_ok}/atoi_output.txt | 0 tests/{codegen => tests_ok}/complex.cl | 0 tests/{codegen => tests_ok}/complex_input.txt | 0 tests/{codegen => tests_ok}/complex_output.txt | 0 tests/{codegen => tests_ok}/fib.cl | 0 tests/{codegen => tests_ok}/fib_input.txt | 0 tests/{codegen => tests_ok}/fib_output.txt | 0 tests/{codegen => tests_ok}/hello_world.cl | 0 tests/{codegen => tests_ok}/hello_world_input.txt | 0 tests/{codegen => tests_ok}/hello_world_output.txt | 0 tests/{codegen => tests_ok}/life.cl | 0 tests/{codegen => tests_ok}/life_input.txt | 0 tests/{codegen => tests_ok}/life_output.txt | 0 tests/{codegen => tests_ok}/new_complex.cl | 0 tests/{codegen => tests_ok}/new_complex_input.txt | 0 tests/{codegen => tests_ok}/new_complex_output.txt | 0 tests/{codegen => tests_ok}/palindrome.cl | 0 tests/{codegen => tests_ok}/palindrome_input.txt | 0 tests/{codegen => tests_ok}/palindrome_output.txt | 0 25 files changed, 17 insertions(+), 7 deletions(-) rename tests/{codegen => tests_ok}/atoi.cl (100%) rename tests/{codegen => tests_ok}/atoi_input.txt (100%) rename tests/{codegen => tests_ok}/atoi_output.txt (100%) rename tests/{codegen => tests_ok}/complex.cl (100%) rename tests/{codegen => tests_ok}/complex_input.txt (100%) rename tests/{codegen => tests_ok}/complex_output.txt (100%) rename tests/{codegen => tests_ok}/fib.cl (100%) rename tests/{codegen => tests_ok}/fib_input.txt (100%) rename tests/{codegen => tests_ok}/fib_output.txt (100%) rename tests/{codegen => tests_ok}/hello_world.cl (100%) rename tests/{codegen => tests_ok}/hello_world_input.txt (100%) rename tests/{codegen => tests_ok}/hello_world_output.txt (100%) rename tests/{codegen => tests_ok}/life.cl (100%) rename tests/{codegen => tests_ok}/life_input.txt (100%) rename tests/{codegen => tests_ok}/life_output.txt (100%) rename tests/{codegen => tests_ok}/new_complex.cl (100%) rename tests/{codegen => tests_ok}/new_complex_input.txt (100%) rename tests/{codegen => tests_ok}/new_complex_output.txt (100%) rename tests/{codegen => tests_ok}/palindrome.cl (100%) rename tests/{codegen => tests_ok}/palindrome_input.txt (100%) rename tests/{codegen => tests_ok}/palindrome_output.txt (100%) diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index 38e65799f..06dacc4eb 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -369,11 +369,11 @@ def object_copy(self): def object_type_name(self): self.params.append(ParamNode("self")) - solve = self.define_internal_local() + # solve = self.define_internal_local() self.data.append( DataNode(f"type_name_{self.current_type.name}", f"{self.current_type.name}") ) - self.register_instruction(AllocateNode("String", solve)) + # self.register_instruction(AllocateNode("String", solve)) type_name = self.define_internal_local() self.register_instruction( LoadNode( @@ -385,8 +385,8 @@ def object_type_name(self): ), ) ) - self.register_instruction(AssignNode(solve, type_name)) - self.register_instruction(ReturnNode(solve)) + # self.register_instruction(AssignNode(solve, type_name)) + self.register_instruction(ReturnNode(type_name)) def io_outstring(self): self.params.append(ParamNode("self")) diff --git a/src/code_gen/mips_builder.py b/src/code_gen/mips_builder.py index 31f54a4e3..e8130b67d 100644 --- a/src/code_gen/mips_builder.py +++ b/src/code_gen/mips_builder.py @@ -33,7 +33,7 @@ SUBSTR_OUT_RANGE = "substr_out_of_range" # MIPS HEAP_OVERFLOW = "heap_overflow" STRING_SIZE = 12 -VOID = "void" +VOID = "Void" STR_CMP = "string_comparer" EMPTY_STRING = "empty_string" LENGTH = "length" @@ -604,6 +604,16 @@ def visit(self, node): ) # pq en vo esta el allocate self.register_instruction(mips.LoadAddress, reg, EMPTY_STRING) self.register_instruction(mips.StoreWordNode, reg, CHARS_ATTR_OFFSET, v0) + elif node.type != VOID: + _size = (len(self.types[node.type].attributes) + 1) * 4 + self.register_instruction(mips.LoadInmediate, v0, SYSCALL_SBRK) + self.register_instruction(mips.LoadInmediate, a0, _size) + self.register_instruction(mips.SyscallNode) + + self.register_instruction(mips.StoreWordNode, v0, dest_offset, fp) + reg = self.memo.get_unused_reg() + self.register_instruction(mips.LoadAddress, reg, node.type) + self.register_instruction(mips.StoreWordNode, reg, 0, v0) else: self.register_instruction(mips.LoadAddress, reg, VOID) self.register_instruction(mips.StoreWordNode, reg, dest_offset, fp) diff --git a/tests/code_gen/unary_nodes.cl b/tests/code_gen/unary_nodes.cl index 254efb12c..98a12e453 100644 --- a/tests/code_gen/unary_nodes.cl +++ b/tests/code_gen/unary_nodes.cl @@ -1,5 +1,5 @@ class Main inherits IO{ - a : Int; + a : Int <- 2; b : Int; c: Bool; main (): Object { diff --git a/tests/code_gen/unary_nodes_output.txt b/tests/code_gen/unary_nodes_output.txt index c22708346..06056678e 100644 --- a/tests/code_gen/unary_nodes_output.txt +++ b/tests/code_gen/unary_nodes_output.txt @@ -1 +1 @@ -0 \ No newline at end of file +-2 \ No newline at end of file diff --git a/tests/codegen/atoi.cl b/tests/tests_ok/atoi.cl similarity index 100% rename from tests/codegen/atoi.cl rename to tests/tests_ok/atoi.cl diff --git a/tests/codegen/atoi_input.txt b/tests/tests_ok/atoi_input.txt similarity index 100% rename from tests/codegen/atoi_input.txt rename to tests/tests_ok/atoi_input.txt diff --git a/tests/codegen/atoi_output.txt b/tests/tests_ok/atoi_output.txt similarity index 100% rename from tests/codegen/atoi_output.txt rename to tests/tests_ok/atoi_output.txt diff --git a/tests/codegen/complex.cl b/tests/tests_ok/complex.cl similarity index 100% rename from tests/codegen/complex.cl rename to tests/tests_ok/complex.cl diff --git a/tests/codegen/complex_input.txt b/tests/tests_ok/complex_input.txt similarity index 100% rename from tests/codegen/complex_input.txt rename to tests/tests_ok/complex_input.txt diff --git a/tests/codegen/complex_output.txt b/tests/tests_ok/complex_output.txt similarity index 100% rename from tests/codegen/complex_output.txt rename to tests/tests_ok/complex_output.txt diff --git a/tests/codegen/fib.cl b/tests/tests_ok/fib.cl similarity index 100% rename from tests/codegen/fib.cl rename to tests/tests_ok/fib.cl diff --git a/tests/codegen/fib_input.txt b/tests/tests_ok/fib_input.txt similarity index 100% rename from tests/codegen/fib_input.txt rename to tests/tests_ok/fib_input.txt diff --git a/tests/codegen/fib_output.txt b/tests/tests_ok/fib_output.txt similarity index 100% rename from tests/codegen/fib_output.txt rename to tests/tests_ok/fib_output.txt diff --git a/tests/codegen/hello_world.cl b/tests/tests_ok/hello_world.cl similarity index 100% rename from tests/codegen/hello_world.cl rename to tests/tests_ok/hello_world.cl diff --git a/tests/codegen/hello_world_input.txt b/tests/tests_ok/hello_world_input.txt similarity index 100% rename from tests/codegen/hello_world_input.txt rename to tests/tests_ok/hello_world_input.txt diff --git a/tests/codegen/hello_world_output.txt b/tests/tests_ok/hello_world_output.txt similarity index 100% rename from tests/codegen/hello_world_output.txt rename to tests/tests_ok/hello_world_output.txt diff --git a/tests/codegen/life.cl b/tests/tests_ok/life.cl similarity index 100% rename from tests/codegen/life.cl rename to tests/tests_ok/life.cl diff --git a/tests/codegen/life_input.txt b/tests/tests_ok/life_input.txt similarity index 100% rename from tests/codegen/life_input.txt rename to tests/tests_ok/life_input.txt diff --git a/tests/codegen/life_output.txt b/tests/tests_ok/life_output.txt similarity index 100% rename from tests/codegen/life_output.txt rename to tests/tests_ok/life_output.txt diff --git a/tests/codegen/new_complex.cl b/tests/tests_ok/new_complex.cl similarity index 100% rename from tests/codegen/new_complex.cl rename to tests/tests_ok/new_complex.cl diff --git a/tests/codegen/new_complex_input.txt b/tests/tests_ok/new_complex_input.txt similarity index 100% rename from tests/codegen/new_complex_input.txt rename to tests/tests_ok/new_complex_input.txt diff --git a/tests/codegen/new_complex_output.txt b/tests/tests_ok/new_complex_output.txt similarity index 100% rename from tests/codegen/new_complex_output.txt rename to tests/tests_ok/new_complex_output.txt diff --git a/tests/codegen/palindrome.cl b/tests/tests_ok/palindrome.cl similarity index 100% rename from tests/codegen/palindrome.cl rename to tests/tests_ok/palindrome.cl diff --git a/tests/codegen/palindrome_input.txt b/tests/tests_ok/palindrome_input.txt similarity index 100% rename from tests/codegen/palindrome_input.txt rename to tests/tests_ok/palindrome_input.txt diff --git a/tests/codegen/palindrome_output.txt b/tests/tests_ok/palindrome_output.txt similarity index 100% rename from tests/codegen/palindrome_output.txt rename to tests/tests_ok/palindrome_output.txt From 055ba4584ee9f9270ebdd8835d4a54a3649da752 Mon Sep 17 00:00:00 2001 From: smartos99 Date: Thu, 10 Mar 2022 02:44:01 -0500 Subject: [PATCH 146/162] Change TypeOfNode --- src/cmp/cil.py | 4 +++- src/code_gen/cil_builder.py | 5 ++++- src/code_gen/mips_builder.py | 22 ++++++++++++++-------- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/cmp/cil.py b/src/cmp/cil.py index 65f669dd8..95984f3fe 100644 --- a/src/cmp/cil.py +++ b/src/cmp/cil.py @@ -134,9 +134,11 @@ def __init__(self, itype, dest): class TypeOfNode(InstructionNode): - def __init__(self, obj, dest): + def __init__(self, obj, dest,flag = False,typex = None): self.obj = obj self.dest = dest + self.flag = flag + self.type = typex class LabelNode(InstructionNode): diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index 06dacc4eb..ff434a051 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -607,7 +607,10 @@ def visit(self, node, return_var): instance_type = None if not node.at_type: instance_type = self.define_internal_local() - self.register_instruction(TypeOfNode(instance, instance_type)) + if obj_type in ["Int","Bool"]: + self.register_instruction(TypeOfNode(instance, instance_type,True,obj_type)) + else: + self.register_instruction(TypeOfNode(instance, instance_type)) args = [instance] for arg in node.args: diff --git a/src/code_gen/mips_builder.py b/src/code_gen/mips_builder.py index e8130b67d..47cb1b89b 100644 --- a/src/code_gen/mips_builder.py +++ b/src/code_gen/mips_builder.py @@ -1048,14 +1048,20 @@ def visit(self, node): @visitor.when(cil.TypeOfNode) def visit(self, node): self.memo.save() - obj_offset = self.get_offset(node.obj) - dest_offset = self.get_offset(node.dest) - - reg1 = self.memo.get_unused_reg() - self.register_instruction(mips.CommentNode, "Executing typeof") - self.register_instruction(mips.LoadWordNode, reg1, obj_offset, fp) - self.register_instruction(mips.LoadWordNode, reg1, TYPEINFO_ATTR_OFFSET, reg1) - self.register_instruction(mips.StoreWordNode, reg1, dest_offset, fp) + if node.flag: + self.register_instruction(mips.CommentNode, "Executing typeof") + reg1 = self.memo.get_unused_reg() + self.register_instruction(mips.LoadAddress,reg1,node.type) + dest_offset = self.get_offset(node.dest) + self.register_instruction(mips.StoreWordNode, reg1, dest_offset, fp) + else: + obj_offset = self.get_offset(node.obj) + dest_offset = self.get_offset(node.dest) + reg1 = self.memo.get_unused_reg() + self.register_instruction(mips.CommentNode, "Executing typeof") + self.register_instruction(mips.LoadWordNode, reg1, obj_offset, fp) + self.register_instruction(mips.LoadWordNode, reg1, TYPEINFO_ATTR_OFFSET, reg1) + self.register_instruction(mips.StoreWordNode, reg1, dest_offset, fp) self.memo.clean() From 20b86660a6eadd8a63082649316c24b8aebe813f Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Thu, 10 Mar 2022 02:54:45 -0500 Subject: [PATCH 147/162] feat: use dynamic type in case --- src/cmp/cil.py | 15 ++++- src/code_gen/cil_builder.py | 106 ++++++++++++++++++++++-------------- tests/code_gen.py | 2 +- 3 files changed, 79 insertions(+), 44 deletions(-) diff --git a/src/cmp/cil.py b/src/cmp/cil.py index 65f669dd8..03fedcd80 100644 --- a/src/cmp/cil.py +++ b/src/cmp/cil.py @@ -92,9 +92,11 @@ class LessEqualNode(ArithmeticNode): class EqualNode(ArithmeticNode): pass + class StrEqualNode(ArithmeticNode): pass + class UnaryNode(InstructionNode): def __init__(self, dest, expr): self.dest = dest @@ -254,6 +256,13 @@ def __init__(self, dest, value): self.value = value +class CompareTypes(InstructionNode): + def __init__(self, dest, typeof, typex: str): + self.dest = dest + self.typeof = typeof + self.type = typex + + class ExitNode(InstructionNode): def __init__(self): pass @@ -330,7 +339,7 @@ def visit(self, node): @visitor.when(EqualNode) def visit(self, node): return f"{node.dest} = {node.left} == {node.right}" - + @visitor.when(StrEqualNode) def visit(self, node): return f"{node.dest} = {node.left} == {node.right}" @@ -443,6 +452,10 @@ def visit(self, node): def visit(self, node): return f"{node.dest} = ISVOID {node.value}" + @visitor.when(CompareTypes) + def visit(self, node): + return f"{node.dest} = {node.typeof} TYPE_EQUALS {node.type}" + @visitor.when(ExitNode) def visit(self, node): return f"EXIT" diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index 38e65799f..df6756b1f 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -47,6 +47,7 @@ DefaultValueNode, IsVoidNode, ExitNode, + CompareTypes ) from cool_visitor import FormatVisitor @@ -369,11 +370,11 @@ def object_copy(self): def object_type_name(self): self.params.append(ParamNode("self")) - solve = self.define_internal_local() + # solve = self.define_internal_local() self.data.append( DataNode(f"type_name_{self.current_type.name}", f"{self.current_type.name}") ) - self.register_instruction(AllocateNode("String", solve)) + # self.register_instruction(AllocateNode("String", solve)) type_name = self.define_internal_local() self.register_instruction( LoadNode( @@ -385,8 +386,8 @@ def object_type_name(self): ), ) ) - self.register_instruction(AssignNode(solve, type_name)) - self.register_instruction(ReturnNode(solve)) + # self.register_instruction(AssignNode(solve, type_name)) + self.register_instruction(ReturnNode(type_name)) def io_outstring(self): self.params.append(ParamNode("self")) @@ -708,57 +709,78 @@ def visit(self, node, return_var=None): @visitor.when(cool.CaseNode) def visit(self, node, return_var=None): - def get_least_type(): - expr_type = node.expr.static_type - conformed_types = [] - for case_item in node.case_items: - case_type = self.context.get_type(case_item.type) - if expr_type.conforms_to(case_type): - conformed_types.append(case_type.name) + def get_children(static_type): + children = [] + for t in self.context.types.values(): + if t.conforms_to(static_type): + children.append(t) + + return children - least_type = None - solve = expr_type + def get_least_type(expr_dynamic_type): + case_item_types = [case_item.type for case_item in node.case_items] + solve = expr_dynamic_type while solve is not None: - if solve.name in conformed_types: - least_type = solve.name - break + if solve.name in case_item_types: + return solve.name solve = solve.parent - return least_type + return None + + def get_asserted_branch(least_type:str): + for case_item in node.case_items: + if case_item.type == least_type: + return case_item + return None expr_value = self.define_internal_local() self.visit(node.expr, expr_value) - least_type = get_least_type() + possible_dynamic_types = get_children(node.expr.static_type) - asserted_item = None - for case_item in node.case_items: - if case_item.type == least_type: - asserted_item = case_item - break + branch_labels = [] + for t in possible_dynamic_types: + dynamic_type = self.define_internal_local() + self.register_instruction(TypeOfNode(expr_value, dynamic_type)) - if not asserted_item: - self.data.append( - DataNode("runtime_error", "No branch can be selected for evaluation") - ) - error = self.define_internal_local() - self.register_instruction( - LoadNode( - error, - VariableInfo( - "runtime_error", - None, - "No branch can be selected for evaluation", - ), - ) + label = "BRANCH" + self.next_id() + equals = self.define_internal_local() + self.register_instruction(CompareTypes(equals, dynamic_type, t.name)) + self.register_instruction(GotoIfNode(equals,label)) + + least_type = get_least_type(t) + asserted_branch = get_asserted_branch(least_type) + branch_labels.append((asserted_branch, label)) + + + self.data.append( + DataNode("runtime_error", "No branch can be selected for evaluation") + ) + error = self.define_internal_local() + self.register_instruction( + LoadNode( + error, + VariableInfo( + "runtime_error", + None, + "No branch can be selected for evaluation", + ), ) - self.register_instruction(RuntimeErrorNode(error)) - return + ) + self.register_instruction(RuntimeErrorNode(error)) + + end_case_label = "END_CASE_" + self.next_id() + for branch, label in branch_labels: + if not branch: + continue + self.register_instruction(LabelNode(label)) + new_local = self.register_local(branch.id) + self.register_instruction(AssignNode(new_local, expr_value)) - new_local = self.register_local(asserted_item.id) - self.register_instruction(AssignNode(new_local, expr_value)) + self.visit(branch.expr, return_var) + self.register_instruction(GotoNode(end_case_label)) - self.visit(asserted_item.expr, return_var) + self.register_instruction(LabelNode(end_case_label)) @visitor.when(cool.CaseItemNode) def visit(self, node, return_var=None): diff --git a/tests/code_gen.py b/tests/code_gen.py index 3dfbd0c8b..b8732837f 100644 --- a/tests/code_gen.py +++ b/tests/code_gen.py @@ -4,7 +4,7 @@ tests_dir = __file__.rpartition("/")[0] + "/code_gen/" -tests = [(file) for file in os.listdir(tests_dir) if file.endswith(".cl")] +tests = [(file) for file in os.listdir(tests_dir) if file.endswith("case.cl")] # @pytest.mark.lexer # @pytest.mark.parser From c992c2651e207b7f5117002eb88730b1261fa151 Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Thu, 10 Mar 2022 03:54:32 -0500 Subject: [PATCH 148/162] feat: add CompareTypes node. Passed 4 more tests --- src/cmp/cil.py | 2 +- src/code_gen/cil_builder.py | 5 +---- src/code_gen/mips_builder.py | 18 ++++++++++++++++++ tests/code_gen.py | 4 ++-- tests/code_gen/case.cl | 10 +++++----- tests/code_gen/case_output.txt | 2 +- tests/{codegen => tests_ok}/arith.cl | 0 tests/{codegen => tests_ok}/arith_input.txt | 0 tests/{codegen => tests_ok}/arith_output.txt | 0 tests/{codegen => tests_ok}/cells.cl | 0 tests/{codegen => tests_ok}/cells_input.txt | 0 tests/{codegen => tests_ok}/cells_output.txt | 0 tests/{codegen => tests_ok}/print-cool.cl | 0 .../{codegen => tests_ok}/print-cool_input.txt | 0 .../print-cool_output.txt | 0 15 files changed, 28 insertions(+), 13 deletions(-) rename tests/{codegen => tests_ok}/arith.cl (100%) rename tests/{codegen => tests_ok}/arith_input.txt (100%) rename tests/{codegen => tests_ok}/arith_output.txt (100%) rename tests/{codegen => tests_ok}/cells.cl (100%) rename tests/{codegen => tests_ok}/cells_input.txt (100%) rename tests/{codegen => tests_ok}/cells_output.txt (100%) rename tests/{codegen => tests_ok}/print-cool.cl (100%) rename tests/{codegen => tests_ok}/print-cool_input.txt (100%) rename tests/{codegen => tests_ok}/print-cool_output.txt (100%) diff --git a/src/cmp/cil.py b/src/cmp/cil.py index da184c80b..a0e8a7bb0 100644 --- a/src/cmp/cil.py +++ b/src/cmp/cil.py @@ -136,7 +136,7 @@ def __init__(self, itype, dest): class TypeOfNode(InstructionNode): - def __init__(self, obj, dest,flag = False,typex = None): + def __init__(self, obj, dest, flag=False, typex=None): self.obj = obj self.dest = dest self.flag = flag diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index b8b00e00a..e0bd1ecd9 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -370,11 +370,9 @@ def object_copy(self): def object_type_name(self): self.params.append(ParamNode("self")) - # solve = self.define_internal_local() self.data.append( DataNode(f"type_name_{self.current_type.name}", f"{self.current_type.name}") ) - # self.register_instruction(AllocateNode("String", solve)) type_name = self.define_internal_local() self.register_instruction( LoadNode( @@ -386,7 +384,6 @@ def object_type_name(self): ), ) ) - # self.register_instruction(AssignNode(solve, type_name)) self.register_instruction(ReturnNode(type_name)) def io_outstring(self): @@ -715,7 +712,7 @@ def visit(self, node, return_var=None): def get_children(static_type): children = [] for t in self.context.types.values(): - if t.conforms_to(static_type): + if t.conforms_to(static_type) and t.name != "AUTO_TYPE": children.append(t) return children diff --git a/src/code_gen/mips_builder.py b/src/code_gen/mips_builder.py index 47cb1b89b..600d40c4e 100644 --- a/src/code_gen/mips_builder.py +++ b/src/code_gen/mips_builder.py @@ -802,6 +802,24 @@ def visit(self,node): self.register_instruction(mips.StoreWordNode,r_dest,dest_off,fp) self.memo.clean() + + @visitor.when(cil.CompareTypes) + def visit(self,node): + self.memo.save() + reg1 = self.memo.get_unused_reg() + reg2 = self.memo.get_unused_reg() + + typeof_offset = self.get_offset(node.typeof) + self.register_instruction(mips.LoadWordNode,reg1,typeof_offset,fp) + self.register_instruction(mips.LoadAddress,reg2,node.type) + + self.register_instruction(mips.SetEq,a2,reg1,reg2) + dest_offset = self.get_offset(node.dest) + self.register_instruction(mips.StoreWordNode,a2,dest_offset,fp) + + self.memo.clean() + + @visitor.when(cil.StrEqualNode) def visit(self,node): diff --git a/tests/code_gen.py b/tests/code_gen.py index b8732837f..c59d4317a 100644 --- a/tests/code_gen.py +++ b/tests/code_gen.py @@ -3,8 +3,8 @@ from utils import compare_outputs -tests_dir = __file__.rpartition("/")[0] + "/code_gen/" -tests = [(file) for file in os.listdir(tests_dir) if file.endswith("case.cl")] +tests_dir = __file__.rpartition("/")[0] + "/codegen/" +tests = [(file) for file in os.listdir(tests_dir) if file.endswith("hairyscary.cl")] # @pytest.mark.lexer # @pytest.mark.parser diff --git a/tests/code_gen/case.cl b/tests/code_gen/case.cl index b3d42c0ce..8f7a7498a 100644 --- a/tests/code_gen/case.cl +++ b/tests/code_gen/case.cl @@ -2,7 +2,7 @@ class Main inherits IO{ - a : A <- new A; + a : A <- new B; b : B <- new B; c : String <- "First sentence."; d : String <- "Second sentence."; @@ -10,10 +10,10 @@ class Main inherits IO{ main (): Object { { out_string( - (case c of - h:String => h <- "Modified."; - f:A => d; - esac).concat(d) + (case a of + h:A => new A; + f:B => new B; + esac).type_name() ); } }; diff --git a/tests/code_gen/case_output.txt b/tests/code_gen/case_output.txt index 419b756dc..7371f47a6 100644 --- a/tests/code_gen/case_output.txt +++ b/tests/code_gen/case_output.txt @@ -1 +1 @@ -Modified.Second sentence. \ No newline at end of file +B \ No newline at end of file diff --git a/tests/codegen/arith.cl b/tests/tests_ok/arith.cl similarity index 100% rename from tests/codegen/arith.cl rename to tests/tests_ok/arith.cl diff --git a/tests/codegen/arith_input.txt b/tests/tests_ok/arith_input.txt similarity index 100% rename from tests/codegen/arith_input.txt rename to tests/tests_ok/arith_input.txt diff --git a/tests/codegen/arith_output.txt b/tests/tests_ok/arith_output.txt similarity index 100% rename from tests/codegen/arith_output.txt rename to tests/tests_ok/arith_output.txt diff --git a/tests/codegen/cells.cl b/tests/tests_ok/cells.cl similarity index 100% rename from tests/codegen/cells.cl rename to tests/tests_ok/cells.cl diff --git a/tests/codegen/cells_input.txt b/tests/tests_ok/cells_input.txt similarity index 100% rename from tests/codegen/cells_input.txt rename to tests/tests_ok/cells_input.txt diff --git a/tests/codegen/cells_output.txt b/tests/tests_ok/cells_output.txt similarity index 100% rename from tests/codegen/cells_output.txt rename to tests/tests_ok/cells_output.txt diff --git a/tests/codegen/print-cool.cl b/tests/tests_ok/print-cool.cl similarity index 100% rename from tests/codegen/print-cool.cl rename to tests/tests_ok/print-cool.cl diff --git a/tests/codegen/print-cool_input.txt b/tests/tests_ok/print-cool_input.txt similarity index 100% rename from tests/codegen/print-cool_input.txt rename to tests/tests_ok/print-cool_input.txt diff --git a/tests/codegen/print-cool_output.txt b/tests/tests_ok/print-cool_output.txt similarity index 100% rename from tests/codegen/print-cool_output.txt rename to tests/tests_ok/print-cool_output.txt From bd57822de48fcffcc77285030bff0be8156b6139 Mon Sep 17 00:00:00 2001 From: gabriela Date: Thu, 10 Mar 2022 04:47:21 -0500 Subject: [PATCH 149/162] Fix comment state bug. Add a regular expression to match any character in state comments through "." specification. --- src/tokens_rules.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/tokens_rules.py b/src/tokens_rules.py index 8c5989614..bfa40d569 100644 --- a/src/tokens_rules.py +++ b/src/tokens_rules.py @@ -99,15 +99,12 @@ def t_comments_ccom(t): # return t t.lexer.begin("INITIAL") -def t_comments_any(t): - # r'[^\s\{\}\'\"]+' - r'[^\s\'\"]+' - # t.lexer.skip(1) - # For bad characters. In this case we just skip over everything but (* or *) def t_comments_error(t): t.lexer.skip(1) +def t_comments_anycharacter(t): + "." # EOF handling rule def t_comments_eof(t): From a3031ab414b28905f15d42f4e69d8abc61bf3150 Mon Sep 17 00:00:00 2001 From: smartos99 Date: Thu, 10 Mar 2022 13:55:52 -0500 Subject: [PATCH 150/162] Redefine abort method --- src/code_gen/cil_builder.py | 104 +++++++++++------- src/code_gen/mips_builder.py | 18 +-- tests/{codegen => tests_ok}/primes.cl | 0 tests/{codegen => tests_ok}/primes_input.txt | 0 tests/{codegen => tests_ok}/primes_output.txt | 0 5 files changed, 75 insertions(+), 47 deletions(-) rename tests/{codegen => tests_ok}/primes.cl (100%) rename tests/{codegen => tests_ok}/primes_input.txt (100%) rename tests/{codegen => tests_ok}/primes_output.txt (100%) diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index e0bd1ecd9..6fc89d7a4 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -69,7 +69,6 @@ def __init__(self): self._count = 0 self.internal_count = 0 self.context = None - self.self_var = None self.methods = {} self.attrs = {} @@ -158,9 +157,10 @@ def add_builtin_constructors(self): self.current_function = FunctionNode( self.to_function_name("constructor", typex), [], [], [] ) - instance = self.define_internal_local() - self.register_instruction(AllocateNode(typex, instance)) - self.register_instruction(ReturnNode(instance)) + self.params.append(ParamNode("self")) + # instance = self.define_internal_local() + # self.register_instruction(AllocateNode(typex, instance)) + self.register_instruction(ReturnNode("self")) self.code.append(self.current_function) self.current_function = None @@ -169,12 +169,13 @@ def build_constructor(self, node): self.current_function = self.register_function( self.to_function_name("constructor", node.id) ) + self.params.append(ParamNode("self")) self.current_type.define_method("constructor", [], [], "Object") - self_var = self.define_internal_local() - self.self_var = self_var + # self_var = self.define_internal_local() + # self.self_var = self_var - self.register_instruction(AllocateNode(node.id, self_var)) + # self.register_instruction(AllocateNode(node.id, self_var)) attributeNodes = [ feat for feat in node.features if isinstance(feat, cool.AttrDeclarationNode) @@ -185,7 +186,7 @@ def build_constructor(self, node): self.register_instruction(DefaultValueNode(default_var, attr.type)) self.register_instruction( SetAttribNode( - self_var, + "self", self.to_attr_name(self.current_type.name, attr.id), default_var, node.id, @@ -198,30 +199,29 @@ def build_constructor(self, node): self.visit(attr.init_exp, init_expr_value) self.register_instruction( SetAttribNode( - self_var, + "self", self.to_attr_name(self.current_type.name, attr.id), init_expr_value, node.id, ) ) - self.register_instruction(ReturnNode(self_var)) + self.register_instruction(ReturnNode("self")) def add_builtin_functions(self): # Object - obj_functions = [self.cil_predef_method("abort", "Object", self.object_abort)] object_type = TypeNode("Object") object_type.attributes = [] - object_type.methods = obj_functions.copy() - object_type.methods.append( - self.cil_predef_method("copy", "Object", self.object_copy) - ) - object_type.methods.append( + object_type.methods = [ + self.cil_predef_method("abort", "Object", self.object_abort), + self.cil_predef_method("copy", "Object", self.object_copy), self.cil_predef_method("type_name", "Object", self.object_type_name) - ) + ] + # "IO" functions = [ + self.cil_predef_method("abort", "IO", self.object_abort), self.cil_predef_method("copy", "IO", self.object_copy), self.cil_predef_method("type_name", "IO", self.object_type_name), self.cil_predef_method("out_string", "IO", self.io_outstring), @@ -231,11 +231,12 @@ def add_builtin_functions(self): ] io_type = TypeNode("IO") io_type.attributes = [] - io_type.methods = obj_functions + functions + io_type.methods = functions # String self.attrs["String"] = {"length": (0, "Int"), "str_ref": (1, "String")} functions = [ + self.cil_predef_method("abort", "String", self.object_abort), self.cil_predef_method("copy", "String", self.object_copy), self.cil_predef_method("type_name", "String", self.object_type_name), self.cil_predef_method("length", "String", self.string_length), @@ -247,13 +248,14 @@ def add_builtin_functions(self): VariableInfo("length").name, VariableInfo("str_ref").name, ] - string_type.methods = obj_functions + functions + string_type.methods = functions # Int # self.attrs["Int"] = {"value": (0, "Int")} int_type = TypeNode("Int") int_type.attributes = [VariableInfo("value").name] - int_type.methods = obj_functions + [ + int_type.methods = [ + self.cil_predef_method("abort", "Int", self.object_abort), self.cil_predef_method("copy", "Int", self.object_copy), self.cil_predef_method("type_name", "Int", self.object_type_name), ] @@ -262,7 +264,8 @@ def add_builtin_functions(self): # self.attrs["Bool"] = {"value": (0, "Int")} bool_type = TypeNode("Bool") bool_type.attributes = [VariableInfo("value").name] - bool_type.methods = obj_functions + [ + bool_type.methods = [ + self.cil_predef_method("abort", "Bool", self.object_abort), self.cil_predef_method("copy", "Bool", self.object_copy), self.cil_predef_method("type_name", "Bool", self.object_type_name), ] @@ -278,7 +281,11 @@ def cil_predef_method(self, mname, cname, specif_code): self.to_function_name(mname, cname), [], [], [] ) - specif_code() + #specif_code() + if mname == "abort": #Agregado por Sandra + specif_code(cname) + else: + specif_code() self.code.append(self.current_function) self.current_function = None @@ -286,6 +293,14 @@ def cil_predef_method(self, mname, cname, specif_code): return (mname, self.to_function_name(mname, cname)) + def register_abort(self): + self.current_function = FunctionNode( + self.to_function_name("abort", self.current_type.name), [], [], [] + ) + self.object_abort(self.current_type.name) + self.code.append(self.current_function) + self.current_function = None + def register_copy(self): self.current_function = FunctionNode( self.to_function_name("copy", self.current_type.name), [], [], [] @@ -334,8 +349,12 @@ def string_substr(self): ) self.register_instruction(ReturnNode(ret_vinfo)) - def object_abort(self): - self.register_instruction(RuntimeErrorNode("ABORT_SIGNAL")) + def object_abort(self,type): + self.data.append( + DataNode(f"abort_{type}", f"Abort called from class {type}\n") + ) + error = f"abort_{type}" + self.register_instruction(RuntimeErrorNode(error)) def object_copy(self): self.params.append(ParamNode("self")) @@ -437,10 +456,11 @@ def visit(self, node, return_var=None): } self.methods[type.name] = { method.name: (i, htype.name) - if htype.name != "Object" or method.name not in ["type_name", "copy"] + if htype.name != "Object" or method.name not in ["abort","type_name", "copy"] else (i, type.name) for i, (method, htype) in enumerate(type.all_methods()) } + # print("METHODS", self.methods) # self.dottypes.append( # cil.TypeNode( # type.name, @@ -455,16 +475,20 @@ def visit(self, node, return_var=None): self.current_function = FunctionNode("main", [], [], []) self.code.append(self.current_function) - instance = self.define_internal_local() - result = self.define_internal_local() + main_constructor = self.to_function_name("constructor", "Main") main_method_name = self.to_function_name("main", "Main") # Get instance from constructor + a = self.define_internal_local() + self.register_instruction(AllocateNode("Main", a)) + self.register_instruction(ArgNode(a)) + instance= self.define_internal_local() self.register_instruction(StaticCallNode(main_constructor, instance)) # Pass instance as parameter and call Main_main + result = self.define_internal_local() self.register_instruction(ArgNode(instance)) self.register_instruction(StaticCallNode(main_method_name, result)) @@ -489,10 +513,13 @@ def visit(self, node, return_var=None): def visit(self, node, return_var=None): self.current_type = self.context.get_type(node.id) + self.register_abort() self.register_copy() self.register_type_name() type_node = self.register_type(self.current_type.name) + + self.build_constructor(node) visited_func = [] @@ -519,6 +546,14 @@ def visit(self, node, return_var=None): type_node.attributes.reverse() type_node.methods.reverse() + index = type_node.methods.index( + ("abort", self.to_function_name("abort", "Object")) + ) + type_node.methods[index] = ( + "abort", + self.to_function_name("abort", self.current_type.name), + ) + index = type_node.methods.index( ("copy", self.to_function_name("copy", "Object")) ) @@ -756,17 +791,7 @@ def get_asserted_branch(least_type:str): self.data.append( DataNode("runtime_error", "No branch can be selected for evaluation") ) - error = self.define_internal_local() - self.register_instruction( - LoadNode( - error, - VariableInfo( - "runtime_error", - None, - "No branch can be selected for evaluation", - ), - ) - ) + error = "runtime_error" self.register_instruction(RuntimeErrorNode(error)) end_case_label = "END_CASE_" + self.next_id() @@ -863,6 +888,9 @@ def visit(self, node, return_var): # Unary operators @visitor.when(cool.InstantiateNode) # NewNode def visit(self, node, return_var): + _self = self.define_internal_local() + self.register_instruction(AllocateNode(node.lex, _self)) + self.register_instruction(ArgNode(_self)) self.register_instruction( StaticCallNode(self.to_function_name("constructor", node.lex), return_var) ) diff --git a/src/code_gen/mips_builder.py b/src/code_gen/mips_builder.py index 600d40c4e..8915d68e5 100644 --- a/src/code_gen/mips_builder.py +++ b/src/code_gen/mips_builder.py @@ -25,7 +25,7 @@ FP_ARGS_DISTANCE = 3 # how far finishes $fp from arguments in method call FP_LOCALS_DISTANCE = 0 # how far finishes $fp from localvars in method call -ABORT_SIGNAL = "abort_signal" # CIL +ABORT_SIGNAL = "ABORT_SIGNAL" # CIL CASE_MISSMATCH = "case_missmatch" # CIL CASE_VOID = "case_on_void" # MIPS DISPATCH_VOID = "dispatch_on_void" # MIPS @@ -316,15 +316,15 @@ def visit(self, node): def visit(self, node): self.register_data(mips.DataTypeNode, ".asciiz", node.name, [f'"{node.value}"']) - @visitor.when(cil.ParamNode) - def visit(self, node): - self.memo.save() - reg = self.memo.get_unused_reg() + #@visitor.when(cil.ParamNode) + #def visit(self, node): + # self.memo.save() + # reg = self.memo.get_unused_reg() - self.params.append(node.name) + # self.params.append(node.name) - self.register_instruction(mips.LoadInmediate, reg, node.name) - self.register_instruction(mips.StoreWordNode, reg, len(self.params) * 4, fp) + # self.register_instruction(mips.LoadInmediate, reg, node.name) + # self.register_instruction(mips.StoreWordNode, reg, len(self.params) * 4, fp) self.memo.clean() @@ -502,7 +502,7 @@ def visit(self, node): def visit(self, node): self.register_instruction(mips.CommentNode, "Executing RuntimeError") self.register_instruction(mips.CommentNode, "Printing Abort Message") - self.register_instruction(mips.LoadAddress, a0, ABORT_SIGNAL) + self.register_instruction(mips.LoadAddress, a0, node.msg) self.register_instruction(mips.LoadInmediate, v0, SYSCALL_PRINT_STR) self.register_instruction(mips.SyscallNode) diff --git a/tests/codegen/primes.cl b/tests/tests_ok/primes.cl similarity index 100% rename from tests/codegen/primes.cl rename to tests/tests_ok/primes.cl diff --git a/tests/codegen/primes_input.txt b/tests/tests_ok/primes_input.txt similarity index 100% rename from tests/codegen/primes_input.txt rename to tests/tests_ok/primes_input.txt diff --git a/tests/codegen/primes_output.txt b/tests/tests_ok/primes_output.txt similarity index 100% rename from tests/codegen/primes_output.txt rename to tests/tests_ok/primes_output.txt From 9e29197aae964b73602d42783673a752a55d2b5f Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Thu, 10 Mar 2022 14:53:51 -0500 Subject: [PATCH 151/162] feat: add attribute constructors --- src/code_gen/cil_builder.py | 83 +++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 46 deletions(-) diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index e0bd1ecd9..6a2554c44 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -169,43 +169,27 @@ def build_constructor(self, node): self.current_function = self.register_function( self.to_function_name("constructor", node.id) ) - self.current_type.define_method("constructor", [], [], "Object") - - self_var = self.define_internal_local() - self.self_var = self_var - self.register_instruction(AllocateNode(node.id, self_var)) - - attributeNodes = [ - feat for feat in node.features if isinstance(feat, cool.AttrDeclarationNode) - ] + self.params.append(ParamNode("self")) + self.current_type.define_method("constructor", [], [], "Object") - for attr in attributeNodes: # Assign default value first - default_var = self.define_internal_local() - self.register_instruction(DefaultValueNode(default_var, attr.type)) - self.register_instruction( - SetAttribNode( - self_var, - self.to_attr_name(self.current_type.name, attr.id), - default_var, - node.id, - ) - ) - for attr in attributeNodes: # Assign init_expr if not None - if attr.init_exp: - init_expr_value = self.define_internal_local() - self.visit(attr.init_exp, init_expr_value) - self.register_instruction( - SetAttribNode( - self_var, - self.to_attr_name(self.current_type.name, attr.id), - init_expr_value, - node.id, - ) - ) + for attr, (_, typex) in self.attrs[self.current_type.name].items(): + instance = self.define_internal_local() + self.register_instruction(ArgNode("self")) + self.register_instruction(StaticCallNode( + self.to_function_name(f"{attr}_constructor",typex), + instance + )) + self.register_instruction(SetAttribNode( + "self", + self.to_attr_name(node.id, attr), + instance, + node.id + )) - self.register_instruction(ReturnNode(self_var)) + + self.register_instruction(ReturnNode("self")) def add_builtin_functions(self): # Object @@ -441,17 +425,7 @@ def visit(self, node, return_var=None): else (i, type.name) for i, (method, htype) in enumerate(type.all_methods()) } - # self.dottypes.append( - # cil.TypeNode( - # type.name, - # list(self.attrs[type.name].keys()), - # [ - # self.get_func_id(htype, method) - # for method, (_, htype) in self.methods[type.name].items() - # ], - # ) - # ) - + print("ATTRIBUTES", self.attrs) self.current_function = FunctionNode("main", [], [], []) self.code.append(self.current_function) @@ -493,7 +467,6 @@ def visit(self, node, return_var=None): self.register_type_name() type_node = self.register_type(self.current_type.name) - self.build_constructor(node) visited_func = [] current_type = self.current_type @@ -519,6 +492,8 @@ def visit(self, node, return_var=None): type_node.attributes.reverse() type_node.methods.reverse() + self.build_constructor(node) + index = type_node.methods.index( ("copy", self.to_function_name("copy", "Object")) ) @@ -539,7 +514,23 @@ def visit(self, node, return_var=None): @visitor.when(cool.AttrDeclarationNode) def visit(self, node, return_var=None): - pass + self.current_function = self.register_function(self.to_function_name(f"{node.id}_constructor", self.current_type.name)) + + self.params.append(ParamNode("self")) + + # Assign init_expr if not None + if node.init_exp: + init_expr_value = self.define_internal_local() + self.visit(node.init_exp, init_expr_value) + self.register_instruction(ReturnNode(init_expr_value)) + + else: # Assign default value + default_var = self.define_internal_local() + self.register_instruction(DefaultValueNode(default_var, node.type)) + self.register_instruction(ReturnNode(default_var)) + + self.current_function = None + @visitor.when(cool.FuncDeclarationNode) def visit(self, node, return_var=None): From 205641291139cbb399973ddf8e1079daf0ae84ec Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Thu, 10 Mar 2022 18:45:27 -0500 Subject: [PATCH 152/162] fix: inherited redefined methods --- src/code_gen/cil_builder.py | 42 +++---------------- tests/{codegen => tests_ok}/book_list.cl | 0 .../{codegen => tests_ok}/book_list_input.txt | 0 .../book_list_output.txt | 0 tests/{codegen => tests_ok}/hairyscary.cl | 0 .../hairyscary_input.txt | 0 .../hairyscary_output.txt | 0 tests/{codegen => tests_ok}/io.cl | 0 tests/{codegen => tests_ok}/io_input.txt | 0 tests/{codegen => tests_ok}/io_output.txt | 0 tests/{codegen => tests_ok}/list.cl | 0 tests/{codegen => tests_ok}/list_input.txt | 0 tests/{codegen => tests_ok}/list_output.txt | 0 tests/{codegen => tests_ok}/sort-list.cl | 0 .../{codegen => tests_ok}/sort-list_input.txt | 0 .../sort-list_output.txt | 0 16 files changed, 5 insertions(+), 37 deletions(-) rename tests/{codegen => tests_ok}/book_list.cl (100%) rename tests/{codegen => tests_ok}/book_list_input.txt (100%) rename tests/{codegen => tests_ok}/book_list_output.txt (100%) rename tests/{codegen => tests_ok}/hairyscary.cl (100%) rename tests/{codegen => tests_ok}/hairyscary_input.txt (100%) rename tests/{codegen => tests_ok}/hairyscary_output.txt (100%) rename tests/{codegen => tests_ok}/io.cl (100%) rename tests/{codegen => tests_ok}/io_input.txt (100%) rename tests/{codegen => tests_ok}/io_output.txt (100%) rename tests/{codegen => tests_ok}/list.cl (100%) rename tests/{codegen => tests_ok}/list_input.txt (100%) rename tests/{codegen => tests_ok}/list_output.txt (100%) rename tests/{codegen => tests_ok}/sort-list.cl (100%) rename tests/{codegen => tests_ok}/sort-list_input.txt (100%) rename tests/{codegen => tests_ok}/sort-list_output.txt (100%) diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index 19618dcf3..f24013083 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -490,55 +490,23 @@ def visit(self, node, return_var=None): type_node = self.register_type(self.current_type.name) - visited_func = [] current_type = self.current_type while current_type is not None: attributes = [ (node.id + "_" + attr.name) for attr in current_type.attributes ] - methods = [ - func.name - for func in current_type.methods - if func.name not in visited_func - ] - visited_func.extend(methods) + type_node.attributes.extend(attributes[::-1]) - type_node.methods.extend( - [ - (item, self.to_function_name(item, current_type.name)) - for item in methods[::-1] - ] - ) + current_type = current_type.parent type_node.attributes.reverse() - type_node.methods.reverse() + type_node.methods = [(method_name, self.to_function_name(method_name, typex)) for method_name,(_, typex) in self.methods[node.id].items()] + print(type_node.methods) self.build_constructor(node) - index = type_node.methods.index( - ("abort", self.to_function_name("abort", "Object")) - ) - type_node.methods[index] = ( - "abort", - self.to_function_name("abort", self.current_type.name), - ) - - index = type_node.methods.index( - ("copy", self.to_function_name("copy", "Object")) - ) - type_node.methods[index] = ( - "copy", - self.to_function_name("copy", self.current_type.name), - ) - - index = type_node.methods.index( - ("type_name", self.to_function_name("type_name", "Object")) - ) - type_node.methods[index] = ( - "type_name", - self.to_function_name("type_name", self.current_type.name), - ) + for feature in node.features: self.visit(feature) diff --git a/tests/codegen/book_list.cl b/tests/tests_ok/book_list.cl similarity index 100% rename from tests/codegen/book_list.cl rename to tests/tests_ok/book_list.cl diff --git a/tests/codegen/book_list_input.txt b/tests/tests_ok/book_list_input.txt similarity index 100% rename from tests/codegen/book_list_input.txt rename to tests/tests_ok/book_list_input.txt diff --git a/tests/codegen/book_list_output.txt b/tests/tests_ok/book_list_output.txt similarity index 100% rename from tests/codegen/book_list_output.txt rename to tests/tests_ok/book_list_output.txt diff --git a/tests/codegen/hairyscary.cl b/tests/tests_ok/hairyscary.cl similarity index 100% rename from tests/codegen/hairyscary.cl rename to tests/tests_ok/hairyscary.cl diff --git a/tests/codegen/hairyscary_input.txt b/tests/tests_ok/hairyscary_input.txt similarity index 100% rename from tests/codegen/hairyscary_input.txt rename to tests/tests_ok/hairyscary_input.txt diff --git a/tests/codegen/hairyscary_output.txt b/tests/tests_ok/hairyscary_output.txt similarity index 100% rename from tests/codegen/hairyscary_output.txt rename to tests/tests_ok/hairyscary_output.txt diff --git a/tests/codegen/io.cl b/tests/tests_ok/io.cl similarity index 100% rename from tests/codegen/io.cl rename to tests/tests_ok/io.cl diff --git a/tests/codegen/io_input.txt b/tests/tests_ok/io_input.txt similarity index 100% rename from tests/codegen/io_input.txt rename to tests/tests_ok/io_input.txt diff --git a/tests/codegen/io_output.txt b/tests/tests_ok/io_output.txt similarity index 100% rename from tests/codegen/io_output.txt rename to tests/tests_ok/io_output.txt diff --git a/tests/codegen/list.cl b/tests/tests_ok/list.cl similarity index 100% rename from tests/codegen/list.cl rename to tests/tests_ok/list.cl diff --git a/tests/codegen/list_input.txt b/tests/tests_ok/list_input.txt similarity index 100% rename from tests/codegen/list_input.txt rename to tests/tests_ok/list_input.txt diff --git a/tests/codegen/list_output.txt b/tests/tests_ok/list_output.txt similarity index 100% rename from tests/codegen/list_output.txt rename to tests/tests_ok/list_output.txt diff --git a/tests/codegen/sort-list.cl b/tests/tests_ok/sort-list.cl similarity index 100% rename from tests/codegen/sort-list.cl rename to tests/tests_ok/sort-list.cl diff --git a/tests/codegen/sort-list_input.txt b/tests/tests_ok/sort-list_input.txt similarity index 100% rename from tests/codegen/sort-list_input.txt rename to tests/tests_ok/sort-list_input.txt diff --git a/tests/codegen/sort-list_output.txt b/tests/tests_ok/sort-list_output.txt similarity index 100% rename from tests/codegen/sort-list_output.txt rename to tests/tests_ok/sort-list_output.txt From a4f93dc84ff8a9123e48e05dc7ab2313320f734f Mon Sep 17 00:00:00 2001 From: gabriela Date: Thu, 10 Mar 2022 21:34:10 -0500 Subject: [PATCH 153/162] Add grammar pic to report. --- img/grammar.png | Bin 28220 -> 29975 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/img/grammar.png b/img/grammar.png index f0e19e68c9b2b9268c0f272234acec7a7387522c..850b4789273d60b79ac547d528bc9b02760b21ee 100644 GIT binary patch literal 29975 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 literal 28220 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 Date: Fri, 11 Mar 2022 11:09:39 -0500 Subject: [PATCH 154/162] codegen tests passed --- src/code_gen/mips_builder.py | 91 +++++++++++++------ src/code_gen/mips_nodes.py | 8 ++ tests/code_gen.py | 2 +- tests/code_gen/hello_world.cl | 2 +- tests/code_gen/kk.cl | 23 +++++ tests/code_gen/kk_input.txt | 5 + tests/code_gen/kk_output.txt | 3 + tests/{tests_ok => codegen}/arith.cl | 0 tests/{tests_ok => codegen}/arith_input.txt | 0 tests/{tests_ok => codegen}/arith_output.txt | 0 tests/{tests_ok => codegen}/atoi.cl | 0 tests/{tests_ok => codegen}/atoi_input.txt | 0 tests/{tests_ok => codegen}/atoi_output.txt | 0 tests/{tests_ok => codegen}/book_list.cl | 0 .../{tests_ok => codegen}/book_list_input.txt | 0 .../book_list_output.txt | 0 tests/{tests_ok => codegen}/cells.cl | 0 tests/{tests_ok => codegen}/cells_input.txt | 0 tests/{tests_ok => codegen}/cells_output.txt | 0 tests/{tests_ok => codegen}/complex.cl | 0 tests/{tests_ok => codegen}/complex_input.txt | 0 .../{tests_ok => codegen}/complex_output.txt | 0 tests/{tests_ok => codegen}/fib.cl | 0 tests/{tests_ok => codegen}/fib_input.txt | 0 tests/{tests_ok => codegen}/fib_output.txt | 0 tests/{tests_ok => codegen}/hairyscary.cl | 0 .../hairyscary_input.txt | 0 .../hairyscary_output.txt | 0 tests/{tests_ok => codegen}/hello_world.cl | 0 .../hello_world_input.txt | 0 .../hello_world_output.txt | 0 tests/{tests_ok => codegen}/io.cl | 0 tests/{tests_ok => codegen}/io_input.txt | 0 tests/{tests_ok => codegen}/io_output.txt | 0 tests/{tests_ok => codegen}/life.cl | 0 tests/{tests_ok => codegen}/life_input.txt | 0 tests/{tests_ok => codegen}/life_output.txt | 0 tests/{tests_ok => codegen}/list.cl | 0 tests/{tests_ok => codegen}/list_input.txt | 0 tests/{tests_ok => codegen}/list_output.txt | 0 tests/{tests_ok => codegen}/new_complex.cl | 0 .../new_complex_input.txt | 0 .../new_complex_output.txt | 0 tests/{tests_ok => codegen}/palindrome.cl | 0 .../palindrome_input.txt | 0 .../palindrome_output.txt | 0 tests/{tests_ok => codegen}/primes.cl | 0 tests/{tests_ok => codegen}/primes_input.txt | 0 tests/{tests_ok => codegen}/primes_output.txt | 0 tests/{tests_ok => codegen}/print-cool.cl | 0 .../print-cool_input.txt | 0 .../print-cool_output.txt | 0 tests/{tests_ok => codegen}/sort-list.cl | 0 .../{tests_ok => codegen}/sort-list_input.txt | 0 .../sort-list_output.txt | 0 55 files changed, 105 insertions(+), 29 deletions(-) create mode 100644 tests/code_gen/kk.cl create mode 100644 tests/code_gen/kk_input.txt create mode 100644 tests/code_gen/kk_output.txt rename tests/{tests_ok => codegen}/arith.cl (100%) rename tests/{tests_ok => codegen}/arith_input.txt (100%) rename tests/{tests_ok => codegen}/arith_output.txt (100%) rename tests/{tests_ok => codegen}/atoi.cl (100%) rename tests/{tests_ok => codegen}/atoi_input.txt (100%) rename tests/{tests_ok => codegen}/atoi_output.txt (100%) rename tests/{tests_ok => codegen}/book_list.cl (100%) rename tests/{tests_ok => codegen}/book_list_input.txt (100%) rename tests/{tests_ok => codegen}/book_list_output.txt (100%) rename tests/{tests_ok => codegen}/cells.cl (100%) rename tests/{tests_ok => codegen}/cells_input.txt (100%) rename tests/{tests_ok => codegen}/cells_output.txt (100%) rename tests/{tests_ok => codegen}/complex.cl (100%) rename tests/{tests_ok => codegen}/complex_input.txt (100%) rename tests/{tests_ok => codegen}/complex_output.txt (100%) rename tests/{tests_ok => codegen}/fib.cl (100%) rename tests/{tests_ok => codegen}/fib_input.txt (100%) rename tests/{tests_ok => codegen}/fib_output.txt (100%) rename tests/{tests_ok => codegen}/hairyscary.cl (100%) rename tests/{tests_ok => codegen}/hairyscary_input.txt (100%) rename tests/{tests_ok => codegen}/hairyscary_output.txt (100%) rename tests/{tests_ok => codegen}/hello_world.cl (100%) rename tests/{tests_ok => codegen}/hello_world_input.txt (100%) rename tests/{tests_ok => codegen}/hello_world_output.txt (100%) rename tests/{tests_ok => codegen}/io.cl (100%) rename tests/{tests_ok => codegen}/io_input.txt (100%) rename tests/{tests_ok => codegen}/io_output.txt (100%) rename tests/{tests_ok => codegen}/life.cl (100%) rename tests/{tests_ok => codegen}/life_input.txt (100%) rename tests/{tests_ok => codegen}/life_output.txt (100%) rename tests/{tests_ok => codegen}/list.cl (100%) rename tests/{tests_ok => codegen}/list_input.txt (100%) rename tests/{tests_ok => codegen}/list_output.txt (100%) rename tests/{tests_ok => codegen}/new_complex.cl (100%) rename tests/{tests_ok => codegen}/new_complex_input.txt (100%) rename tests/{tests_ok => codegen}/new_complex_output.txt (100%) rename tests/{tests_ok => codegen}/palindrome.cl (100%) rename tests/{tests_ok => codegen}/palindrome_input.txt (100%) rename tests/{tests_ok => codegen}/palindrome_output.txt (100%) rename tests/{tests_ok => codegen}/primes.cl (100%) rename tests/{tests_ok => codegen}/primes_input.txt (100%) rename tests/{tests_ok => codegen}/primes_output.txt (100%) rename tests/{tests_ok => codegen}/print-cool.cl (100%) rename tests/{tests_ok => codegen}/print-cool_input.txt (100%) rename tests/{tests_ok => codegen}/print-cool_output.txt (100%) rename tests/{tests_ok => codegen}/sort-list.cl (100%) rename tests/{tests_ok => codegen}/sort-list_input.txt (100%) rename tests/{tests_ok => codegen}/sort-list_output.txt (100%) diff --git a/src/code_gen/mips_builder.py b/src/code_gen/mips_builder.py index 8915d68e5..ff4a2ca3f 100644 --- a/src/code_gen/mips_builder.py +++ b/src/code_gen/mips_builder.py @@ -4,6 +4,7 @@ # from tkinter.tix import Select # from soupsieve import select +from soupsieve import select import cmp.visitor as visitor import cmp.cil as cil import random @@ -177,7 +178,7 @@ def generate_exception_messages(self): def generate_extra_static_labels(self): self.register_data(mips.DataTypeNode, ".word", VOID, [-1]) - self.register_data(mips.DataTypeNode, ".asciiz", EMPTY_STRING, ['""']) + self.register_data(mips.DataTypeNode, ".asciiz", EMPTY_STRING, ['"\"\""']) self.register_data(mips.DataTypeNode, ".space", INPUT_STR_BUFFER, [BUFFER_SIZE]) def generate_attr_offset(self, type): @@ -200,8 +201,8 @@ def generate_str_length(self): self.register_instruction(mips.LoadByteNode, reg2, 0, a0) self.register_instruction(mips.BranchOnEqualNode, zero, reg2, "length_end") - self.register_instruction(mips.AddNode, reg1, reg1, 1) - self.register_instruction(mips.AddNode, a0, a0, 1) + self.register_instruction(mips.AddiNode, reg1, reg1, 1) + self.register_instruction(mips.AddiNode, a0, a0, 1) self.register_instruction(mips.Jump, "length_loop") self.register_instruction(mips.Label, "length_end") @@ -215,6 +216,9 @@ def generate_copy(self): # copies from t1 to t6 a0 bytes self.memo.save() self.current_procedure = mips.ProcedureNode(COPY) + #r = self.memo.get_unused_reg() + #self.register_instruction(mips.LoadInmediate,r,-1) + #self.register_instruction(mips.BranchOnEqualNode,r,a0,"copy_end") self.register_instruction(mips.Label, "copy_loop") self.register_instruction(mips.BranchOnEqualNode, zero, a0, "copy_end") @@ -229,17 +233,51 @@ def generate_copy(self): self.register_instruction(mips.Jump, ra) self.text.append(self.current_procedure) + self.memo.clean() + + + def generate_input(self): + # copies from t7 to t6 a0 bytes + self.memo.save() + reg4 = self.memo.get_unused_reg() + reg5 = self.memo.get_unused_reg() + + self.current_procedure = mips.ProcedureNode("Input") + + self.register_instruction(mips.Label, "input_loop") + + self.register_instruction(mips.LoadByteNode, t8, 0, t7) + self.register_instruction(mips.StoreByteNode, t8, 0, t6) + + self.register_instruction(mips.AddiNode, t6, t6, 1) + self.register_instruction(mips.AddiNode, t7, t7, 1) + self.register_instruction(mips.BranchOnGreaterZero,t8,"input_loop") + self.register_instruction(mips.AddiNode,t6,t6,-2) + + self.register_instruction(mips.LoadInmediate,reg4,10) + self.register_instruction(mips.LoadByteNode,reg5,0,t6) + self.register_instruction(mips.BranchOnNotEqualNode,reg4,reg5,"input_end") + self.register_instruction(mips.LoadInmediate,t8,0) + self.register_instruction(mips.StoreByteNode,t8,0,t6) + + self.register_instruction(mips.Label, "input_end") + self.register_instruction(mips.Jump, ra) + + self.text.append(self.current_procedure) + + + def generate_str_cmp(self): self.current_procedure = mips.ProcedureNode(STR_CMP) - #comparing lengths - self.register_instruction(mips.CommentNode, "Comparing lengths") - self.register_instruction(mips.LoadWordNode, s0, LENGTH_ATTR_OFFSET, t6) #length offset - self.register_instruction(mips.LoadWordNode, s1, LENGTH_ATTR_OFFSET, t7) - self.register_instruction(mips.SetEq,a0,s0,s1) - - self.register_instruction(mips.BranchOnEqZero,a0,"end_loop") + ##comparing lengths + #self.register_instruction(mips.CommentNode, "Comparing lengths") + #self.register_instruction(mips.LoadWordNode, s0, LENGTH_ATTR_OFFSET, t6) #length offset + #self.register_instruction(mips.LoadWordNode, s1, LENGTH_ATTR_OFFSET, t7) + #self.register_instruction(mips.SetEq,a0,s0,s1) + # + #self.register_instruction(mips.BranchOnEqZero,a0,"end_loop") #comparing char by char self.register_instruction(mips.CommentNode, "Comparing char by char") @@ -274,6 +312,7 @@ def generate_auxiliar_procedures(self): self.generate_str_length() self.generate_copy() self.generate_str_cmp() + self.generate_input() @visitor.on("node") def visit(self, node=None): @@ -316,17 +355,7 @@ def visit(self, node): def visit(self, node): self.register_data(mips.DataTypeNode, ".asciiz", node.name, [f'"{node.value}"']) - #@visitor.when(cil.ParamNode) - #def visit(self, node): - # self.memo.save() - # reg = self.memo.get_unused_reg() - - # self.params.append(node.name) - - # self.register_instruction(mips.LoadInmediate, reg, node.name) - # self.register_instruction(mips.StoreWordNode, reg, len(self.params) * 4, fp) - self.memo.clean() @visitor.when(cil.ArgNode) def visit(self, node): @@ -991,9 +1020,12 @@ def visit(self,node): self.register_instruction(mips.CommentNode, "Calculating str length") self.register_instruction(mips.JumpAndLink, LENGTH) + reg4 = self.memo.get_unused_reg() + self.register_instruction(mips.MoveNode, reg4, a0) # saving length self.register_instruction( mips.CommentNode, "Allocating char array for new string" ) + self.register_instruction(mips.AddNode, a0, a0, 1) ####?????????? self.register_instruction(mips.LoadInmediate, v0, SYSCALL_SBRK) self.register_instruction(mips.SyscallNode) @@ -1004,18 +1036,22 @@ def visit(self,node): mips.MoveNode, reg3, v0 ) # saving pointer to char array - reg4 = self.memo.get_unused_reg() - self.register_instruction(mips.AddNode, a0, a0, -1) ####?????????? - self.register_instruction(mips.MoveNode, reg4, a0) # saving length + + + #self.register_instruction(mips.AddNode, a0, a0, -1) ####?????????? + + self.register_instruction( mips.CommentNode, "Copying bytes from one char array to another" ) - self.register_instruction(mips.JumpAndLink, COPY) - - self.register_instruction(mips.CommentNode, "Null-terminating the string") - self.register_instruction(mips.StoreByteNode, zero, 0, t6) + self.register_instruction(mips.JumpAndLink, "Input") + + + #self.register_instruction(mips.CommentNode, "Null-terminating the string") + #self.register_instruction(mips.StoreByteNode, zero, 0, t6) + self.register_instruction(mips.CommentNode, "Allocating new String instance") _size = STRING_SIZE self.register_instruction(mips.LoadInmediate, v0, SYSCALL_SBRK) @@ -1033,6 +1069,7 @@ def visit(self,node): self.register_instruction( mips.CommentNode, "Storing length and reference to char array" ) + self.register_instruction(mips.AddiNode,reg4,reg4,-1) self.register_instruction(mips.StoreWordNode, reg4, LENGTH_ATTR_OFFSET, v0) # storing string chars ref diff --git a/src/code_gen/mips_nodes.py b/src/code_gen/mips_nodes.py index 9c41da371..2e8288b89 100644 --- a/src/code_gen/mips_nodes.py +++ b/src/code_gen/mips_nodes.py @@ -222,6 +222,14 @@ def __init__(self,reg,label): def __str__(self): return f'beqz {self.reg}, {self.label}' + +class BranchOnGreaterZero(InstructionNode): + def __init__(self,reg,label): + self.reg = reg + self.label = label + + def __str__(self): + return f'bgtz {self.reg}, {self.label}' diff --git a/tests/code_gen.py b/tests/code_gen.py index c59d4317a..32fd9d438 100644 --- a/tests/code_gen.py +++ b/tests/code_gen.py @@ -4,7 +4,7 @@ tests_dir = __file__.rpartition("/")[0] + "/codegen/" -tests = [(file) for file in os.listdir(tests_dir) if file.endswith("hairyscary.cl")] +tests = [(file) for file in os.listdir(tests_dir) if file.endswith(".cl")] # @pytest.mark.lexer # @pytest.mark.parser diff --git a/tests/code_gen/hello_world.cl b/tests/code_gen/hello_world.cl index b41b36c81..eafc79020 100644 --- a/tests/code_gen/hello_world.cl +++ b/tests/code_gen/hello_world.cl @@ -1,5 +1,5 @@ class Main inherits IO { main(): IO { - out_string("Hello, World.\n") + out_string(in_string()) }; }; \ No newline at end of file diff --git a/tests/code_gen/kk.cl b/tests/code_gen/kk.cl new file mode 100644 index 000000000..223a18c53 --- /dev/null +++ b/tests/code_gen/kk.cl @@ -0,0 +1,23 @@ +class Main inherits IO { + boolop : BoolOp <- new BoolOp; + main(): Object { + + let a:Int <- 0 ,line : String <- in_string() in + while (boolop.and(not line="\n", not line.length()=1)) loop { + a <- a+1; + out_int(line.length()); + line <- in_string(); + + } pool + + }; +}; + +class BoolOp { + + and(b1 : Bool, b2 : Bool) : Bool { + if b1 then b2 else false fi + }; + + +}; diff --git a/tests/code_gen/kk_input.txt b/tests/code_gen/kk_input.txt new file mode 100644 index 000000000..b67d90210 --- /dev/null +++ b/tests/code_gen/kk_input.txt @@ -0,0 +1,5 @@ +1 2,100 +2 3,200 1,150 +3 2,10 +4 3,55 5,100 +5 1,1 2,2 3,3 4,4 5,5 diff --git a/tests/code_gen/kk_output.txt b/tests/code_gen/kk_output.txt new file mode 100644 index 000000000..162a54bf5 --- /dev/null +++ b/tests/code_gen/kk_output.txt @@ -0,0 +1,3 @@ +a +d + diff --git a/tests/tests_ok/arith.cl b/tests/codegen/arith.cl similarity index 100% rename from tests/tests_ok/arith.cl rename to tests/codegen/arith.cl diff --git a/tests/tests_ok/arith_input.txt b/tests/codegen/arith_input.txt similarity index 100% rename from tests/tests_ok/arith_input.txt rename to tests/codegen/arith_input.txt diff --git a/tests/tests_ok/arith_output.txt b/tests/codegen/arith_output.txt similarity index 100% rename from tests/tests_ok/arith_output.txt rename to tests/codegen/arith_output.txt diff --git a/tests/tests_ok/atoi.cl b/tests/codegen/atoi.cl similarity index 100% rename from tests/tests_ok/atoi.cl rename to tests/codegen/atoi.cl diff --git a/tests/tests_ok/atoi_input.txt b/tests/codegen/atoi_input.txt similarity index 100% rename from tests/tests_ok/atoi_input.txt rename to tests/codegen/atoi_input.txt diff --git a/tests/tests_ok/atoi_output.txt b/tests/codegen/atoi_output.txt similarity index 100% rename from tests/tests_ok/atoi_output.txt rename to tests/codegen/atoi_output.txt diff --git a/tests/tests_ok/book_list.cl b/tests/codegen/book_list.cl similarity index 100% rename from tests/tests_ok/book_list.cl rename to tests/codegen/book_list.cl diff --git a/tests/tests_ok/book_list_input.txt b/tests/codegen/book_list_input.txt similarity index 100% rename from tests/tests_ok/book_list_input.txt rename to tests/codegen/book_list_input.txt diff --git a/tests/tests_ok/book_list_output.txt b/tests/codegen/book_list_output.txt similarity index 100% rename from tests/tests_ok/book_list_output.txt rename to tests/codegen/book_list_output.txt diff --git a/tests/tests_ok/cells.cl b/tests/codegen/cells.cl similarity index 100% rename from tests/tests_ok/cells.cl rename to tests/codegen/cells.cl diff --git a/tests/tests_ok/cells_input.txt b/tests/codegen/cells_input.txt similarity index 100% rename from tests/tests_ok/cells_input.txt rename to tests/codegen/cells_input.txt diff --git a/tests/tests_ok/cells_output.txt b/tests/codegen/cells_output.txt similarity index 100% rename from tests/tests_ok/cells_output.txt rename to tests/codegen/cells_output.txt diff --git a/tests/tests_ok/complex.cl b/tests/codegen/complex.cl similarity index 100% rename from tests/tests_ok/complex.cl rename to tests/codegen/complex.cl diff --git a/tests/tests_ok/complex_input.txt b/tests/codegen/complex_input.txt similarity index 100% rename from tests/tests_ok/complex_input.txt rename to tests/codegen/complex_input.txt diff --git a/tests/tests_ok/complex_output.txt b/tests/codegen/complex_output.txt similarity index 100% rename from tests/tests_ok/complex_output.txt rename to tests/codegen/complex_output.txt diff --git a/tests/tests_ok/fib.cl b/tests/codegen/fib.cl similarity index 100% rename from tests/tests_ok/fib.cl rename to tests/codegen/fib.cl diff --git a/tests/tests_ok/fib_input.txt b/tests/codegen/fib_input.txt similarity index 100% rename from tests/tests_ok/fib_input.txt rename to tests/codegen/fib_input.txt diff --git a/tests/tests_ok/fib_output.txt b/tests/codegen/fib_output.txt similarity index 100% rename from tests/tests_ok/fib_output.txt rename to tests/codegen/fib_output.txt diff --git a/tests/tests_ok/hairyscary.cl b/tests/codegen/hairyscary.cl similarity index 100% rename from tests/tests_ok/hairyscary.cl rename to tests/codegen/hairyscary.cl diff --git a/tests/tests_ok/hairyscary_input.txt b/tests/codegen/hairyscary_input.txt similarity index 100% rename from tests/tests_ok/hairyscary_input.txt rename to tests/codegen/hairyscary_input.txt diff --git a/tests/tests_ok/hairyscary_output.txt b/tests/codegen/hairyscary_output.txt similarity index 100% rename from tests/tests_ok/hairyscary_output.txt rename to tests/codegen/hairyscary_output.txt diff --git a/tests/tests_ok/hello_world.cl b/tests/codegen/hello_world.cl similarity index 100% rename from tests/tests_ok/hello_world.cl rename to tests/codegen/hello_world.cl diff --git a/tests/tests_ok/hello_world_input.txt b/tests/codegen/hello_world_input.txt similarity index 100% rename from tests/tests_ok/hello_world_input.txt rename to tests/codegen/hello_world_input.txt diff --git a/tests/tests_ok/hello_world_output.txt b/tests/codegen/hello_world_output.txt similarity index 100% rename from tests/tests_ok/hello_world_output.txt rename to tests/codegen/hello_world_output.txt diff --git a/tests/tests_ok/io.cl b/tests/codegen/io.cl similarity index 100% rename from tests/tests_ok/io.cl rename to tests/codegen/io.cl diff --git a/tests/tests_ok/io_input.txt b/tests/codegen/io_input.txt similarity index 100% rename from tests/tests_ok/io_input.txt rename to tests/codegen/io_input.txt diff --git a/tests/tests_ok/io_output.txt b/tests/codegen/io_output.txt similarity index 100% rename from tests/tests_ok/io_output.txt rename to tests/codegen/io_output.txt diff --git a/tests/tests_ok/life.cl b/tests/codegen/life.cl similarity index 100% rename from tests/tests_ok/life.cl rename to tests/codegen/life.cl diff --git a/tests/tests_ok/life_input.txt b/tests/codegen/life_input.txt similarity index 100% rename from tests/tests_ok/life_input.txt rename to tests/codegen/life_input.txt diff --git a/tests/tests_ok/life_output.txt b/tests/codegen/life_output.txt similarity index 100% rename from tests/tests_ok/life_output.txt rename to tests/codegen/life_output.txt diff --git a/tests/tests_ok/list.cl b/tests/codegen/list.cl similarity index 100% rename from tests/tests_ok/list.cl rename to tests/codegen/list.cl diff --git a/tests/tests_ok/list_input.txt b/tests/codegen/list_input.txt similarity index 100% rename from tests/tests_ok/list_input.txt rename to tests/codegen/list_input.txt diff --git a/tests/tests_ok/list_output.txt b/tests/codegen/list_output.txt similarity index 100% rename from tests/tests_ok/list_output.txt rename to tests/codegen/list_output.txt diff --git a/tests/tests_ok/new_complex.cl b/tests/codegen/new_complex.cl similarity index 100% rename from tests/tests_ok/new_complex.cl rename to tests/codegen/new_complex.cl diff --git a/tests/tests_ok/new_complex_input.txt b/tests/codegen/new_complex_input.txt similarity index 100% rename from tests/tests_ok/new_complex_input.txt rename to tests/codegen/new_complex_input.txt diff --git a/tests/tests_ok/new_complex_output.txt b/tests/codegen/new_complex_output.txt similarity index 100% rename from tests/tests_ok/new_complex_output.txt rename to tests/codegen/new_complex_output.txt diff --git a/tests/tests_ok/palindrome.cl b/tests/codegen/palindrome.cl similarity index 100% rename from tests/tests_ok/palindrome.cl rename to tests/codegen/palindrome.cl diff --git a/tests/tests_ok/palindrome_input.txt b/tests/codegen/palindrome_input.txt similarity index 100% rename from tests/tests_ok/palindrome_input.txt rename to tests/codegen/palindrome_input.txt diff --git a/tests/tests_ok/palindrome_output.txt b/tests/codegen/palindrome_output.txt similarity index 100% rename from tests/tests_ok/palindrome_output.txt rename to tests/codegen/palindrome_output.txt diff --git a/tests/tests_ok/primes.cl b/tests/codegen/primes.cl similarity index 100% rename from tests/tests_ok/primes.cl rename to tests/codegen/primes.cl diff --git a/tests/tests_ok/primes_input.txt b/tests/codegen/primes_input.txt similarity index 100% rename from tests/tests_ok/primes_input.txt rename to tests/codegen/primes_input.txt diff --git a/tests/tests_ok/primes_output.txt b/tests/codegen/primes_output.txt similarity index 100% rename from tests/tests_ok/primes_output.txt rename to tests/codegen/primes_output.txt diff --git a/tests/tests_ok/print-cool.cl b/tests/codegen/print-cool.cl similarity index 100% rename from tests/tests_ok/print-cool.cl rename to tests/codegen/print-cool.cl diff --git a/tests/tests_ok/print-cool_input.txt b/tests/codegen/print-cool_input.txt similarity index 100% rename from tests/tests_ok/print-cool_input.txt rename to tests/codegen/print-cool_input.txt diff --git a/tests/tests_ok/print-cool_output.txt b/tests/codegen/print-cool_output.txt similarity index 100% rename from tests/tests_ok/print-cool_output.txt rename to tests/codegen/print-cool_output.txt diff --git a/tests/tests_ok/sort-list.cl b/tests/codegen/sort-list.cl similarity index 100% rename from tests/tests_ok/sort-list.cl rename to tests/codegen/sort-list.cl diff --git a/tests/tests_ok/sort-list_input.txt b/tests/codegen/sort-list_input.txt similarity index 100% rename from tests/tests_ok/sort-list_input.txt rename to tests/codegen/sort-list_input.txt diff --git a/tests/tests_ok/sort-list_output.txt b/tests/codegen/sort-list_output.txt similarity index 100% rename from tests/tests_ok/sort-list_output.txt rename to tests/codegen/sort-list_output.txt From 98a3fc04e7c2a3d168b0b73801fff144bb0fe4f0 Mon Sep 17 00:00:00 2001 From: smartos99 Date: Fri, 11 Mar 2022 11:10:44 -0500 Subject: [PATCH 155/162] delete unnecesary imports --- src/code_gen/mips_builder.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/code_gen/mips_builder.py b/src/code_gen/mips_builder.py index ff4a2ca3f..107e4f8cf 100644 --- a/src/code_gen/mips_builder.py +++ b/src/code_gen/mips_builder.py @@ -4,7 +4,6 @@ # from tkinter.tix import Select # from soupsieve import select -from soupsieve import select import cmp.visitor as visitor import cmp.cil as cil import random @@ -271,13 +270,6 @@ def generate_input(self): def generate_str_cmp(self): self.current_procedure = mips.ProcedureNode(STR_CMP) - ##comparing lengths - #self.register_instruction(mips.CommentNode, "Comparing lengths") - #self.register_instruction(mips.LoadWordNode, s0, LENGTH_ATTR_OFFSET, t6) #length offset - #self.register_instruction(mips.LoadWordNode, s1, LENGTH_ATTR_OFFSET, t7) - #self.register_instruction(mips.SetEq,a0,s0,s1) - # - #self.register_instruction(mips.BranchOnEqZero,a0,"end_loop") #comparing char by char self.register_instruction(mips.CommentNode, "Comparing char by char") From 22d8a267b91b9cd4c269619fdb15b7c0567832e8 Mon Sep 17 00:00:00 2001 From: smartos99 Date: Fri, 11 Mar 2022 11:56:46 -0500 Subject: [PATCH 156/162] remove unnecesary files --- tests/code_gen.py | 22 ---------------------- tests/test_1file.py | 22 ---------------------- 2 files changed, 44 deletions(-) delete mode 100644 tests/code_gen.py delete mode 100644 tests/test_1file.py diff --git a/tests/code_gen.py b/tests/code_gen.py deleted file mode 100644 index 32fd9d438..000000000 --- a/tests/code_gen.py +++ /dev/null @@ -1,22 +0,0 @@ -import pytest -import os -from utils import compare_outputs - - -tests_dir = __file__.rpartition("/")[0] + "/codegen/" -tests = [(file) for file in os.listdir(tests_dir) if file.endswith(".cl")] - -# @pytest.mark.lexer -# @pytest.mark.parser -# @pytest.mark.semantic -@pytest.mark.codegen -@pytest.mark.ok -@pytest.mark.run(order=4) -@pytest.mark.parametrize("cool_file", tests) -def test_codegen(compiler_path, cool_file): - compare_outputs( - compiler_path, - tests_dir + cool_file, - tests_dir + cool_file[:-3] + "_input.txt", - tests_dir + cool_file[:-3] + "_output.txt", - ) diff --git a/tests/test_1file.py b/tests/test_1file.py deleted file mode 100644 index ecaf7144c..000000000 --- a/tests/test_1file.py +++ /dev/null @@ -1,22 +0,0 @@ -import pytest -import os -from utils import compare_errors, first_error_only_line - -# tests_dir = __file__.rpartition('/')[0] + '/semantic/' -# tests = [(file) for file in os.listdir(tests_dir) if file.endswith('self4.cl')] - -tests_dir = __file__.rpartition("/")[0] + "/codegen/" -tests = [(file) for file in os.listdir(tests_dir) if file.endswith("hello_world.cl")] - - -@pytest.mark.semantic -@pytest.mark.error -@pytest.mark.run(order=3) -@pytest.mark.parametrize("cool_file", tests) -def test_semantic_errors(compiler_path, cool_file): - compare_errors( - compiler_path, - tests_dir + cool_file, - tests_dir + cool_file[:-3] + "_error.txt", - cmp=first_error_only_line, - ) From 2780b9c609b888b0a9a35a4238c8ac7736b1e4e6 Mon Sep 17 00:00:00 2001 From: gabriela Date: Fri, 11 Mar 2022 13:40:37 -0500 Subject: [PATCH 157/162] Add self type checking in Case Node. --- src/type_checker.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/type_checker.py b/src/type_checker.py index c3915a3e3..5d4b1435a 100644 --- a/src/type_checker.py +++ b/src/type_checker.py @@ -458,6 +458,10 @@ def visit(self, node, scope): @visitor.when(CaseItemNode) def visit(self, node, scope): + if node.id.lex == "self": + node_row, node_col = node.id.location + self.errors.append(SemanticError(node_row, node_col, "'self' cannot be bound in a 'case' expression. " + SELF_IS_READONLY)) + try: static_type = self.context.get_type(node.type.lex) scope.define_variable(node.id.lex, static_type) From bed772aa21ac130a3c88717e15c19aacf843190a Mon Sep 17 00:00:00 2001 From: gabriela Date: Fri, 11 Mar 2022 14:59:36 -0500 Subject: [PATCH 158/162] Ensure "comp" expr does not associate. --- src/cool_grammar.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/cool_grammar.py b/src/cool_grammar.py index 1bdc2a8c1..25e416b43 100644 --- a/src/cool_grammar.py +++ b/src/cool_grammar.py @@ -118,12 +118,12 @@ def define_cool_grammar(print_grammar=False): ) identifier_init %= idx + colon + type_id, lambda h, s: VarDeclarationNode(s[1], s[3]) - comp %= comp + less + arith, lambda h, s: LessNode(s[1], s[3], s[2]) # this expression do not associate, so call comp instead of arith - comp %= comp + less + notx + arith, lambda h, s: LessNode(s[1], NotNode(s[4], s[3]) , s[2]) - comp %= comp + equal + arith, lambda h, s: EqualNode(s[1], s[3], s[2]) - comp %= comp + equal + notx + arith, lambda h, s: EqualNode(s[1], NotNode(s[4], s[3]) , s[2]) - comp %= comp + lesseq + arith, lambda h, s: LessEqualNode(s[1], s[3], s[2]) - comp %= comp + lesseq + notx + arith, lambda h, s: LessEqualNode(s[1], NotNode(s[4], s[3]) , s[2]) + comp %= arith + less + arith, lambda h, s: LessNode(s[1], s[3], s[2]) + comp %= arith + less + notx + expr, lambda h, s: LessNode(s[1], NotNode(s[4], s[3]) , s[2]) + comp %= arith + equal + arith, lambda h, s: EqualNode(s[1], s[3], s[2]) + comp %= arith + equal + notx + expr, lambda h, s: EqualNode(s[1], NotNode(s[4], s[3]) , s[2]) + comp %= arith + lesseq + arith, lambda h, s: LessEqualNode(s[1], s[3], s[2]) + comp %= arith + lesseq + notx + expr, lambda h, s: LessEqualNode(s[1], NotNode(s[4], s[3]) , s[2]) comp %= arith, lambda h, s: s[1] arith %= arith + plus + term, lambda h, s: PlusNode(s[1], s[3], s[2]) From bf476ca0bc5e4ba0968758b25ec0e307bf29112d Mon Sep 17 00:00:00 2001 From: Amalia Ibarra Date: Fri, 11 Mar 2022 15:34:39 -0500 Subject: [PATCH 159/162] feat: add cool to cil section to report --- doc/Report.md | 122 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 82 insertions(+), 40 deletions(-) diff --git a/doc/Report.md b/doc/Report.md index 829919c93..0918e2ec5 100644 --- a/doc/Report.md +++ b/doc/Report.md @@ -1,16 +1,15 @@ ## Introducción -Cool(Classroom Object-Oriented Language) es un lenguaje de programación orientado a -objetos que, aunque pequeño, tiene muchas caracterı́sticas relevantes de lenguajes modernos. Su orientación a objetos, su tipado dinámico y el resto de sus features lo hacen muy atractivo e ideal para un primer acercamiento al mundo de los Compiladores. +COOL(Classroom Object-Oriented Language) es un lenguaje de programación orientado a +objetos que, aunque pequeño, tiene muchas caracterı́sticas relevantes de lenguajes modernos. Su orientación a objetos, su tipado dinámico y el resto de sus features lo hacen muy atractivo e ideal para un primer acercamiento al mundo de los Compiladores. -En el presente trabajo se muestra una implementación de un Compilador funcional para Cool en el lenguaje de programación python; los llamamos: *El Compi*. - -En las próximas secciones se explican en detalle cada una de las fases en las que se divide el trabajo del mismo, como fue abordada cada una, las instrucciones para su uso y algunos otros detalles importantes a resaltar. +En el presente trabajo se muestra una implementación de un Compilador funcional para COOL en el lenguaje de programación Python; lo llamamos: _El Compi_. +En las próximas secciones se explican en detalle cada una de las fases en las que se divide el trabajo del mismo, cómo fue abordada cada una, las instrucciones para su uso y algunos otros detalles importantes a resaltar. ## Requerimientos e instrucciones para la ejecución -Para utilizar *El Compi* y ejecutar un programa en el lenguaje cool se han de seguir los siguientes pasos: +Para utilizar _El Compi_ y ejecutar un programa en el lenguaje COOL se han de seguir los siguientes pasos: 1- Primero se debe verificar que se cuente con todas las dependencias necesarias. Para una rápida instalación de estas se puede correr el comando: @@ -18,25 +17,27 @@ Para utilizar *El Compi* y ejecutar un programa en el lenguaje cool se han de se $ pip install -r requirements.txt ``` -2- Para compilador un código dado en Cool a ensamblador, ejecute: +2- Para compilar un código dado en COOL a ensamblador, ejecute: ```bash $ ./coolc.sh ``` -en una consola centrada en el directorio *src* que se encuentra en la raiz del proyecto. Aquí sería un archivo escrito en cool. -3- El *output* esperado (en caso de no haberse detectado ningún error) es un archivo con el mismo nombre pero en .mips, el cual debe correrse con el correspondiente intérprete: +en una consola centrada en el directorio _src_ que se encuentra en la raiz del proyecto. Aquí sería un archivo escrito en cool. + +3- El _output_ esperado (en caso de no haberse detectado ningún error) es un archivo con el mismo nombre pero en .mips, el cual debe correrse con el correspondiente intérprete: ```bash $ spim -file ``` + que finalmente nos mostrará el resultado generado por el programa de entrada (spim se encuentra entre los requirements especificados). -Si se encuentran errores en el código de Cool proporcionado, el compilador los listará en consola, proporcionando detalles sobre su localización y tipo. Para más información sobre los errores de Cool manejados remitirse al README.md de la carpeta *src*. +Si se encuentran errores en el código de Cool proporcionado, el compilador los listará en consola, proporcionando detalles sobre su localización y tipo. Para más información sobre los errores de Cool manejados remitirse al README.md de la carpeta _src_. -## Arquitectura del compilador: +## Arquitectura del compilador: -*El Compi*, para tener la funcionalidad completa de un compilador, transita por las fases fundamentales de: +_El Compi_, para tener la funcionalidad completa de un compilador, transita por las fases fundamentales de: -Análisis sintáctico (Análisis léxico y parsing) @@ -44,70 +45,71 @@ Si se encuentran errores en el código de Cool proporcionado, el compilador los -Generación de código (Traducción a un lenguaje intermedio y generación del correspondiente código mips) -Más adelante se analizan con más profundidad cada una. +Más adelante se analizan a profundidad cada una. -El código fuente del proyecto se encuentra en la carpeta *src*. En esta se hallan distribuidos los scripts según su funcionalidad. +El código fuente del proyecto se encuentra en la carpeta _src_. En esta se hallan distribuidos los scripts según su funcionalidad. -**FOTO de los archivos del proyecto** +**FOTO de los archivos del proyecto** -Si lo miramos como módulos, podemos decir que el módulo de lexe... en *code_gen* encontramos todo lo referente al proceso de generación de código... en tools todo los utils para... +Si lo miramos como módulos, podemos decir que el módulo de lexe... en _code_gen_ encontramos todo lo referente al proceso de generación de código... en tools todo los utils para... **COMPLETAR** -Analicemos ahora los prometidos detalles de implementacion y diseño tan anunciados. +Analicemos ahora los prometidos detalles de implementacion y diseño tan anunciados. ## Gramática -El primer paso para acercarnos al lenguaje objeto de análisis fue definir una gramática adecuada. Siguiendo lo referido por el manual de Cool (el cual se encuentra adjunto en la carpeta *doc*, con el resto de la documentación), se diseñó una gramática que respetara la precedencia necesaria de los operadores y la estructura requerida. En el archivo cool grammar.py puede observarse como fue modelada la misma. + +El primer paso para acercarnos al lenguaje objeto de análisis fue definir una gramática adecuada. Siguiendo lo referido por el manual de Cool (el cual se encuentra adjunto en la carpeta _doc_, con el resto de la documentación), se diseñó una gramática que respetara la precedencia necesaria de los operadores y la estructura requerida. En el archivo cool grammar.py puede observarse como fue modelada la misma. Como ahí se puede apreciar, un programa de Cool consiste en una serie de definiciones de clases. Cada clase a su vez posee un conjunto de atributos y de funciones. Las expresiones que pueden formar parte de dichas funciones son el corazón del lenguaje. -En la imagen *1* se pueden apreciar varios niveles intermedios de esta gramática, lo cuales, precisamente, definen diferentes tipos de expresiones: +En la imagen _1_ se pueden apreciar varios niveles intermedios de esta gramática, lo cuales, precisamente, definen diferentes tipos de expresiones: 1. **< comp >** , que representa las operaciones de comparación entre elementos. 2. **< arith >** , que engloba a las operaciones de suma y -resta. + resta. 3. **< term >** , para la multiplicación y división. 4. **< factor >** , como representación de los operadores -unarios isvoid y opuesto. + unarios isvoid y opuesto. -5. **< element >** para las condicionales (*if-then-else*, *while* y *case*), la instanciación con *new*, las expresiones entre paréntsis, los block, los dispatch. +5. **< element >** para las condicionales (_if-then-else_, _while_ y _case_), la instanciación con _new_, las expresiones entre paréntsis, los block, los dispatch. -6. **< atom >** como el nivel más básico, donde se ex- -cuentran los números, ids, las expresiones boolea- -nas y los strings. +6. **< atom >** como el nivel más básico, donde se ex- + cuentran los números, ids, las expresiones boolea- + nas y los strings. ![Figura 1.!](../img/grammar.png "Fragmento de la gramática de Cool.") - ## Análisis sintáctico -### Tokenizer -Para tokenizar la entrada se utilizó una herramienta bastante útil y práctica: [PLY](https://www.dabeaz.com/ply/ply.html), la cual consiste en una implementación en python de las herramientas de parsing *Lex* y *Yacc*. Mediante el módulo lex que esta provee, es posible acceder a un analizador léxico ya implementado. +### Tokenizer + +Para tokenizar la entrada se utilizó una herramienta bastante útil y práctica: [PLY](https://www.dabeaz.com/ply/ply.html), la cual consiste en una implementación en python de las herramientas de parsing _Lex_ y _Yacc_. Mediante el módulo lex que esta provee, es posible acceder a un analizador léxico ya implementado. Para utilizarlo, se definieron una serie de reglas que orientaran al tokenizador como trabajar en las cadenas de entrada. En el archivo token rules se pueden observar las reglas utilizadas, las cuáles consisten fundamentalmente en definiciones de los patrones que sigue cada token deseado, con la ayuda de expresiones regulares. En este sentido, se trabajó fundamentalmente con el módulo re de python, el cual permite definir dichas expresiones. -Nótese que los *keywords* no requieren de una regla específica para su detección, listarlos es suficiente para que *lex* los tenga en cuenta en su análisis, pues son frases que se toman *as is*. Sin embargo, cabe destacar que para ser capaces de detectarlos independientemente del uso o no de mayúsculas y no confundirlos con types o identificadores, en las reglas de estos dos últimos se verifica la posibilidad de que la frase matcheada perteneza a la familia de palabras claves del lenguaje y se actúa acorde. +Nótese que los _keywords_ no requieren de una regla específica para su detección, listarlos es suficiente para que _lex_ los tenga en cuenta en su análisis, pues son frases que se toman _as is_. Sin embargo, cabe destacar que para ser capaces de detectarlos independientemente del uso o no de mayúsculas y no confundirlos con types o identificadores, en las reglas de estos dos últimos se verifica la posibilidad de que la frase matcheada perteneza a la familia de palabras claves del lenguaje y se actúa acorde. -Para la especificación de comentarios de más de una línea se arpvechó la facilidad de *lex* de definir estados alternativos al *INITIAL* o por defecto. Así fue posible asegurar que los símbolos de inicio - (* - y cierre -*)- estuvieran balanceados con reglas específicas al estado *Comments*. +Para la especificación de comentarios de más de una línea se arpvechó la facilidad de _lex_ de definir estados alternativos al _INITIAL_ o por defecto. Así fue posible asegurar que los símbolos de inicio - (_ - y cierre -_)- estuvieran balanceados con reglas específicas al estado _Comments_. -Es importante destacar que los tokens de *lex* registran la posición que ocupan en el texto de entrada, considerando el mismo como una array de caracterres. Esto, con la ayuda de una regla para la detección de saltos de línea nos permite tener bien identificada la fila y la columna de un caracter en el script inicial, lo cual es sumamente importante en futuras fases del compilador para ubicar y reportar los errores detectados. +Es importante destacar que los tokens de _lex_ registran la posición que ocupan en el texto de entrada, considerando el mismo como una array de caracterres. Esto, con la ayuda de una regla para la detección de saltos de línea nos permite tener bien identificada la fila y la columna de un caracter en el script inicial, lo cual es sumamente importante en futuras fases del compilador para ubicar y reportar los errores detectados. ### Parser -En cambio, para el parser, no fue la variante de ycc la que se decidió utilizar. En este caso, nos mantuvimos fieles a la implementación efectuada por el equipo en proyectos pasados, la cual se puede apreciar en el archivo *shift_reduce* parsers. Este cuenta con las modificaciones pertinentes para adaptarse a los nuevos requerimientos, por ejemplo, para la detección de fila y columna se realiza ahora el parseo sobre tokens del lenguaje, en lugar de sobre simples lexemas. +En cambio, para el parser, no fue la variante de ycc la que se decidió utilizar. En este caso, nos mantuvimos fieles a la implementación efectuada por el equipo en proyectos pasados, la cual se puede apreciar en el archivo _shift_reduce_ parsers. Este cuenta con las modificaciones pertinentes para adaptarse a los nuevos requerimientos, por ejemplo, para la detección de fila y columna se realiza ahora el parseo sobre tokens del lenguaje, en lugar de sobre simples lexemas. -Con el uso del parser LR1 que aquí se provee y la gramática atributada de *cool_grammar.py*, es posible parsear un texto en cool y obtener un árbol correspondiente a una derivación de extrema derecha. +Con el uso del parser LR1 que aquí se provee y la gramática atributada de _cool_grammar.py_, es posible parsear un texto en cool y obtener un árbol correspondiente a una derivación de extrema derecha. -La construcción de este árbol o ast (*abstract syntax tree*) es la base del resto del análisis que se efectúa por el compilador. A lo largo de la ejecución del proyecto se utilizan variaciones de estos árboles, pero este primero que se menciona está formado por los nodos que se encuentran en el archivo *ast_nodes.py* y no es más que una representación bastante general de la jeraquía que sigue el programa parseado. +La construcción de este árbol o ast (_abstract syntax tree_) es la base del resto del análisis que se efectúa por el compilador. A lo largo de la ejecución del proyecto se utilizan variaciones de estos árboles, pero este primero que se menciona está formado por los nodos que se encuentran en el archivo _ast_nodes.py_ y no es más que una representación bastante general de la jeraquía que sigue el programa parseado. -Cada nodo posee los elementos que lo caracterizan, por ejemplo el *ClassDeclarationNode* cuenta con tokens como: el *id* que representa el nombre de la clase, un *parent* o tipo del que hereda (que puede ser *None* en caso de no existir), y la lista de *features*, o sea de definiciones de los métodos y atributos que posee. Además se añade un *token* que permita ubicar el inicio de la declaración en el código de entrada. +Cada nodo posee los elementos que lo caracterizan, por ejemplo el _ClassDeclarationNode_ cuenta con tokens como: el _id_ que representa el nombre de la clase, un _parent_ o tipo del que hereda (que puede ser _None_ en caso de no existir), y la lista de _features_, o sea de definiciones de los métodos y atributos que posee. Además se añade un _token_ que permita ubicar el inicio de la declaración en el código de entrada. ![Ast Nodes.](../img/classdec.png "ClassDeclarationNode in cool ast") @@ -119,17 +121,57 @@ Con este fin se realizan 3 recorridos sobre el árbol, apoyándonos en el patró -TypeCollector: Cuyo objetivo es registrar los tipos definidos por el programa. Aquí sólo se lanza un error cuando se intenta redefinir un tipo, o sea cuando aparece su definición más de una vez en el script de entrada. --TypeBuilder: Recorrido que busca asignar los métodos y definiciones de atributos a sus clases correspondientes, y detectar errores relacionados con referencias a tipos inexistentes. En este caso es necesario notar que, como Cool permite la herencia, se debe asegurar en este recorrido que no existan ciclos entre las definiciones de clases. Además, para poder garantizar que no se redefinan métodos ni atributos, se asegura que en el momento de definición de un hijo ya se haya visitado al padre, de modo que se tenga constancia de los valores heredados para el análisis. En esta pasada se verifica también que se cumplan los requerimientos de la definición de una clase *Main* con su método *main* que no reciba parámetros, la cual funciona como punto de inicio de cualquier programa en Cool. +-TypeBuilder: Recorrido que busca asignar los métodos y definiciones de atributos a sus clases correspondientes, y detectar errores relacionados con referencias a tipos inexistentes. En este caso es necesario notar que, como Cool permite la herencia, se debe asegurar en este recorrido que no existan ciclos entre las definiciones de clases. Además, para poder garantizar que no se redefinan métodos ni atributos, se asegura que en el momento de definición de un hijo ya se haya visitado al padre, de modo que se tenga constancia de los valores heredados para el análisis. En esta pasada se verifica también que se cumplan los requerimientos de la definición de una clase _Main_ con su método _main_ que no reciba parámetros, la cual funciona como punto de inicio de cualquier programa en Cool. -TypeChecker: En este último recorrido sí se visitan la totalidad de nodos del ast creado, no sólo los correspondientes a definiciones de clases, métodos o atributos como en las pasadas anteriores. A medida que se recorre el árbol (con el contexto ya populado con las tipos correspondientes al programa y sus propiedades), se va chequeando que se haga un uso correcto de tipos a lo largo de las expresiones utilizadas, que no se referencien variables o atributos inexistentes o fuera de scope, etc, reportando siempre los errores encontrados. -Cada tipo con sus atributos y métodos se registra a partir de la clase *Context*. A su vez, para poder ubicar cada definición de variable en un contexto específico se utiliza la clase *Scope* que nos permite ir registrando scopes anidados. +Cada tipo con sus atributos y métodos se registra a partir de la clase _Context_. A su vez, para poder ubicar cada definición de variable en un contexto específico se utiliza la clase _Scope_ que nos permite ir registrando scopes anidados. + +Si tras terminar estos recorridos no se encuentran errores es posible afirmar que el código .cl de entrada describe un programa correcto de Cool, o al menos hasta que un runtime error indique lo contrario ;-). Para poder obtener la salida esperada de este, es necesario entonces pasar a la última fase del proceso de compilación. -Si tras terminar estos recorridos no se encuentran errores es posible afirmar que el código .cl de entrada describe un programa correcto de Cool, o al menos hasta que un runtime error indique lo contrario ; ). Para poder obtener la salida esperada de este, es necesario entonces pasar a la última fase del proceso de compilación. ## Generación de código: +El paso de Cool a Mips es demasiado complejo, por ello se divide el proceso de generación de código en dos fases: + ### Paso de Cool a CIL: +Para la generación de código intermedio nos auxiliamos del lenguaje de máquina CIL, que cuenta con capacidades orientadas a objetos y nos va a permitir generar código MIPS de manera más sencilla. + +El ast de CIL se obtiene a partir de un recorrido por el ast de Cool, para el cual nos apoyamos, una vez más, en el patrón visitor. El objetivo de este recorrido es desenrollar cada expresión para garantizar que su traducción a MIPS genere una cantidad constante de código. + +CIL tiene 3 secciones: + +- TYPES: contiene declaraciones de tipos. + +- DATA: contiene todas las cadenas de texto constantes que serán usadas durante el programa. + +- CODE: contiene todas las funciones que serán usadas durante el programa. + +La primera sección que se contruye es la sección .TYPES con las declaraciones de los tipos que se van a usar en el programa. + +En CIL no existe el concepto de herencia, la forma +de asegurar que un tipo pueda acceder a sus métodos y atributos heredados es declarándolos explícitamente en su definición. Además, es necesario garantizar que el orden en que se definen los mismos en el padre se conserve en los descendientes. Para ello a la hora de definir un tipo A se declaran en orden los atributos y métodos correspondientes comenzando por los de su ancestro más lejano hasta llegar a su padre y a los propios. Nótese que se hace necesario guardar el tipo al que pertenece el atributo o método originalmente, a continuación se explica por qué. + +Dado un tipo A que hereda de B ¿Qué pasa con los atributos heredados cuando vamos a crear una instancia de A? ¿Cómo accedemos a la expresión con que se inicializa cada atributo si se declaró en otro tipo? Después de un breve análisis, salta a la luz que es necesario que los atributos tengan constructores. Entonces, inicializar un atributo heredado se traduce a asignarle el valor que devuelve el constructor del mismo :D. Para hacer el llamado a dicho constructor es necesario saber el tipo donde fue declarado el atributo originalmente, por eso se guarda en el proceso de construcción del tipo antes descrito. Lo mismo sucede con los métodos. + +La sección .DATA se llena a medida que se visitan cadenas de texto literales, además se añaden algunas otras que nos serán útiles más adelante. Por ejemplo, se guardan los nombres de cada tipo declarado para poder acceder a ellos y devolverlos en la función **type_name**. + +Expliquemos entonces de qué va la sección .CODE, que no por última es menos importante. De manera general, está conformada por las funciones de COOL que se traducen a CIL. En el cuerpo de estas funciones se encuentra la traducción de las expresiones de COOL. Este proceso se hace más complejo para ciertos tipos de expresiones, donde un poquito más de creatividad es a veces necesario. Analicemos una de estas. + +Las expresiones **case** son de la siguiente forma: + +``` +case < expr0 > of + < id1 > : < type1 > => < expr1 >; + . . . + < idn > : < typen > => < exprn >; +esac +``` + +Esta expresión se utiliza para hacer pruebas sobre el tipo de los objetos en tiempo de ejecución. Con ese fin, se evalúa **expr0** y se guarda su tipo dinámico **C**. Luego se selecciona la rama cuyo tipo **typek** es el más cercano a **C** entre los tipos con que **C** se conforma y se devuelve el valor del **exprk** correspondiente. + +El tipo dinámico **C** no se conoce hasta el momento de ejecución, que es cuando se evalúa la expresión, por tanto, la decisión de por qué rama se debe decantar el **case** no se puede tomar desde CIL. La solución consiste entonces en indicarle a MIPS los pasos que debe tomar en esta situación. ¿Cómo se hace esto? Se genera el código CIL para cualquiera de los posibles tipos dinámicos de **expr0**, que no son más que todos los tipos que heredan del tipo estático de **expr0**. + +### De CIL a MIPS: + ... -### De CIL de MIPS: - ... \ No newline at end of file From a29273199cf98b04035191cc4b103fa1b9eac9da Mon Sep 17 00:00:00 2001 From: gabriela Date: Fri, 11 Mar 2022 16:37:04 -0500 Subject: [PATCH 160/162] Restructure folders and scripts. --- README CMP PRACTICAS LAB.pdf | Bin 173122 -> 0 bytes customized_tests/run_pipeline.py | 31 ---- customized_tests/test_0.py | 104 ------------ customized_tests/test_1.py | 74 --------- customized_tests/test_10.py | 107 ------------ customized_tests/test_11.py | 81 --------- customized_tests/test_12.py | 106 ------------ customized_tests/test_2.py | 79 --------- customized_tests/test_3.py | 69 -------- customized_tests/test_4.py | 82 --------- customized_tests/test_5.py | 81 --------- customized_tests/test_6.py | 86 ---------- customized_tests/test_7.py | 89 ---------- customized_tests/test_8.py | 86 ---------- customized_tests/test_9.py | 80 --------- customized_tests/test_IO.py | 74 --------- customized_tests/test_adr.py | 92 ----------- customized_tests/test_cycher.py | 38 ----- customized_tests/test_cycher2.py | 48 ------ customized_tests/test_cycher3.py | 55 ------- customized_tests/test_hello_world.cl | 192 ---------------------- customized_tests/test_let.py | 73 -------- customized_tests/test_main.py | 55 ------- customized_tests/test_main1.py | 55 ------- customized_tests/test_main2.py | 53 ------ customized_tests/test_merger.py | 107 ------------ customized_tests/test_mnotfound.py | 45 ----- customized_tests/test_parser1.py | 37 ----- customized_tests/test_parser2.py | 37 ----- customized_tests/test_parser3.py | 31 ---- customized_tests/test_parser4.py | 30 ---- customized_tests/test_parser5.py | 24 --- customized_tests/test_parser6.py | 29 ---- customized_tests/test_redefinitions.py | 57 ------- customized_tests/test_reducer.py | 77 --------- customized_tests/test_reducer2.py | 53 ------ customized_tests/test_reducer3.py | 55 ------- customized_tests/test_tset_builder.py | 79 --------- customized_tests/test_type_builder.py | 39 ----- customized_tests/test_type_checker.py | 75 --------- customized_tests/test_type_collector.py | 30 ---- src/{ => cmp}/errors.py | 0 src/cmp/evaluation.py | 2 +- src/cmp/utils.py | 69 -------- src/code_gen/__init__.py | 0 src/{ => code_gen}/ast_typed_nodes.py | 0 src/code_gen/cil_builder.py | 4 +- src/main.py | 22 +-- src/parsing/__init__.py | 0 src/{ => parsing}/cool_grammar.py | 2 +- src/{ => parsing}/cool_tokenizer.py | 0 src/{ => parsing}/lexical_analizer.py | 6 +- src/{ => parsing}/methods.py | 2 +- src/{ => parsing}/parser_automatons.py | 2 +- src/{ => parsing}/shift_reduce_parsers.py | 6 +- src/{ => parsing}/tokens_rules.py | 2 +- src/{ => parsing}/visitor_type_ast.py | 2 +- src/semantic/__init__.py | 0 src/{ => semantic}/ast_nodes.py | 0 src/{ => semantic}/cool_visitor.py | 2 +- src/{ => semantic}/tset.py | 0 src/{ => semantic}/type_builder.py | 8 +- src/{ => semantic}/type_checker.py | 16 +- src/{ => semantic}/type_collector.py | 6 +- src/utils.py | 3 - 65 files changed, 42 insertions(+), 2807 deletions(-) delete mode 100755 README CMP PRACTICAS LAB.pdf delete mode 100644 customized_tests/run_pipeline.py delete mode 100644 customized_tests/test_0.py delete mode 100644 customized_tests/test_1.py delete mode 100644 customized_tests/test_10.py delete mode 100644 customized_tests/test_11.py delete mode 100644 customized_tests/test_12.py delete mode 100644 customized_tests/test_2.py delete mode 100644 customized_tests/test_3.py delete mode 100644 customized_tests/test_4.py delete mode 100644 customized_tests/test_5.py delete mode 100644 customized_tests/test_6.py delete mode 100644 customized_tests/test_7.py delete mode 100644 customized_tests/test_8.py delete mode 100644 customized_tests/test_9.py delete mode 100644 customized_tests/test_IO.py delete mode 100644 customized_tests/test_adr.py delete mode 100644 customized_tests/test_cycher.py delete mode 100644 customized_tests/test_cycher2.py delete mode 100644 customized_tests/test_cycher3.py delete mode 100644 customized_tests/test_hello_world.cl delete mode 100644 customized_tests/test_let.py delete mode 100644 customized_tests/test_main.py delete mode 100644 customized_tests/test_main1.py delete mode 100644 customized_tests/test_main2.py delete mode 100644 customized_tests/test_merger.py delete mode 100644 customized_tests/test_mnotfound.py delete mode 100644 customized_tests/test_parser1.py delete mode 100644 customized_tests/test_parser2.py delete mode 100644 customized_tests/test_parser3.py delete mode 100644 customized_tests/test_parser4.py delete mode 100644 customized_tests/test_parser5.py delete mode 100644 customized_tests/test_parser6.py delete mode 100644 customized_tests/test_redefinitions.py delete mode 100644 customized_tests/test_reducer.py delete mode 100644 customized_tests/test_reducer2.py delete mode 100644 customized_tests/test_reducer3.py delete mode 100644 customized_tests/test_tset_builder.py delete mode 100644 customized_tests/test_type_builder.py delete mode 100644 customized_tests/test_type_checker.py delete mode 100644 customized_tests/test_type_collector.py rename src/{ => cmp}/errors.py (100%) create mode 100644 src/code_gen/__init__.py rename src/{ => code_gen}/ast_typed_nodes.py (100%) create mode 100644 src/parsing/__init__.py rename src/{ => parsing}/cool_grammar.py (97%) rename src/{ => parsing}/cool_tokenizer.py (100%) rename src/{ => parsing}/lexical_analizer.py (93%) rename src/{ => parsing}/methods.py (95%) rename src/{ => parsing}/parser_automatons.py (96%) rename src/{ => parsing}/shift_reduce_parsers.py (95%) rename src/{ => parsing}/tokens_rules.py (99%) rename src/{ => parsing}/visitor_type_ast.py (99%) create mode 100644 src/semantic/__init__.py rename src/{ => semantic}/ast_nodes.py (100%) rename src/{ => semantic}/cool_visitor.py (96%) rename src/{ => semantic}/tset.py (100%) rename src/{ => semantic}/type_builder.py (98%) rename src/{ => semantic}/type_checker.py (98%) rename src/{ => semantic}/type_collector.py (92%) delete mode 100644 src/utils.py diff --git a/README CMP PRACTICAS LAB.pdf b/README CMP PRACTICAS LAB.pdf deleted file mode 100755 index b4e06dec4447c3a30d27d1370d982296741aef52..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 173122 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±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%0ANA}pep1|^~ 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

(X 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 z zx@yF#o=Py1^Mxi+X{?-d04T=%bP>INi`lXa6$;d~4z9oU(O*nn<&AElaBXrK8v-wv z@WWU7T|7{%fPX3V6%;`G1(DlHw9lf}{F5{CJv4{3D&oY+^9Jr=7Ze^2m0QS?B=ybI zq}p?-Q|TYZj-{nF(f zw+`)~HNk?p?f!0xk<*PhlUTb>kv1_t_(>`h0UF%8ga3pfpSARdU8?E3AnikZ{#CPK z-1=ayUpPxQdpHH>2hpJ;YpC#dnTk3U=FDu|zM>_LZDG?InS9SgdhM-`#3;SBNDRNR z@zWxkvO2yoZG| zf-ohrJf{Qm#%yLqU|EMRdn9M@=If4)Y;czlm)z8lgBJKqBM{~yt!@w;w0?Lk!lB^ z#qu<1_Fr|6LYZJ0=IBau$IN-5r}X3T{N)`NEeZT8f_f5J34afbj6_hah;g$HAt~WN zxuvK}DEl(loY-RYG%897MO~VucG=_&P;4R~)gi-VJwigZJNBi>4-=^^i*3Yq;(zA@ z30aoA3wW-;V`>?7K?r<au;c4qUAN^OGc-}y+wnZ!B_!!id+ zayt6EP8(_yw8GvmOn!BXuK!dX_58LDd7AS9ZPF3n9EYore)SYoQxPYLF$;4`UnU2j_lJ%Z8{i@o3m5C8k#J&4j5GNc#F)m53MWep>q*?T_C(gS zCJR{a>6KQM_RqkCt@vcBhg-1%R3rAHmv7ezy+%G)+>G379G*FR$1Lp^#u%S^(dECf z4-V+3DOs4~=a*XLrHqG@AN{t>74orT)wj(NVF9;ngAb>?$oU0XxGxV_zoTgpFu~UL zGNf5JZCPWMosX_ZN7=gHbp9b8DNR$4m2+b zpKjgY!NAid&j80|B9>BxM|UPF^FDXA1XCg!yvz(qxR2|MP<}cGZyoVcH@j~{p9uSW zZ4!fX+zS$OWFw^PJ=Ru&ew_Pc@+KG=Su1cFauqu}VD@2s#mV5;`g97+;w)$3)o+L! z>i)~Nbm>O%a8qzCAud_cM&jfNC8!D4@WIe1#oA=3Df4ao8(us!Vj%KWn)4NlcWg~XqM8}A~yP%I0* zhhRYlz4Sf03q@7g2tO2F`+aaE$nbbCpuwlC#za026@D{VW-p)d_8093PAHWE+HDCz z)-d9`*0Ol;!=FRhh**WRF?6uKrO?MuD~?CIPr{k z@#cy4&eH1yFP^Q|0n>8*!mvf^4CR91qb3j7yfq;9Y|>`5bPZUx6_`o#g1>he`@!h| z1)^a*GwSti_!a#ID`Z%MrK0=1wP!B1tipAj22k4E*u|#%WS<#)K{WRm=;TBL`6HO+ zzc>^M$ak@21wA;uirw;vI*#e2)r1CYwk+d28VXhh&!i+3F%;nqc>+j^KkT>AENXl; zcO!kjSvkQ3m0&xdg!CwxkhqJDo^@uBN4#U?TlXAE<0-FQs3GFoA^(b3NZ70k0tA!* z2LZ^rmsYTeDs2l%g0d7y-ZmZrV8pLw?N7%KVMunQicfPR8fp>Ug(=`2-~>h&XT6z@ zDCkB7f4)On^S;1qX;xZR!*m0k$t$5G!dMl=rs4A(oum+)B4p>p6Bl3S$miHUSz|?} zD;EN#yI9MFpCckR3+B;-;VA{1UeKlpj8I$XT7fEU9njHk)UoZf%9=V97Snu;4J@sr zemy>Zr?}6dZPM!8tE4CJ*@qXgzzmlY-kuz}aBN*1y1H5K>!1e)I&z4B^z*DmE*04h z?JnEO?P8|T&c?#H1(w`3!&|f15Mj5;iL_ZeKWYPO)mVpE=&(zYkrbqaxdp*hO@_w zjKBMhWI4z|pmwCn5~}ok9B?yFZ%cu@o_2ntM<1|*nio|>2c+#(CZ6s=@h<-?d~Jp&OUd9!r>UGCz&O))HIWQbNAd$+Un>NBLxtM46Kt$JQvj#Z;j({m+J0by#GmqUcgqVr<}hd` zUv_)POBQC>EqP1eT{Tgl5_e$o5cyB!=+in9FjfJy`r|)XouBb>gGHS(Y~h}v?oOwy zg!USji5NrHBXunY4`Y?05#Y5$`NBP zJO+hZTV}ybXunBBc>uKCso7!%UqT)FrV(xhgWyR?3;_LMeEhl5!gbndqUx}abl34u%l!A%g!AsFl*5t zvVv0(JZGavEe8PmX$6tqB~zqTNIJ;PAwmrhUqn~X0=p}a4uFqkPG2pvsI zICU4lVGQH37M(rp%Jjg~+u0EiHpZ95RXXDHTg5c%Gvuh&2>!_y;7if_+y3{jp`bl> zxY~@9U(MWi6jwFzJ!QpcaA|#IXv;hq^i^n>vYtb=ib1+Tw$= z?BEuLL$j`*)Pd80rOgR0L=Bq!h-ZvSY!@YXNgcZDotp(RZ5O7y$K@bNXQ2K-u#J4v zynt7ZpnvBBVBeof6 z>l0~cFup0D<2*Q~^ik^u^WK#%)y(gwYZ0VPwv~&+s}N&yJo%y`%XGr^1lg)L0x7T~ zUuwUV-yq`^CBoJsj)rXcT`NG zjP_?|WxaToSa^GX4cO#`qR10vzS@dP)d-I9#PG9ol5n{z?2zJ!6eku1e=(A+NLAKa zvnB*)-Mg5DJq72%c6tOw_IXsLD$$<^6h!+`j3&c7ChrL!kv_J=*J z475sOP#_!w*C^#t?IU26+jpvba8N**kh?t)yexQOhs8#RStJI^=6u-z>e5Su@9m7< z7X4KqHj2%P2M;=Uk5tzy9ds@ZYIie`wclEI8e8@Hx+UxqhfHJL;AvARG)TDCc#O5l zWa>eh1}64$yK2hM#Qk?MVQIgkDF-V`i3XL+r64;2Kf?sPD`S;WHlt1~TGAc?m^yIB zqRo8Vxhn&3Fiue1ZS4k=;>YzQBNN4kx8JQe%aIb#I?i2Cx+tK^|v!XiS&&v41I zatP>#7SQYW{tryrJ^`_<9P&FBsZ3?AG|1S$s-##Zqvk_W%>>TtmXV=Ri#eS6bDAy`#2DoIwRSb3x4a7_p>GR&gyxD}s#35V@_G zCmZT4lsrgl-3nfqQf|F8=n7a|?I~CIod&Bj*6_YaA_Fc8iK^>L`LW=7a!+Xze*SGaW;5zR zO*UzxGKIm(SfTs%i?c(0DUT)h&9X?$!76MYkp4$6VIgugTju8di|0pRL&4k5GHJq& z`V2V4A6}5_fogxzN5v`@=H#O$HfdNPiS}}&#+8Xw{jz0(scgpCRa1!Glp`jI6U%x} z9z@$rP7=R$6cY3SzR9R$bN4?68qMxbXtcy<|q71-&iCAibQW8$uE_C;WHk|jh z>f}9_+)Nxt=n!}qe7art?*1loMqWz;wq&Sjrim(h7L8^*^TKT-4K1I~Q_Hrn%*?b% z1mUU>^F^x1ricv#}cpW(h_oUG%)n&u>(BonD zp8oa^nIpoiQUCNH{=TR>OkRy#J!gc$s4e*nfwj>ai=yqD7;LAsY_dv=aZAC6J?!V- zsD2u|$k=#WQI`}Ok1E($Ep2xU+ORV^tCprI(XG4BR|Vh&&%-pf(DnOLY64|kH9QT5 zbJgquky8rosXGYXx+_$&0+BwJPmCb;DHzo4qEYPMg?HZ>QE#U7vNUxklpV5QCgV3yu z(QKCaB!f%m5Fa&24^|2+!%uK$Fn$qXRqIK~Yg{6f@9Qcd0*w5%V%di8g=J|3m$HlU zvOVEIGJE;HF=(f2+}??OQ(1jQ#R#^-hU@2VDtWFs_Vqg;4{_NP7@&)fGjWP8=tv*8 zV}{$dL6=&Zb3JCh$>P|_c}G`bBkl~`H(EbRe-Rz$L)mptmK^~Mtx_9F+|udRR{tP- zjis>Y{=V`E=kR)6-C}hI-DjXcc9so8PpFTDlS5w=Hx5K10YXIjY%SiNh27#Unx!x#oeY; z;VYLGJ7y+G9^dg3KC$tbuB2i9!l-ybX24;fgFwJ(_jvtd$jCcDoMQkdFS!X+s#(aQ5~H z)2y9$ZkAGQ0XpI=l|4+RR-gO|v)u$?+2CyyKy?BQGCe!`!YBShit;RyGKraxA3PoaHy=cbB5WU2j&msf^?iz&=@lG`bQ7mLL7RMfm<*B&p-$ ziSpXkg%G8uuKH*{%6i(+;$m9@@-X5*=28$QKH@c9galHZ!zUc*DcmEgb9}`ZXL{h3 zN9E^)D%~7>>p}faY7;rpDKP?5xuV^j(5qNBhmv(Pzd;qDUCW!y245N5%cHUgvhsdv z%|**tYP-RWzd2jm*Gw~@=YdpG?R%&iCnsyokH4Irg5sNlAc$l$s!@Sa0mezPh6-Xj zOj(^tBbSZADj@@E+ODIsqLMe24Aw%`k0v5WXzMjh+HRS*M4!UGfia=)FcliCxic6w z)9^guFIrNTB#Gn!tEN@=!|pzq969G2J01?~b8ssbb(6_zm}C~R;}4=zRYweY-E~Rf zU=yt!HA~Z#pDk&~;e|fxiev*4yUimy6MGWssb-ZapF1j(y{zDJhWyq5^(u8}s5u7M zlAt8^abSM{SSI)N zU5j@RM>*)$b^<=OnitNeciYz5R))eT7$_5oMfkk10mYzdXGOL3fehlMH$mLrC4h+o zB?Z1#G@C^fNydFyWEi$p>6X@7pCJ)`51W1a)TP8#k-A-HujGw)_^JmMDolEx zX$hH>6YRY*i>=j`mP9ZhFVLyDGf#?nfa>c+f$wLhJApl=}=+=H&?XT z@N-B$LTZRx)cc^Uum!pY?hh-{s`vyEn}-S5Dj*;UpY* z+2MXbNRbtt!9FGbj-~WRZXJHb)X?Ce%u{kpNMqu;P*K3{B_lPCBEy6a#!?V&25+rq z0XABqnid=~*Nbcv4?Yk=ZmVa+-7`&ess817(p1$3T~j!Ep)lV-E?gMVSSV6g+suW! zzLB0w2N}O1CTEvYbeT?ojzfZBzQ-d!IAi?u1cvGS+%0s8`J|VI(hl~N15x8fxJiV5 zjYg8u=bpZyPBy22%w<{x0_i0M^V+S7BwHmQBh@8$>#1;wBa^EIR%RjqTfdJ3)T!1*(;d?FMjAi0on?C$8qv$ttDsfiy|#-2G?3~N89M;Geu%yS>Nat^XFFE6fzFX;2V%lX6HOACq=zSG7FSlGT4^QA%7?=S6t8%b`g8BF#$bDYw=e&IT9s;LkA_x##}sbAb!v6U_dsf~>y34& z$2LPS3_G=zY8j>xSyFETI+8*uKh7*J&n}~7Vsi!)3MYWimbiPKP;Q`Os}o*MYZno0 zK33nA=(e%t>=P*9n+*OCRf`X53$97_^u&UEsTLy5)GCrwUsQev6|D><@F*L=bS(zK zGC3-@KP{=1L9|{$hs0FS=F|LO$JVnN#u~lww6J@X6VZA!r#`;P4yAO#zwX$W)W#if zv$fDZCOa{mf~0#PT)dKcRr#U#7fY3AqJ(BEU4x#C*R+T)opD?5;30mb@jXiEuXGB$ z+!-X2yQ&r!!b4B7oqKW3`sv zls8e+;2dcJTR9HP9-9Yn5$>M-V}syrV$Hl#Vu)ES1w5j{+N{C! zZA?-L^?<9mc?nPW`@P^0>(Tu6&^QZCGmo~5e$?oPTZez)O)8-=+Z|IV{criwuSlj& z<{PP#@e$*$jtQ???V}*!!GBN^u z1al;txQHiEOJr%QfxO-&f(;B-EZT|W{7!v#O23PUTWGS*K`bX@QhI5h5jWm#!aaWm zVIlD&V{7j&goDkdc6nh^7S*lVGJ_O^U~{1Ofl#cyGnH>QfMv46EO`IbWIr}%|Da^q znka^|8;X)X<@Y&kG@s#g!6bZhgB;)%B|1-;bi8cBag^^Ao!F_F2j|9;okA;hS@$j+0C zA~bGxD4!p5jd&Kvnty23+7uf`p}bM3q)}N-O9hK@tISo{89vS}Q8WWQrO6O9sCPb~ zRRX}J*7Cj-hE`Zd_(r+8E|#eoGdJ^MWh}w>++pNz6>Nt?C~PcgJYkN~sv}CFdd<(| z6s<4w0S}^-LBE?0aR7YUto2{#(FR zV5BKfrdfrR%Eo0SV#x3xe&QHUL;7`U*Yl&FFsoJH-%z-06vH-&%iyrT#rK~j2od|LEQrNh7E+kois4!(L{?~(Qz@m&Y*c4E5m%l#vNtZ2;GnBZ2{;-W-`fx@vq ztt4F#cQ@G`LCDH`o!h4pabH{;`8=l!zk7;RPBpqb^yK!%dDB$6;i;;69n7ci9a|gDw9Fz=U zf%Hu4AG(HvnLPY^ajy27R7DVk3D-yMKatb+={kY*GCx1+m8{kd#BDpPuV%`bflif$ z+z3s<)O$06Ll*_v=HFBlLB#!Bb7yMJJ)&6;Q)SZ|;;z;YV{JNT(mU~mKV}0D2UGxs zLc)c|%Z2YhqG@x$S}Fl zjQO-oMF9$M|C>hnGkJHSwqeO+EWSm4@UMR@8D+^em4CRrOOq1}2=ER?IhkN62TgT@ zUnAZ65EH&)xny>|K5(GvsuDbzG<5fyEA){)VWTLjGad;QDu>lexc+@(k(KjL_B7(v6EL}mXzRa5Jr*YOE#)M4hn z!w1y}o)1Vubrkr?ToYvS+aiL)>sc<4=Jb&8^#||24Z$nytADzxe(PT_w6sJWU#LIj zRz%;;7^YCl7xbXcDYzQ|0}^_x%|K}xmht0|xVnZ`vmhmPCLX4)`P5hna(MnqC7xYP zqoJkFdK{X?S{{i(_YrO0Z1%kNVb^J)Mc`^2A`%Su7EY=e?IGVf4JL+SoA}#mfqUC9krxENn*Z)ne%yq^@nf&~N}hs4Z`AhDj-U_(-x!=q!2*;U1;zk7gg^ z2!T(bi$g@m&luS!q89q~p?**U5Zm(aGWtn8A(XihaPN94i7B<_8;u_p?hN*8&s939 z6SIk)T{{7SNt09lK*A9s$j2oc&|#v);~j&t`AQ&tc?Zm756w2?MML0;?aSr%A_q5F zL(z(w1hnBD)G`O>Q*5v-0(#klK=&! zp*64>ekU~TANaTk*d3~AeF!+(MgGJF`y?;Lh{HeUKm@WC@ikbML)EL2z5ioOP1Ac? zQRJ&USpVz-br8U0Ym&-EjP!`rYL+_XKVqXqDHUVb`Q>Kwvwo6T^OLcai}=SgJyG7N z89AnhK{78cB>m4)XMUD5>6ltnQ%i}|a*RQmOjlIC)XPi{uj@FltMOq{9?D-pm8!9N zliX&j;$y~pPU?A#6+NN=5l=g~3BDB~=64;MZ-9k*Vk0sPCQNAi?|c~Q$Ni&_UNb%v zq-v-mhgF0hT)>YKvdp5n_vq5e%q~lB6VwlSrdGv=9S{mb$_Yx zf^k{07;>@FH9z?7HUg^o18{k{LrJSkHxg5`*_(Cr-GZ!@BE2xGM!1uZwT3lBC}MA{ zj%z)YEGOh!lt^Gonp&>E1oKXCt>7E)J!&Po35n$1D#ueKLg$1Y{=W_q4{A|*Ef?#V z+wX_gp-zGKK1IO1G-j8GUhFBrf3;wsh#r28r*IMsfUs)uWsOodvmGrXqV>$~L(#x{NY_zkMaul{QbELFP(>(#Bx!~@rfzt;*5h4bQ zql2}Om)#r-${;*vdYDx@a2_SuE9N9e>X6AU-Oc#KU_Y(x-g3I5Dh(1rEKMr#ji zbh)D9wM_t(Y(dG)cK%h~5HFe?H9J>{6*nZRW4~~u3`Ff&?Z->SlR=#R&wqu+E(^*9 zkTy#AnAfVEuyNW%%P2lczihcyCKJ#Lq1G0;yrKA>?S61*)9zR>K|XjsA8$Yu6vi&x zw`6wVZ^>lM%Rl~`5q{dH`hJ4xa#M$Z#G@yM?fI*8e_huj5%h0la!F(;RpEc>B}bE~bCNHD z^&&iQM82hZxfvRSbfcz_R`1s*Z8;3?ap0(V=A?9k|Cl(zL`clgPML*QF{(j#8pf`S zsCmyYIe8$gTC!dae-4P-qcm;lA+_@-Lq=ku!I;S`q>DT6R}s~$CB2(~dMdDp*>CX% z6xQp%0@|q`jqC|dgFWu-77^oBf%A8#bKFU5{oI;U3P!Gk3(xo3UWS#5R}iJtLT7n5 zzFW`>QRh6Jsgw*v|BSY?Lv_Z0Z{3qqlzrodDpV969kRWkm|8u+n_gkNFt72eQws{T zOC&sJ(`Fj=6*&v(-u zkBQHQwd_-i0IEJtRQ&RkJUg7*{xLtN7RABiLBTh3nJAi*=v_(u?x`Zv4H4aPB)S}6q_ z3IW^84rW&k(3_~r;P$^+wod|lvw0BH#9vfC&WI%bcAyIOgcFkQ(Xm1{0rk#JG=IqxLZ-mTtNa*kHo z$w!JGA)^wZi_6woqcuN3^XwKMY{qUX1t$m}C#+(n5an{XyZae!C>tYJ&2ddq_1hFr zOeS6;diA$6z{yafMx!f>1Q3MBj~5p|GRkqEjq74_rBpHBDkjF(pVcO=1*f}zo#bak zsHSJf!g%IS`S(BOwGb)7{b;1GYW;t?bQ^fyOX$nXjuj^!2XKxLn6#Q`0|`ln2^O9|BKLYEEmIov>j+Md)L9~%_hWG z$_D0gqLuzCvxHe$=J?ieYIVt140V?xye!t-Yk6Le48Pk%rFq;7;}6RTQuP$`nQ~32 zIgqjL7A8S-O&W_OyUKu;$@G4;ANe=7Frjnv5jWLoJS24BTH$mZ>G0(8Kh7NwzBTt; z{zn0&2s@vlMb}d`W(c!V+F9eT3_woW6Il{!0C@4hMZu{FZ21ht@xSi68;~@2zFoDc8vU#qc7+2g*nqJ5B#wpv~*;U5z`g& zLGa1laj_`r5QspkE14v+OnjjB8U!7JKad+ z)eEUcnp2PX5HhQWfH})6_b&P-(<&+pLeIFk3-M_@ZF(`bB=eMs(Y8d);HQoW@2~p$ z3aCTi<5CW9wYS0MED7<#{exbOWTq0s>?IbVGwXI0BM}=5MuwYzR{QPI{?m#X*Ww2L zzFWD&I_dU~-aUgnNBx4z*s(AJ)>zS2JqYzE)&JR;*K(7Nym7U`X9J_Gq z8mU}KNrqOi#+c3~G0{_v(~zlw7<9O+9epSX2}t-OF}m^_ZHEjl_k%6bn@-b- ztl+ZPvsQCaBceGAlA8+Im+-f&{K}JDto6Wdi3cLl`6=`wOfmLAP z@WJgf{}@CXwJ;7rwl?`!0f#PS#=fh=+$NDnquH?3d)l8lxoq4IS{$dHjXO&*Lx51HbAd+sn%1<$9{p# z-dsizcV5cTJ|lIUv7s{ja$JSU-U2GJLU$w3;PQpOjiR$+)6CAF2SAe(58y4<=D zfx5-P;3ClamAG_4rn^UXFvayY#(mK}*EJttI<~%n-W#S3QC`74TE4tU{h6N8(XgIC z%JkD^B(()K2ZC7t2)}ePxlfKMtdO@hC| zTQHqcMIRhWE#T|Pb!C*8c3H7*n$X&8+!gI+5{1Z@_H?{w=$E$MJ@qVtRB2xxO%k@5 z785zx{X#_y-gY@R3Mg?f?@1GbNia=`QuWJvIQ3i!~2 zAkoxb0;}xLkym2BR8K}87y`;bwx=ezLF_elhRMar)v3IZ!hhT*V}~Kote8V7XeQ&e zUJ^gg$aCJif%m!`*9Ni9K%9HXB8?GKZ8F6~bn;hm}aj@)`-O9cnH__J$c@NrM z3H3G{c1i$t+=^Gdj{}jLPY(dOnqNX~){3(4TZHuK`txPtHqipV3@MOwyxRu*Y#XWk zMLEI4Z3@P!pWc$m`|V=;u2T=He5l1n#$U}bEIk0nJ0HL(xtuxPbWz>enXPb(_){WY@4^OPfYThqZ?Y1?KovEX`J zFiL53i%5DEiYX4}McOnxNV&_;=z#BD^momp{Sa569w#9+()`OI^O{gl^btaEJzvF~ zm{uVvI5THp>OlRDI8rTT2eL@tk~N>KPa_{|giB@w6*uuVdU^e~=yL``xTe)Be$G}9 zSk!V$pyI?-!E)H69LERl4Uohz8-{2{uyuDVy`7{Us_X-a+ELjG$tWkZ#)_*%16wa6 z)lsc8K7Pc&S}Liv(Vut45C9QuB7m5!s*cw;{B`U4aX8%0^^>u4*Y|SpF}Xn^RzL1t zwL4VWXoGs+s7^wmgT!Y8K!9CKjb|#JxHN5bcoWvX7)?I!pg!Wz z0p+~PG z)BFeZG&VOibNZn@P0W7|mmlQQ*4Y7I`XhXrx!ai;+x$SE7XL+kTK_noHqO?D#tx3= zrZxaufUS)&zz$$%;9zWHWo+W~-&YR*^)x$U2Xk8^fIYz8+1Sy^{HJ3FfFr=s*xLNR zU&GPd4d7^H;AjSL0yvpD7#jne%&m-m&aSoqXMhX9^*@Rzz=QI?Kfb8Bl`#S9f7sCf zk0Z+ZKmOeRazq)}S^r-+^v4lpWM=+xPXD{{e>$QJOh3Tr|Dhuq{Rl3Pv$6yZvwwxx zWbc}~b9J@E4;szFeAOQybh8t;(@%>?(AMcm(9Z*w+V{ugDm(rC(|6HxQDxKATE{cD zTW(&-@~lp3mA{Jr4iN*v#Ri@Z$uBCSh2AeRGBq$V5;8hR7vo|V>`f{{v=$+tBao1e z==zYQ@H~izI!KOQqb3MW zU?+m5pE#}S?;w5T#^)P5wB3V;r>7$z&Q3@EJeR#GDONgdwd69sXVR-#tE+D|n2Pz!gUfe4{{1};h zu>P`FaTvaN7>E~OO&$y{iR_33fMRf$s%u-3?LJyWf^$mmOa(iOK3hqHFSO>P0nhVObe zr2J3fMo@R4m-e}@zIWhgKK!X^K~?{zd9h7yVjhCrnVq4A)j!@n2C;Lzg#iN7 zgZKZ&KD_?v;yqVUhTw&7qwOoa?7;9BFx0oofYkMuR>-oiNx&)J`2g(8HtbnkDhC8` z+83s$5}gm-c`D%Qdv@@?y$L~v9k2MByar)ugEQ!~bIvwXw@A%dkuJ7tzhcG6Ja$#Woy$tmE z46i%D<*&n^f#`aJKMU)Zof&!leWL3!y>@#@Y46)!&Zm->s`9p-_ZRVDw43`vYk~p4^PyP}B0g_$pjsGhJ(cK$=BL%Uu9j5gHuF>1{ zj^B;wH-CozP|*5?eS6!Tm&&%I_XWV+Z+gY>+I^9u`ND{4L6ke`eE@J@euX~|Ol>VM zejN_KkM4;;d|`Oy?>_)u21Z};$37E2^?Cr6GtjT(Z;_Xi+kL$Y04MElglb z?}FJ+#hu<2hh97TZw#;7o0rnIR3p46`Mcr+ z`GDH9T zUmVfxWaLhu9<<4<8-a~2q(5RtyWr#ccUdzM$DLG!>bg*0p-95hgDm#iKh(KCqq%rx zAwF;_j?S6`n?BoCpie}x7u6M6<2MjCIYOFggqPMWZx~*Cfuu% zH?)pfT0W9JI|<+rXT(|kdb1VPzS8?ZBnt)9=S`3zuN6kmp$b;MEvUP|S&2O|PToS~Q{zIkgh166@m!oGRiz!tGFdS=BMvoqaL*gL*8LW;ipRf(gsw+^nE7 zH>zgPOw!t}i7qsCw14B}X83lb@O~5K(x7N7A+++g$?eL@yF*md64{ADm;09)xv769 zqI-$govLHSf=1vkZE-Rl`_v?N^Wou)>?Eg$OGM8}UH6fTB|PGFzq`i`yw05R7ptwm36C*|$}iN^jy{$}z)g?E&^Fs&83loj8r<*b-=3}{*Er5Yo^H!_ zMx=6p7dm*5?T*~#KOUxNruIywY?p*D+gw`l*B&G@M&x^3fKCX^8rAcvxsZF=s=&%s z(xZHKrUp`D+bA~tqaSnyM>xsBa-G?>6tCb>_DZ6k#uG6lQX&l#eNo7X3*HmUjir~X zD5&{JGhBTxHzTv_=g&J7(gO}hmFyzJjPZLD&}Nm1$}`q_*Niys;#?EURuUT5quE*I zZ6U`mUc^C%lg)UbdzdxD+bD37%@_JJ`;hkO7c>wIskSC)zJ%Z(No~7^X9JB1d3Gk% z(UbAyzaBvx#N{wrfI;AMRBzX)oj?~lc z-nDh4wH%~ywYL}JcKbFtAm7p+y*}4T=kUuDA&J*$`Fj%~ zKEt}&Jez6p{@B#PMSa&~w(r1DUNJENuvc_$)yRb_5-^Q7{I{S3{dl3uuK2e*?^4vE z23tw6v0F*w2~6%WR~`#=076qlha;|t3YJhw$=`EkuJSrrHLp3)XCdJ~ET z>LJnvhKV_>U_U$8kTV4gu4jfeRLLRW-tz`h;TVn?S3VH<1#1YH>3`5%wvP#~mb@xm zytK&a0%@iIa;@C^!Xo58*$GmCI<3J!f7dElR2j{YnZz5D%u3EbfuILmOSYCSLbKU9 z1Pcv~b(tdFWsg4qi$-8DSh1~49;5O$~nfT)P& zLEa`1ubS#_!aM5^PX~jL&nnq~_>d6sxOJD-|!TU&&I*M~U;r+t3p@ zb+Wg&{-r!U%+xcBIt%Dc)Wy82Ol&nDXJm3TYdu$(6x+j&X`PelDf*-I;!sU*3Wc3h;1rr@MdX?3#^P3v5LpGC7n-_q z-rRoS@0))yv^74!t^X#Y>(vnKQRKf$8FB{U!TLy^|3xDbJH0h5G`+!4FHk6$dq7=w z97vO6BuD6?JL(rPr;ARHAXAfa#xDl3jY_--w+w1j~ zbMLNdF)v|FRkvTpJXbMbCgBG(>T8L=-XU$G(Drywe+ny&yR%yjx3F}JD*HDzU#BL! zHZ{Jh@HLHI6)MeNR;mz2stN})LWWA++x^ja5m(G%8D%eN~L7e;tsXvZo#qED&UN}cG{sxHFn4CqBgdCDkC zGR|oE@$QTYqk_w%?`68R%)rhf@VDy6$R0-kj zcOnub`E9a&sSm#uO=aGKlNo^?xWhemQ)qOcYSgsm_LJ(zBIXts#8ENr7bzAT&vKQY z!EuP-;Ty)A*pg;BV!jGZ8x`IpqSMQdN5vE{LiNH+ALJcYinxhtN6&hkVjk+@4pB zJ@{Fv#7Sj_1Fg#`BImks?1&y$b)Z$gY3!~nxYE|e5Ve8cco-6G zoSzG-wX-{g_QLsKfT38pXn#pYNxE(X@_J7J$6lGtns6flA_jalTap+?u^|ywwK-f2 z8X7HMM$+$(x+c^RSVG6VuSR?*mIoO0Zjrk7;4b6n_n}iWEN0OKTCgY`D$#Xjej<0C z)ND(a36g!3jiy}ou16ZK(}E~H_f0>Zz#1E&z@0?dsl~`SGYMfL?F@iivqK3KH9qz% zX6Q8!XD#h5K6yE+K4G`VsjZy0?NG^9kKsw!(O=^Yt302Z8_@G)it-Jhi9HkVOgmaW z5fPwNmd%a-0(`${mn11cJ*N~DpZpom>l%2dNnYAC_-+lli`G^>OOy$tBI~sL#Mdbx z_xa-mR_Hi!UISk?8J~ZrIjrQ76{<-X5)gOw8k7ZvURcYm$q_4TugY^l&22iIrgns~ zvWJ?1+~`JX*eCY~syfHkij?+ICxcu8|B?_C@s-Mr z>I_}4@G;~4@Jeu(2~?9v=KwaNud7p+`^+G?@&sL=wIl9P|F(Fgb2@J_h+>7;o`5R8 z3vti#CmOnL3J>38T<$fkq^HnLtG87UNQCh*>Z>_9TN z!{AErYdY_W_=k^RuMDmO4r3cCw$CYZT}<#^+_UDwG0jzZ?HQwIQ7DFID5iP3=I%gY zkM+3f>V*mz%ETg6>^BzE?+IMMP`XXxp9ManAzEYd64%x=P7~j}XH>U#aBK4rHd8f6 zqv&+?(E2qCJ2(eTnY*LozOyP6h`ke+JQ7JddJONg;vwq1uZTYegA`GmdH`{dA!ayq zuM%%sA`EXbR0$oGXBysS>#}BjFu~=om(MO=L z$|0WaF{HT5qtu~lVi#}HagGk9Ra+nu9R@rmjk`zb8w539@_7EPMc{hbgPm`d5p%Cv zr3{k@ytjkihPiaz9n(hbyqsxyt-5=%vaaDMt~{h%Cl5xBhSaM0#*2?=lnyDVh)L&_ z-bl2C+m0&YUqhKNO_<3UE<|=Y7c(1o_)(oKQxZlouinRmCNJqbmTCmiCZcW?h|IXo zgy_MWi*#zaH|M*@iO4*+JkN!{=k)Lzek0XkC{eCUG?!3(o}NzrK0H>Coyoa;%$67K zG(QgJ0)x)xHGJiQW5j8a@=@c!XnpkY?qoEL ze?_lXZV|_J6Yg>A+`X&t3^4wBq{Z2Y#j1^Ng3H++9}RrZR3nYV3q{@cBskbqPkMqI z^b?i~jROPv9`a0?{i4J?#^cQmt*eH@=rGONQT+XY5dpmLsYwcHf9&&!A-uORmCj4X zf!|ww&t&DyqmcGb(hykca;u;3-|ns4-&NvJnFu<0j^4R@N>li;i|si&`(_bih6H>W zrJ>PlhfyM91ffDh=*{=F?+n`H7=*cNGssDXjfq?G_Eh1dhMFw=<&gZ~Z1`!m%}3ex zT1U$Lmh+_8=<8_4zvIqfvb4dDc8sc65gWU4e;9OfZL5dh#3oWmj7o)$=%y{MY8qYS zT{*)Wa*83*NW#v7&9KY^Cb><54sD#p(?V}d-ilkjg$equLy=nEDOltoS|$Fy_$FQQ|yD{7gcPHaL@ae^hTz= z&^}h|MkxkbW*_CZ(4RAUJSC&{F<19~kh|Q-=ejP{;o9EVyzVhKE3A!+appHyw5Ch9X- zb`EEy>`6{0)=fVmk{PM=p8zQoG$7U>s+pg3tk+Ee{rGRiGvLwT0+$$y^Ky<;pdL9{ke@}B;j+sU7jfgv9o&)_CWcEDE`H$W8 zqVgu}4j)(Tb|-irMy*DEZL(CRg2gfd7jUuUoTJ*pUbWP=O-PJLOVfwrA+l9i!Bv^J z*37%?yCDUsYZ85EJ_)B!*)5EqdJod4Gr~o=H1pAjV>@S?0vXzo5CpiVMakom3OX+b zbx?B9CVPxIqt@!Q46$UA>0^%}R)xT|xZEi#g&ilvUPIGCSBO{Fe`+Yh9h%)(+5WWI zlnx5|6qu#?{8-X0!kXGZcNyV%WhS)2uyORua-G|zsm%S`MnmqXr~L?--wAZIQlC|8WM_)L%wfA zcq7e?N{KHMvI}>tTkX)e%ujUsQra2G)CzEs+(#SCyzuecl1t-1YlOdKwPFVS+wNkH zIg|>XG*^$5MSYEG*9OgF%+hkaE*Hi{m0lGy{hGz_=S7w&jMYFBQtkx^8XI{muzmJ{ zzf$4tnAn^gahFIjV_h#+U83JsUpZJy2y?XmCT+-7ZWsom>bm*7 zIPiIiVnn)@Em%pYDjT1yN41VtE-nf5=?uQ4MRd%ra#%4Ty=l|d5Lz*;yj*&<%o}X7 z)v5u7AIP?Bd+8;Ny_(`r0_eP>?#~!w@dZuWBh@bqu8KR4!F&spRi+RdC*ZN_AnvVsLazUNU+&BIyR< zkqqO2?tKIQl4SJg*SoGj34JKnD#`EZlL4be)m2}CG>SGV;W@u1SAxWU6&X<5kDLJ+ zr8_U7t3E7bl=?#=N2)R>yij-8ZXns z=3(oP!c7fPXhcfq2+znNW0ssn#Zrh+Oo8bkBw9)ITPm5$)vcGW=rS&8e~dVpwr7wZ z&qTMk=UZ~!_N|%L=0Sk-zB)T_!2_mHt|+;wBwBr1wf2RKk7!PFdII`G_#a74Cm_?rc9$iF3K$!&Oga-?R3!MQgT|9=4Kf z@oZt`(3}Ofs>jgtE-|#H&%WUwcLYdmbVIUmlI(~Sb=1zvf+g5T+a=Jd$*&u`*aVaNE6VV^-bVJwvsUM$x9mV zxPA7+7Pw%1==&VV!l2=7O$O+K4()hlv2Gg0?Jvw%o2(ID=dn;muG+2FxV!ZMd2dj+ z9>3IOd3p~Lb9CjNd;n02gzUyzQo^|~_~w3rSKnX?qbVXc9=ZI$z%5GC<8r`8{j$x% zI^6W?kzUMfvRrj}!Ba<|Bi^Ks=B!`m7K;pGEF6+#yU_23moUMRP%NT>)C+pfy6tqj zHk1J*Yq-k+o9v^;Kh!`7`>iwO-@^BQfH^@X*y5Nv)YtPCo(j&0iDZ0oxc*HNC}%dTZRL78G$F~8I7i&_XfC~>8& z--lhzW>(rd+L-Q_g}~?WKStn;WsSnk>l`@!cFK)r*`F1xXk?3B-ubT2Bp!T_CfdTb zMNk`xnuo_)tj45;glZ0}9!Fbo@snWel1t*AJ9xCf!FXg55Lxw{)`TIJoS5hmaC5C0 zT+NL+OxefF4LH_O^JA(q%D!i%XnRJNGr_Z-BmUC{RXv4k>Cu!IZPm1rYa;md@@g-y z0G;E8NF*FThG?8?vifE(3}rBS(d*GS)0^eAjuEeR!M69THA`#m%yH4+}AaFb7k_?g7Phv>b zNaxtEX8VGJa`ELGmi!9FPY;&%sN7g8B2pZYNT?0Ojf~5Z8Le%$Zh5)cTW$Z%_>f)J zaz@3o^?^ccaeQr|<1$O$20FAA@{RgFKy=!qOX9hD;wRdKTwmh78d^H1n9g%^Zm}?# zR_J&iPwhRzY=<*U@^i;IzQ=^~+_Sn`-v8c;KN%`+W+zSB>6b z+X5GEOwo&-6cbJh7YWWIJJde)af*TTO|31_R{8i`(Cyu>S26$mg8j#$+Y2pybKb1= zEZqiFsdYh**-mS|7m=}fG5CJcHIH`i!~}zaPOJhWBsR$#EJn2|D)AbU0(R~n&vjb& zt2rsgx2zf}oIHQmGqA(br!dkRc}IRS0ohs>axpXzcQ_vX8+9YvZ}mvUxpZ9q%~>Af zA@4!7#tauE(Oy?_*25G&V< zh)6x#ggu0C4XIS3GF6uCyLDFbIv<XgeBofG17iyp zTSn**WO5fE(9cmQ z>ury@M03NJBtAmppKdAsEvjsr#Z>a{{B@_T;ReYTO2ryYW(*RUtwKkVnenOaAD75o7)D3)s&#kNLh8FZ}|XmKMj<%|a~mar4axfAd#itL~+Wc9Qx z(!HetCV5shgbuK75{-FphTM(C6XcKjvFB>IaxhF#inx00x z3m9)oxV>T(Q#u-yFj=Evaji-Ac+nO^O$X<-mmEy+|B7Cwxf-c3y= z@nefnV&W2E5^y0tIQ95XqM$9W8m1#8Uy+-j4eG(yv)r-kOw2Cu5|N2@%o?~tGJ2ws zJ+J}_hw&Fyh148tLv;Ah#t^Rhp$Uo=pXguu!zeceYCAhj4Y`^yX0A$!QlN!ItYK!B z^~~%yx`pG2$8AUIb;AY`Z?UXjKYS1^qpT?8m|J=n1fQEzJc;_%N^?^Tw}UV;0ph-8 z*kJD3lZQMmo(Aqow&Np}KjY1p8ie-rt>_oW)LN_rULa-=jCsdq4LPtaxcsR<*6{@4 zVkBYf%19J6r&iMKEx}+|>Ms4!p!b@uL({9ZB-y32ZT?61x_5Ynlzrz?TaN4?T8TCI zp$ov+YCg9krl0Jjja=$Ub0sxD@PbB-{U0GA!2gWJdw4jvU7o^hz zuJ-AuNL4q9l;^%Jdj;-R_gtu{w2s7ITC5s*n)8I;X6Q4{G zi6#FJYxfi*O4MkJy6x4rZQHhO+qP}ncK2%Awr$%s&ie1pKDar_eYy28Un;3oW-66b z&H0V78GIkp3Qq9OEIE^cu!4YGIQh!t;yD)sRNieR(91r-Tsr0WXB3k)^+x_JQK-l^ zu=y_GR?fsYj!Mc5O(@nwic>JBSRte#zXcPf;p3<$Tyqv!9v!XGTQ;pSzQ3J8_uiRwHNtXy@#UXUP zDei6n!kJ$?Trx4XObOq{2s>$TQnA(_`d-!JJpSN}mxVZh8H_wS?3t7H%$J0fuZ>N3 zkxp$FcFfhVdY{nCimiwvLk-r@a^9o6-cn;q&2i)MVcG+khvi;_ACPj=w!ns#li_>~ z5`@`5`pq8J#-3I7>mphQJMn6F*#?d@ zE#{9Ff4zyP{Zt`Ks2PA<{0ZhE5HcWWi7Auf=$qM+cYdPy;-A5>9_yn!vlAgAFwm@V zq&U8h(umuM!iuEVO=mU6WgPgXUbE0K1?dYq!h`>u)w`+*$@Fcpvw2bUoVQ;>w6KaK zyt+ok6vr=|F|3Lnl?A@(54n>pZXmCPNQ}s+1q*9DZ?+vO)Y?mxI;t~3WAlLp2AKw- z)Q7=-Mu;@$VbZc&z{MChPQ6<8I*2y*q@aRqKQ3x1D<_u+@8@GWUlYzLMgo@=M8m#a z(u5M!oHjCs(>rV-h6TY!1xgg9y7nOB#epe ziT27T1kA7hJnQp00HHc%+4AMcdhi(JJ+Dz?B7&VMjMQ5`Qa`?sX5E-I^t(6vHYqAg zxv7h2)DD>&+I-y^eAQO|WQcQw)wde`Fz~w*%zjPy1SB`W6%m~#64a{n!M!|@lkKTTd8$2Zw!_$%8s=VO z3H#-_^u*_IxFZz7_sdY7t+A%ks{PQ6>dYHVdzZbveli46D}uDszSDK1xc>xzf+G)@ ze4H9zaRgT}6TU~6a3pON!jjpY;ei{TJaboMO(GT&m26Uz9Av7iQ77?mCQq`M+jKDI zfaNruq))8b-9V`x)-@rU`wEH)4Wri>iTYw5m^15ohtA?rH<F%>LKzN5y_xwnW35##|Ar;m4?$^1#~z zm$RewU0>1Gvh9h`GJ;qYH#nYikjtLeNxrDaXI>bNk`srhLQ~dM5?_!Io2A8?=ut(8 zaq|h!!8>6r;cH-FfSf8yNacvLxoW(+5|L^`WLa*J)Kp*%zCtQ>rZ8Eg1nrAV6+ zf4Y$j#MJ&spDN+HHsKmOdqkJZw$T}ixj=J7F#I+n9z{(tON5MgLh08p!=jP}fiEE; zLbMw*a_8~H-O6q66ZzKPr662^gX$X(8j!{n@G2SESS*6ie4mY*Dr(ZFB&m&6oP7ln1U9LCfG=QTV zW|KZti>!&1^Zc>^?o32(Zr;jng50*n5gmi9_Y<8rU~t7(Vz`Y2bmYGL3J-HGt{zQ; zxSUY7=4{HoXdbL7W#KYu%V+jZUR_-{BTg4tFv2MqGC4_!?d*(O`=njakCh6jngeYn zTkEr6iA+6cHpX;eaTU)#=qV7_+LkEbWA^UFb9{kTsE!uI&BxL9UWGQz!LhKrITuDl zP}h;}C7L{b9eWyXCg)avah&XGafh`qhvAJZp?!f#PfhR;&`o?lN`W|_wAA2#3_O}0 z6#k4BQwjh(n6@0d>0`si;6tsr(&k!3#eYP+c9uYO zEjup2t6EjgMh+!6V{S)by#@#>EToXrW|SolkV_e@{UB z!iKrxQgU;noT|b`c^=tlthr!VkZ~do{JOtgk2?X~Rq?6mNblwPXUzrr@TcwgzEz*t zr@~o{Y^%laiyRSE^k;gK=~&5rH_BUd08VWo47z9#kX1^yHOmp;W6&izw3`Qrta2lU zErjriCsVjRPoX6U{}|C6Dn?^7CA6nCv@}rmJ4b3fnKS4FIaW@kc(!M8in%n9t>`t< zLDQba{29lAP$8+>qS8*ns~zPCll!wtX%%ZgNYDsc7`-Zj{Qzw9qQI<9LfauZ8TDK= zCKse*XnE@>qsTdV2cIKQ(ugT##v8teG&|Uwa+}{??cJinXp|mGTO|Lm(zRR_bz%zK z{aCH1xAyj4Wni$Qj+cAl$Y?-`%1P}D?Svq=IVwBFI|bQ!)W{u=$US7rc^w(!N)G8- zwQI}j!}`wH{zgX{ptlSDg2@kyb&9#K?x@8IA?VRW0)YE~tgZ7<8wh#%8C6EYTVOX&qEXcX#0^_unksPIsv;ao2Izevj5-0MYx3ldnyV>-h z|BcySBUQV5Q85B9g-riH=WHfZ)w+FpncxCV zQmBibyvKmyn3JUDI`MR%+F%4LNLyO zI#O>JAN8+e4_aO`jrnYG5T}hgb0L7hb1dB_gWRz{w7MKP%+)~68F1CRcu{3tnKrA z9uP|>#ArccUh|!>oc!rh*b39_UD5h)<+C< z$45rm>eMHcok>;czeV+!p!K;tLrVp^h(mEcX}{~0#pZL0YXfTqDPd<|6?&`v90Decs2OOUlx|qkA;VofUL>ly&AZ=wpSeitNLFq3 zVgaLk#ofE?tL_bX7*dwZDD7n2bA-VuVabKgtyarQ&msZV>cUG8m5sC>VTFw=RUtx1 z7IASXgg8s;$!pF6S-nq5gqZ#itMFDGIMP6!-BA@KZ?nf*Q{KLrCEl~DzyDHtqhImn zcG1{`Qi+ra4?j}6Q#(}i&GvrQ{MkZRfU}Qar^0UMgCBEx7sW2Kkfm;uZeYDKwz-PJ z>Liw+`XbNMUu?VdQhoh42x#xryOU(a-wN8|_0^(T<@!w*eK)7189GQ4Ybs3;u~(1P zlc*Ni1Sty7(EFvdd-9m#675A;!c8@)F9?cl$xcw2zDfG>l*{+!XBe8_TgySurzG}= zI5|Xk*I>)nLSd|NIxNzykeyvk2mIKCIXcEv+$^Blas@S)4{mR#ho*rL*@U7#c zTkXed>P4N56?IybfZfD(_Y^6Zm^3HuJ|xE!Y)PJd4xekZd@fXmiv#C385zkM2oG!P z+wj(G(f1Wx=+1kSY5VAbEcMlE;zu)t0+IaJe0C^IjjgdUQL>%{XNd!AVSPPNy{Up> z^Du{FVlpMvVThoTnc+kAi|#q{G#0+`jk%w=AYM?Yg z(*!NrU=|U#Kyc_M)~hCu?v!~LrWo#S`fqF-inA$Xr}!VByAdl`v@re>12x^+`VdEJ zd@p}i_*MlPpe>{`M4Ts@ir8^KhnNsy&^-&1xGpHhJPVmjda`z*1(9BoN{LR^z!~*{ z&-hg0xj~Ly;><{GFSt$I4`xV)J^EB#&L$n!)9;THaN+JW6rX{6FQC{$K216PtHAtz zUzYrkLz@=LLeKXGYT*9#DI}0`TzK_WJ&nqZBk{7czm?MuGU(Vrs#=#KI4a2mUYpV< zxDTYr9_1l-X`r4(CE1qn%%a{07z(qj$PJ>6_^x$MupCVm9npR;K_W8ZCVRx}B0{g@ z#3LwRmWe7^AiUOpLZN(Nc{WpJC3~*~nj(Udyn+7a9IE9-$P*ra-W-!e+|)b8an4~w zC!m`X7J1R!L*%g~rqG!arIUp>Oxt;X>`eD>zR`)1hcJ+quc;;B_Q+m1Z*`uQr;9ISI_X43Uw0iq_mTG=7c*9}G4=YBXWb{pm*jkq1HXa~|OU&l*Sbh$?@DLl)o)QF6p($R1Pbg(gV* zxGM-IunaM?@KxM$r6ggFOm2n3o^M@`eVgP2rd3blg-gu(nPwBXFxpVcSzcX7ra>5$ zOAYFD+Uv|lY=&7IZ`ba2kE5N7J!Z4Fe@6sO!jfY)hyA5WxABCjXH@Z|Z$6W7Aa`=F|quqe1|B+@eofJ0hdivu)QZ27?ZDasD8q*hj%h;kpXd#06m0xYw zc+34JZK=4~t~)c&?F$zv8=e?HT`9 zdAPb1SxCIA2<#b5<^7#DSo=eJHYH?6JMJ&n&7m2zlcGb7G*S{ewO_46!Chw}@GfPJ zp`<|kd`LX})j{sOb+b6A#_5qvqgKs+Ga_!}VBB?!f!avpf;>c%JE~JgwI)P}e$yH` zvVy^%fTC*}%qs2}42QQ{`PFw&Gs~j}WX9skVy;;zrso2Pen!*b*pd~_>t*N^MR&Q4 zzjX7^KQMP}o(Zc1Mey`)${Fh+8*~s@ZCt9LM&DH#{-30W8(iH$IpJ)UgUNcVmw`uq z`S-k6mAR=rHnPI3-Gb1Eb?Fh24rN?W#`ze41I&6XUk$!q$)%lUBKzm9#q99&(wiNz zAxkKV#9ZYzLJLrLp6+eaQ2H8DTB4j?^ppEeOh5j$bj_rSwTK`|h zPEkZcUO?L_hy3Xq7@r&%o}7ZwH!(eVZ!PFXqT|OtGqr${*9RHf*bKNijO+=3&}rewRdpX zGcj~@b29_k;AGn1%79*&1Ky(1p$4GDH;Yfg8biJl8wU`{r#Y)#K;NeTutZIr`Bg06 z$ZBr`&f)iW3y3L!9GiLH9$ub7J_2!{g_Tc904L}0zxpwu{-p!Gyb%Cthu?~x#{tnHAQ_bJ^e#IxU?J~u|2aek3vlJlQ!K6@ne_4F$UV#KQ%Qq zJpu*50mP3>iYo0#EdS^X@Lgg2F7%}vRNETV4cvFt4HI8mf^qf@zO#vO1_so|-X7@P z{af*77ieYxn68=G1`sW9lInWrC+3G1H1#ul`+9494mfAxi^qow@Q9c9`?ctoN3Z0? zg*Dqd{o7?o%3uR(gYc)LSMn!LQF&P0g&B;9kAyY=a}#LxATRs zWP*RPcjhI|ozd0w1t8ZiA?wc;?HxAd_%Hr@nZTOS9v!lx{H1PY=ckR2j zg7i%9vKoM~*}3^!?{75posW?4)s)T8qPUcqgcMwSMMFtc#Bd(c`x-mS4{O1=oCnb*P( ziOpZ)%kBV>{@;pPTRNb0qTiwy@_X<3w%om)=d02OoI~#?#jlJt0O@jX1WsS^3tM-d z(zl&wT;Vs~fd?Piot@`u##h+S8AZ}LUp#0Z$Om{2S^XP$k6HZ}cn^5X4|tE7;Uim* z9d6P#-yKiGH(xwT-_aeMx7^Xwe}*qO@7wgre`jhh|1)gvj(y~gJ<5I6O3*vFIC}aK z|7x$iGQ6|>z7q!VqH zvIBv!>;vcR#`0nYti;>wZ8so$#MW$$O@N-k-2f}%{s}^{LNbv0%!9S$IEL4yJV7^H zDtZQzLL+~OX+(1nH_%3h;F~Md@$lAe>&_CJ%<&~kmB|l!<%u$&dRbXFjq%Zb+9+2v za=Gaz8C~ut2<{TeN-udr<&jJn)_tL+ir7I^pD`#k0NKn$Cw{@WCFM9>PDv9OG;MMC zm?2^jxY?ZVLoQ#AgGg(xwLIe2y0wq&iWV|ExuK;{$zRfB)VHTcgmuH)7dEThLj|uo zJNK!3#JN!Yd{Vu6>hjfGwUS=7MuYW5bLtjx7W#5)E20Ypg6XdXzQN5SteSFs;Jo#% zI%f*=hy#XOwi8N0M5`IQs}s>%;492WGhud8h$h`yDQLXxUw&{#59&XEUO0uSh5l{+hTnB?(l??htu*dUfm8?#3*YKGU!AkMzjR~5i76I&p2I7X$3Q5{>p z=Z%M)tjSn`m~|D;4UnS@#@l(tR6XL$Doo5+T;|JxYQl!h6&0j8GY$j(*3wdBfh0t+ zV<0TyXv$E1eRH`8i;RtY7z9u1tG^>5jdB?+BY!kBhW}WLL%qF?FZAmx_8zLYuVb}} zkYD;cQ`m>-gMrgok#dE^s3ws{WjFWBjWJuxS&O~2@%X|}Q>nh!VyNa8n9q0K`J=|z z+XR{OuA750%Mh2aarSZ7vCl6f>98IAZd4~N*;M-dBEqYP8yG8ZvMaV*6a4q)M`Q0g z5v6GVwj#Z2*}>wV^iO9HdQegr!E4*RM@XuNCfw$VNHy?vrgAi7f1?YrXqnGbr8_v2 zo#{O;p6vd_;MSov?>AEE1}${nImSqsA__wJ^n9%&bbN~js~gy5a^@xAngZ6~jxY_V zTCWWW_#G=P6=WlpQs=!I+M?L{0m<=~aos>Qq1frtsGlahI z8hIjiK6WH}=6ePkd z(SunTAC9lndejwBZqAtZ!D>Xs3GS$ z?Mcx9`UPtN09I&QzkePfAW|Mm=q2qcs|Qi68eTn!I`PyTLKD^L^;2ji*W0x;v1?1U z#dd!}r@K~L*NVS3Ndq;|D07x3dh=Y354eb!JFux@LyYo9j-8NL<_q+yx>@0F(AQGkv*e=z{A^#pq7OtpoKTpWBOa=Zmv+3iqzVqiw=eqX(fS0HVr!}fdcm}^ zdhU~E2G#U*i$D?VSfe4+{7{&@sw*(Lh}Y*!-CGHjz@P3&Nz)MZdh}!gno&F420g-4 zE@#2P!m^{V%Ry$cfr#g>lBG;#@Td5F{o2AHMU?P17}*FU%Xb4k)cPhG;C$ZD@C7Y1 zp;R2j!Z$e;$#~NaT{rL59bZbe4rJjR7J5P;tKuI;9yw5>tRLZUe6eQ*TQ}SYNqRIE zDMKxdgj}`#F)qavnMf5-jdUeCH?8n}%Xt7Ps!&S(>$4R-#Hjgs!oPSQx>$U#C+nmT z>Ix^k_d4~W+Xf9wMsA7Q%0m&drvZHo&F#i@miM^ghxrP+ zGGd56ev<{>ud&2Mtwn{7qp@$|l0F2wG!HK=LUY)HdL5DS3}eon}=N=`+c>`OAA0(d4rbT|(s! zM_?Wp!!y)m$L>%aJjLJ`bK9;Yx~OYBFdX58FNY63t-ZpgFmt~X6fE1#`}vHxY&-VF zatS>~Amk)IJO{X20ZPhEovRq}9RZ;(&N;-E7&Tgo;-P0B%T_<$UHTIsko^!=em7!V zcQl|jW!;yD>TD2$`vzT*xyOY&t3O8m*lQRr6D6$>JJF2;xCIID04NM)7F%d&!{FDX z(0^e5PU+h=Cx3XPlx)(d0cu~GhzwEY3Iku5)v<*2jl-Liy8dL4%)7nj865JinXs=L z*cvt~OyK{^pDpj0PB$VN-_y}hCrQkmP^&HY+W!%R6vey|OrS<1>R6)qOu8i-$Fr{jfI@7MG$V9iuZ^`1H5(tYz_<~h)f^6 zun)2p8X|Jo)W!n`a!=OIbXoT{tYObiC-7_Gfce|STWddP>oYG+WRIMN_qBp?+3jnq z9GAdsc##`@+lU=VO!9d$yp-rdEVEo9g!}N$rT!5)pp4)qJ@0D06%RWhEKKb_5AIt- zbF1kQCbRV8^#>Emx#=GRt#@hJi*Iyh`7A_Z;L>yLN6ld?OQ_w!kzMP);I!jLL}{0T zR%GF-fxP0b3fvTZX^YiKk`@r*@*N$+?WAz1Ea25J>Y#a>fuw5p|Zb(^Zi>)No1f0&(MiK1^KuH8@TCPG1n}PZmymg{Di`PTrHb zS>`>>776+HC|-;FA;n(T`cMHktXot9coAlvqL4%b#nN6@2aILI$u+S$T|>@>o`^D} zbayEpVj0hJb`*JzDn(>0bP5q@NqicjP@*81|Fxo4vm`l!QU@4uungkEr1}An%m7$F zTRwbM5S4i=87W=5kRQ2muQQn#@yhiiyp#$p85Q)WpIn^A)V|h^TI(qLD4nKfHX!p$ zi(2(FwNpDgtarR~?UH{_4+{$*?D*mH$yVvzvL-L~YSW#~7No`pGK&~#*)*_=}iXmm@&KesAjRnH&eBPX~$>69dRP=nwN!&k}+Q}6t2sI3=b;FcA{DS~KLgZO^ z8TkVZeWr)?U8EdAMnUiS`U+r%kl{?-PSvLji`z8L(7w1F zI5|8=?VS_v6up^59WZ)mNfRE-9(%gDsVeyDYkI>=k2s8W+pcp%(LE%#l%GO&TcgXE za4*Q?i$yKx252ayWD;9WkC@CJiQgPD4I3SmxH$ly#S-J?oR2@XrdH4XH3+Im!T(~p zv}@|h6EH=T?&DJ*8r`s31Yb0@4n4V(I`6B)N?zHbDKe_Lp;O^I1P{aEInVV=9nOc! zbd3WiYgn0*QZwGQ%SP;)A-+yneHqd!Ah9=^9T$NDDnD00%1ZAB5JUh&>#(C1W;O+8 zTQAdv$fVgiuN9D1FhQ_tz)$$TlKf7^Xms-56zey=GbDD0L61?)e!9XMb4*zJfNv=_GA)+NYJ#gNR|Y8=k}zNmtRFw+=?StpINiTD-!+* z?QA9Rc@qJg(fQ`RjOKAMaq;K1+H4@!-ZZa@L2W9ml|egvlOiYxZz0*N#pxZj>dx_7 zWRm~pw-#lmR_UaN;ZxJ@_3@ruVd1ild|X#MM^_6}m~N8*cd4JI1741&Q7p>82V#RO zMaa`RPG^pVuPXN~JwLJp$H1uA;+1A)QEg0Xz-pWpQwsZFI5HO1#I;p^!}pGyRIcc~ z)2AL%V4{Rcw-3_l)Q!m*yo{Csyc89ds_f$f6iPnv=<2c>E+Q`i&tV-xFsg66PY|G^ zc(@PaPPhj$rStjQo`{3Oc5*f;F5>bBk~Mco5FG_?--;X>72lhV+G;8f>Xl613_{;Y zT%J|WW%OA*lg|V@pOq|I@B@->ecNDy5{b!TUNGvoCm`;k#Tu+*K7Z(*=$HBVSnjt> z7q$X77#^N2(tz830st^?4St3>Wu{ayW+`hd@v*8PD=BmVQ&nIM{LY;zJ$Y~|A1Z2( z#;MdfF7~T7vhh^t@uFIg?ZglbJr9VAVGMiEr`bgR*f|Inoan6cA}rXm&J4XGCXMnxu~$(>m%|b{AEafMv@Ya z{qBt3aV=(2Gv;NyDjVK#Qa~jAXJ8*cbD8YRaj}TOme^uV^PyyDj z#o4Ug&X)(-4UEoz_E&Rb3*t~%!^T>l-{Q`_{1ZMKvfx!@jjKn;f~e%@MeNuhvE2K> z6>M0Xl9|cVRnj^2sGGf6^f#1+<%MmJnS(J*PXaw`B}NA>Q&b}ea-5F1`q z*9VVtCGH+pyMiYe=}b1{4v#A;Cn-Nmn})(zBTv_;97fJmi}sJv;cs@e|A0#oI6$Pg z+OI|a>9qL-#m|Us`Qp?0wX|pXY}NwslOX{vgHV~Pr(%x0F;{WOkp<>M^~z+>lS^C7 zrVC`{mSR6tuG>_Yk)Ys7q8@29z67~moIO^Kdr`Vb2xR*bT{&;g@Js6W_d7h_F2BCN zc17r47cV})t(y}dTBn=Vrv#U>H+RHS0ZRt9&{%ay6uAqF(Ii?kje^xz*tfzE!KM`I zGHs3~`B>QH3f<~qfLH^S1EeW6!Lt-ia=Zxnn)Twg%zkn8}<9{Q&kk&zjS>>nc1RZdROlVA@eE>t_z>RU~D= zlX~Wrti=pN%q|v~h-yW>En8)x{O>b9o@q^_*PH5QoiK}70lY=*Nsk=Bu3-$!sR)d4 z11d;LuEkNp)*+pl-io>QtsEiqje7$bZJp+3eR`^O%{-;KHN0g;EH>l_udr{KT*TLC z^(>Ee+X!J#K|uSt`|yJ%v}AVJtTeeYylB_ZBJ}DmK4vEt(nR=1KSOQ%bdgElxLwIv zZMoJ zad2vS`u!dNvRoQ=lYBpr=i_fqTzt|w(7iz;-+ZTW&6HWW0V&yfG#PE z$PWnqqzLhPC;_6VgbLiDSTSgv07a8*B~wGoq@D&c>X5=RCRfAK^O)myE?Wz35=27D zs;S1b(^goRVV3T3{VlxCw5^6&M^wH}bucG1Hm}j2E->QL?+v&Q%BOB6aG#;3gIR#{ zy40?ev)?xvd@>IqX48-adfncO@8-_qH7&ATsQ2MyHw|q@cSw?KQ z8aKg?&6IHCcb^TDt2Ty~#ycBoZ!LF;LM~jFgqx>8MS%n>4R(2bUtBk{DQXZR(h!>8 zupx|E03E$Fa<&yl>`@rWIyd;T-3YMt2>GnspB$7vyg5Py<=9frZ>{gvE}aV4uJ#P~ zq3Zc86lgouq?Msczbc~f2vlwQ+R!8^De7!lFyo2n#BChQ0zTmo(Ofq? ztaSD$#{G!9ry}}oxOGp_Qwm?5(=_ePwi zhYxkk)}wo=A%)%{Onz-f;9@It>%T9F`casSAkRy=YHi}owL%H0aw1mFWQ>Yrr$S70 z0Jn)Pd+a)h=s{b!Ow9|6uywUR6^H2`jha;CoZ`bP!4u1WcA-8;SJOfw8rMC)^;uH8!cYnf zW~~Cx_KV}b#uOX;hJaRWuzbn#`7Gk3|D|cm`#cP=iL;0c5EgGER{(Cu%o7hEZ#JTc zmzOmN)JOxHbE^~!C>Z8pDHd+#lOrJ*kN8=&qM7vtej)abnl@Y~QxCeH&y@uevlGRh zt*OoP(Q;__;&b4BOCJUi`)99rh=0Y;oPw>(@wA%b-t;=;er%GBdMNd)I_&H>ENIF3 z$;N4t2n3`Uju5)F$|qGn+1PGlk@4@fytWeT{WbgPHM6Z>ACc5@$91a2_ZO zcY+GESQeca55NY*qOx?TmxIjegxesCH0;>Byi0l8o64Rk!91;>Ex$z`+-B>ZYbr$C z4EpQzfF-KLxR{}&!ytg>+v>uW#<-)hvRp!b!*L{+3Hqg^c7NABW<->n-M?2Qipa;~_iqtn!P5<<}1<7;-kK%-keo8X39eU-#|HG{tCW{WMBEz7Zb_$NQsi zMt(WUuia_clCN6cZ6iXuVx@#a2mFHn~Y_IT19BPnJJHIu}+#IZ)b5w@N)w z!QAHk-I8OxW$;?UA#y}>Q-|`tSH=mDL?{y&>Wd;h?Mow_ZGD$pn`SWxP{N>uEOTMq z>t=4!!=B7=mEtCdKA5TpoAsyX789cPzw3wP*eOh6_dXOzAh{i>v%T5ZVh_S?gJk$T z(P{+*3P)6dTy_u5KsV6s?J!6|e+yVsFJ$UVzMwRMPj=ch2QKt4$Xnk`L1Y7^Umnedc9pYf1}W{~k(QBF!9Z%@FeiOdjh;zW0mUTu z)w?PhSx@z^O8;``g&Nl2izB9p#$+!X@+qNX9bS(RZZ0}F87%RdvC$quJ%@uBOQTl6 z&3CXMa1zmmiQT+R-$RcJfb1FrnQ7At!9xE>Ia;ru=3q_Z0Sn9j7n?KlWh^NO;*c-)))9 zd`>=4u4&31(^eJEoqqj$X>J2(3phgIt>vHL^qORQf&%$ILIpeGuP1g*!rYG}D?eRx zeLPpC{L)1JYd0UMLz~di?4u4Z_JhSsWvxw#;&UnT($I!xA?_lzJQhp!BYOIy%N!rOx_m})4#vZ&ji~iNL=<1S zag}E%m*NM@zC*zfz?cn42z<6pkm6me4~ZEg0*#NfZDm4nAw--Ivx9J+2ud(Nc!YZ? zW<^UYba7xXMyhUG7Wd_ndtO&m#x-CgneFx3qums~J&g=w^i}3KS2wHnnwz&+H5s;a zFsu)%rlGxSWLxWeO{25JlDb~4&R%Sd#du{Ww6)a14(;RjVZWubmj1zrUk`(MH%hTu z?sWtc;7I{>21x%Ryo<0=CB+AM`!)yBpsg2CV2FXc?P#}F9fOM44BYU`U#+mF@Bddi ztG1M7l@$P}GhY4IU#7t5psvIwhOyPBKzU+?V+p5Za;)0IMa*{s5x?Gsw zRYe1}n=AGtWMp}X994)+w--M`5R;jVM@#o^-hash#jXE1=B<*P9Kfa<)1t zdfp68H4asFpnG4BZIZwkq`oiH$#TAKvxVHC_kkT#Db?L0f`7Nvm#^34RV?N=)>FiT ziqeiKGaSzj>_m4ICa=UznLRdW(X=frzaDXPPF-ODTJ|=_txeS_ZRj#ne63fL($17X zjw8Hsy}kLVi}I@&1CwmyrWbYB>QH2&gwu>u*=YCu>pPuMqd;Q)muxD34-(_#1TM7Ny!;GMUT30Pxa)P~gh~qfU<2v9K(kgqc~eM6}3>Qnxz`2~GiV%%U%B6oI={x7nKt+U0VIQ}4KM_YcFkdD=_W zhTg{wcIrd+S`lUzkMV)!?N7lrD>w*5SU3~7r5}Wd!y`|eT;f{3Ja$yvLUAehge?Nbs|R%LsM1|AjdkGmMH#7a!=2ag7m+)O?0{w z!xRn}Vg9>z%}(D|`fqaWX{sVDui82WSN`g=!jFt7f%1HQH_=*y05~<8+G^L^xK=0? z{bngRzt^`=e1yI^!vYnkXWQmDCZO}gI@#}}Mvx$7ZD;x9r^t4Vch`dzB1wsXFwuUT z?E*N?yaqWwrfJRXl_Hd!0dt5$5T$HTlrL3~s&78`V6=+p&ZqM-3g?QcVh31XCnypM zXB8V9R22+OoBVidC&+~h{mr%22<=xiOh6*ugE{gw`_=s)t`0rEPo&nk1k93XL>qa4 zvLJx;wIS;UbshYNue77Em`7QZjE7R-#vj6?qW*Az&#WuCAOC6>Kv&_(=A)xbvV?Fg z)rp4wCA*>U_iwQ@FGk`C0zUnDAsdXCjbk}b1H(fU9=vd{N4kDy};)4xp*2uDavt{4dGdDl}9CE z<#ml386B+mI5J#pE;D>VE9twRpHT>yV%WXPa=`_`e48OP%U(<=pyBS7bqEZ_SwUnB z9e*f>SC!V0PjIhHMR?oHoP<>XFho&O zvPX8}9;MQIpC5dO&3=3O@>td{qB^4JC-eyl4{Bxz2C6uyD|p<7LV(o-dfa|gB)1>; zqKWVgd0Netzw zKpPIiWo10`N^SNP#RvuOI9W+nTH`YBg9O6*8$!t4#)ZWKamgqop>Vj=WiF$l#M19X zgUBTZ74Hx0UBDx39pZ#N7sriJD4Y-zA2zH6nwM*=G)#+)bTqjb;MW~2T2W{8)zCM} z1MJY9JGj_;BU0%Ne*#{iyzVC~Uxt4NN1ZvF3D#H37Y7{mlz`7Vp`%5EqHxkR!~+U| z>Qxp#x6p2SfZd8eXV2lLzN5+}GBQIwfZ_D-d@VqH(BC{*#NXrs6#*e&MEG6I z=l=24vyR|8Mt4pq6^Lbdb)g-io5;cW)qklS^_Ca2@0`o;+Gre&l9-n*-pa1zTqID% zwVtASG_0=EoBk703g~oeL2p(}cnfLIF6ei$AkY&e{ys%EgN9e=(*3ne5FrfHuRbY* zaX>xCKw`oT^eQxL?2i!Ev%c2Y1TBYJ?rxdlTwT2WHO_l$FO60p8KLd@iNke602*@c zUxaWY=7WlOoezrQbiQ*J;lH!R&spn4J$vD}__EJsu`i3?bLw&B%|i5@KbR)>E&;xD z#s{LK5ebHhq`RP$LA1mPmOjCstjP7KCEB`NP4gdDs;E89kS$dWM1Ae)K2`{yD2Olb zBYhh7k;W;st;~~g9&_rv6lLuL_~gCm{-?M)0Y?jmRlwgnjOxwzyc4La!Hpe-LR0dN z)&)?%(LW30@*0yqWwSKpHt_I+H0c_lrDH=P^qLt9?b5CCOWZ zD^Xuc#Y%#`lW~G^R0{ydxW7*0vaiI%jU8I0=kRCyOoaoIb*Y+BJm3Oi53zMzCp|SQ z&~$`2IlEZiavF70??faZ(WrHU+&{{b`>5DwD=A0hH|lIO)ic$Z36rKmv>VEcsR!gE zUt$`2RI~|H!Ms(;;uo4$mA%L7%Ps{>4P5M<`32l+X|+Y!J*q36uM+dYBQ&kYW_B@M z7d&T#@scbrLQZD3{aK#{6fFmO-uw(?Nct_61WQO+qywJ@;@l>RFhO;>_xKk)E)FFg z4Om^Kb>%UH=krLMftU*z-VJGy>h*n87=36slQ_IG)Y|>uRQ~n%-pS4QqVUMU0e;cW z)Yb0N^V~}_a0AYS770`V-i=qRqdO8qagZ7HztfBxUdP(l)_*nNs@|h>Lig|u`glq^z7R1~sy?|Nb8c&f0K*h!8L{6W{ofhn z$~raHgoM^imuPW_csZ<*Yt%;TJ9Kq@to#Q!l91^xdW>AW2-o&j?~aX$9|?{ehu&%) z1Gy5%ZN!eLX)S?UMLiG~1*)keeHY@;h;98lnD{d_+g_2!Da{|M7(bCULU|EK8Ma2d zax3_&qX+=$eB6)wi|r_^SPV)1kvT5M=X=VQpY3aUW>b!OvNv}H#~93}Nt>WSVmsg7 z-3F-gik-1ZOHdy1(?XDQYx|XP5kzIS1*g|qdKlZr@6OD#xB?Gn37gLF62-JQ}R-5}D90-}htbT=YMN|&Tack^HH>%EBg zec#`G{yaW9bN0-f&zy567SGJ_&c~-6+zN9l95>B9Y>93jWLvRJr#MH2{kkDS`;fr) z(cbFjmkcJK-Y=bt2K>ZSu7N{|()i&q9NAR*t3WuD7O_yiNB5ayNS38Pan$D*_6;IO z5ox3>B~F$Sb&LtEucLg&9ul_8E&$ifO{8S=9!4XU2A1QUSX&@cXg__!zO>qq_bGt5jK$JEYncV; zPNYf~DfFyAk)*&a+LMj9VI&rDpo=U#$O=&OImgpQ>LDL4W}fCn>g>2|eEC}jTP8R3G|W}{9u?gG^*9`5jS!s@ z@JI}>NFKFwCyvvba-N+j;W;jLG%eo1mQX<~rRc>R9hC%Itu;|yR)T!mSbAYQ`*MF5 zl_qsDj-Xv{9noouQ<}@rDqHIZvQl}}``wQ|3k?8OtzIpDAE}dXEj{S4Y;IF{vpjPr zFG7l+?}Yc0xNADg=EB`W*XL&aWMAbv_4pXyTgup7mgCJm3i_e|*hnI7)X(g)kE?71 zwOoD~fTw2F+<$EPjOqFF(AJ+C^YMH+Tq^R<1m#aHxr?)mKD>=PVwS6p88%3*h-WL< zVGj(;Z-|N+_!*4Oc~_UO-Bm}D6iLD(ks?m7X|+T)wun>;ZwJh>uu%d7fJUlAnP^(fCRH zyaJ_>(7zzk+3lrIxaOP?$Z=79Kuu`+{F>+Cf_qoK<#>lKTNve={&i!HwfXO$@Yd=E z+n4-0oT_p0v8pP$Re`ROU(|_5k;enqi^D}pnpbrPMi2O6+=ZrIwGmZ~vI?#EB9;b? z7nvirmpx0zK=*i;#^`#;|1tY%o_h;U1J=IS@R7ln1rB=2lg4>_@OY-ORd$i2O1E>t z$I=)XZc{W?bTptTE&2)Zy2uiF&8(l$yAibS!SC^YzKzI@rCQ3QJ6A+9<(MT6psMT* zj0hJOwh9lB;*7%>IdQYB_RV!z>!VK>eV5vj^PvJ=Fd8&O~~xRu7Pu|WvHDwW4&9_ip_+JYfuA%V8*M9v zW{LTt=%64o%;iJNdr5-F!sYBm&X1B8iW?x=S(xjbe!LaQC(&a#@$nIXA)a2aAP}em zOog7UMchWlrmwKd4?j^fL2cEkC)ivmD4}@dd6^AH$jt=Qo`CO9 z3+<{=EboV<=$FLqF1?(_jxxHCpy(G@)l9N!)wtWX*H`d!*+ofcg$9-k!%_o%F~zZ# z*eWv%1gG+1LFS|UXVdYSbi>nORKJ~P{P11h2CI8cBLf`O^xenxM|hGATJk3%-jav% zQ@nu3&%M|XwWVPbppcibj#O!iN8)f0*WJAnZYig#S1rU@okYR8J4kJ?n>~67&-h-> z??2od;=FMM=Ks1kB&05*E~pB-H>9lmKPKmbT^wR#18}fG0ANnAHY$stqoJ{l699a5 zi$+M_?w>nA*VU^8U{{|pv9hwFvPd}TTbUaQ+L*!;QT@NA=6dq4*l1m+y zl*^FC2$pxt43=5TlEv!!rjXrrek`Z!+*fXYTnoCo1$6UT5CnKbC;z$@1OdS=OZ}>` z0yu%3|H^^&N75@Gh?DjI^;S>?vOKN@F<3gm|HUhW`>zJ3Bp*>QQGaSI$!Dx7Vw@tS zL=pFMf()b$OrZ>*_`Y!Z9F)GBK7V>~`Q@;ux5#74Yij#Tqj2Ht9(wD0kh}Da`r@)W z%w(V!YxhY>72q&2`3W#F$;ohHFp%ycpEI=^4j@yI0PGS+$?ue)U}3q@#voE|uIV)D z!x@Xwy+|N$WT0wiU~F$eoSmP;K98axp}6xBkxP&fo~07*vmIe4e3S&f&2s3A7ayZt z%rACv8ZDac%;MqUEgh|6yevni0N@J{&LU%(qnFfmo5A}dl+EE|VGZmzJSmb?dldc5 zU~;mzw^vI*^DZ+K;Vd=+aTZNb1F=j11K^L-`CuyyD1dHu|0IlvfDA{VQk zFwpNgXQ++*K)O<~Q*jjOlUqYNiJ|8#hOlt27-7n5u8JEjO#qIn8GGT!Meg?oY%&&> z#s>yINQr)pScKCJ{hO_T4-H#WTi93xjST5EQ}f7MXD4U7-A6WcjB~(uKO2@Bmb(X(!b{tP%Z87a zc#D_iN0*u}eIMbTX!e|FUS297T2si6G@x(bk72vH;IhoRDZegTGYq4>(+hRK}&}OM~NlylqbDr@jDJKQswS+S}t|x;-L;= zWtE=YLfZY=$TZqU)X2tD4tWKAILKDQ3gp3qN}*2g*{M~#luJL?Gm*P6UGm8J3SIm4(`@UAzfAgDc~xmw0~^zOU~6v1s)+zQ#-=`ayt{uI4tms^mg*Y zY+OGez8FbmB*6}@8TolgF@?U(e{`sH525M>Ni4)U=7< zy$7Svsb#F5$OQk=n2P^%x@?0!<>&u#_5RY(do_lUZF4=wfyp;CyLBqugSfOT2m|Vyjr6n-Hjrm zhgc^`+}A~A073agKQK9lq3$b(z&IHSWc^O~DW3XUnulN4@x?h?vnKjoo~MTp*w&dD zH|R_wsx35#ADDRDb2UiWeeK2bSm{ODgWkjt(ZiC@y3^n5&SG9!DmjVNzKaPuAC1>) zi(o0G5f+0WTW5ibnLY1 z$-b?9+&W&ewaU00P+BEOdu0E#NiO*Zd3P{_8lPPqF14NFtcBeVy>FUZ6y(QTHrRPP z7M?XZ3p@Mv_tGz$F?~N%r{T)}9C5xELulO(H5iPWxzoc`P0OnNj-^(#sSJ!u$TKZL zqaJAA-g2z+W$x^3c8mNhWhT}7xEDB1xn|U?6nn=Dcu%OUmU2A|4<(`E{0S*Fz6_l_ zM(hH$Sb8{pltUaL*WC!sHT|vA2XbNZn-7(x9k-{wKT@u5sn+r>XMO;|k}9fo8x6$C zsw%;Cd;(E@mtvW_^IQhAlsm_8!G}f--ZqxCy01RX2oJ8BAEnQUahxg)``Mncm=s79Jrolz!jU zf*F>I&f{n*sX&<>Dz2uyI5qUFDq+S#xkTJ$AUj;^p{Ztq=w>gydg3LMMd*sV;^86= z7&-U-=ZO89r`%m*ILydP~3?`krzf46beY~4>Wf`5{^M4G$+ zKByacotbp;blAF?zf+D=Mn^2mq@aG>8z>hdhKvzGN8shiAKQTBUCy?JQ>7)yt+FQ~ zPFH}8^IT-g>bvO(tFd|)0_2PBW54pwT zhDy89^>zJZ#mZY?xe||>ejG;y@Q3VMo+y?{saU#3IBsxB$|!fP|9q&xZAKs*cIkxO zvHO&niHw5IxHv3ajJMU&&I^3RHXvNS>A$e`BqTF%d&*J7&uPJ*2u~0Wqrbf0)L}Sw zL>i*nM&Gi+%sWvtuGTfWI~P3F77%}SmxsTNnqQ!;dxYC-KsTJ8HvrM7;seo^oi)GL zG2xi2);nBF%5RtQQ(42&-A2yR5l0{9u~kA#tHw4G&HQEuKdl6LZXf!2zdDe-f}~i7dIlD0Oyw#np7ykgjTe02#F|{!3=9 zFtHOxO53_+uX!3~n>on}KE@lKO_@sbriaJ1QsZ7AmZj%OrW$ELsLlEgsZl7}RioNn+zY=?R=AYkU?TL&X{+#vMx5sk&!w75V1vQMm_KwY9TrcDfIDhyr%1kwmM3@(<0( zpYOzoVmrDExfaXATj3v^(B3!cRmS0oE_>}I`K=wtY|)~Tv;Hf?r;&FKuyO zN%-9?c2C}F@p+(1WkxFUA;4M7Tc!47)=5z*WbivhmXP`+Yv8wwi4VS~AVeXp30dx- z{q_g%C2}PnO^+iBSEt@fEz$qR#mkK9?^+!7GMxMQ*jV->O^;$q4G$JR`5wL9t!-PH z)8{_*OpvY;dX+j{hQ}1uxsn}R{9T#joFU#)KWT}c9S9O{pR7J#i}HYMtQeG6Y?!}u zlv=Pu_lp~$7k>U4PJE#yh{m_j3pG@XI17h-hECOTi23;e1lx6=vUkNJZ4+ouwkjbZ zKJ@gdBSphnqzkWQ7AJG!H>G=rqVRj`#p9fic5r$k)Y#jwi~KVCHZ&Ucs$6@&v6 zEf<#~-{~Z2*AX70&loz)G-#859g@D>@5?WPVZKWF8Awu8WGCyrRR4sAm;hfwX zjxsTdO%OY;6kn$-!RYU7!M4)Tfb`xS;l-SRZo(Ah*6af{sr2XExt@{3?*S5hBi~5Y$ub>w zIR|Ppig5{pbW7Pa>BfC`Kl>>+ANnZx5ompN<<$pFDGkVK%~w?e$qsl8rYstCVolE9 z7JeoAMPA?hiX7#X zYZb-b*&^Pd*wQ7097E`S60oZYmF7Eeb-C)?p}5y6^WbDGDu>7%f$4I~n%*|bGY%XP zc8V}CNpXnj^%%OZ8mMHb)Ib}t8J*b5!UxoP`W?3?dEH4H{utbJx3YF6 zt!U|>Y1d76{Ol~-T*b9XJ=1t9te@ieDNv~J`+Sx`V#mly{^Ij=w^%7lX8O;3cY}$F z{fCp_XCjXaw}&&TrJ4sb47d!!S;e*{hgdl33GO1t?QA{#i81fAtG z8ojQ#v`;-JORU5+cq;KyPfvgFX;K;~SE!$apU1!t^JrSusJzENqjmey4@@ms>E7Th zqDFD$Kackmj`kl%LH$T#e7K!Lxi&<2$UF7)!R(f2>P9FfKXIz7#g}ZhBd4wQOTF~g zm@I8#NXqnShzs|K0+`Q6+E)p|!B82xvKAb8hL_`Rt$J5G0KeTWT2KaPE>He#Ln8HA z=z-De*`d31r%KJQgK1(zx#*(h$J)CU{Q}Ps;$NNJAC%^%L0j|c+Oagm0TJ^FKmyzt zXf9oIVjd;;%UyPMx)PscXATq=4RzzxH$g5Glj{}aOk*&r_|p~= zyclJ(@>!`-d3P+P$W+R>1SpUE)MiY{ z6CfF7WGbXOZ{Ir%77ro%+gB=Dj68n<{3@Efi!dFBd{+sv1CJMiKwr)kj1@=Zs$*(( zB+~vMyg2c$F>HE_4LyL!J_us7c$iI=G*CAZstg|UJFG0?K$GN)km<_{TZVwU&2o4Q z80cRR*#3OZu*uVRQAOXsm;k_7`P&?65ovrzUt3cu>OQ=WE^C>)s%H9LQX6B*Ks}n*>C4HTpwtNJX1UOJm~IE!2BUWt z4_}si?ES6>KrGZt*kf=3*FPm-LGbVz+o**Lx`zB7>;{2=NMEL0umE=sU^^35E9oT75n!r-+^E>UqE z^V_(Evae6rrS{s7juDDu)LtK3awD2V-Gsz9_|2O=iT4(&?io4OPz|R>fZL0YnfXicQYmKTaiaEh`#R&~6Kk)_n%tJCY%H zzWXxgo7cc5DeTqH1k}C#(ZGT)(@}MV6$vWSlP9%D<3v9XUODrBObQ^43I*auIqz23 zWy{b`9M|Y*>E;)>IwvC0Jc9JQ`ZDzQ;U-bLyBE@!8t`_|WAuJ(P}a^hdAu}&mrCjgy~gADFz(_rS9^s`IBfXm1AbqgZBQL+>mQi< z519`y|?jMysD$XR$K2wqn-IOpV|{Z#b$rMINC9!tR& zSMv`aEyc_d=r_yYcB)T14);nW%y^<4Cz;3^LV44BSKFF9HDA4IlFc$03Zbbu4>nuL zYSuHP*(E`%A+}pZNGqbm;Lv1q_;fa0VzZK{A=^enp^5dKHF=Sf~+X(NY!NnVZh0eMm$JmsyXjspfBh8uoo2I+8;ZCGgBwR!+ zMMuq|M#BV!&TInauZov>$IY47D&7sRF^EFPq+qH&Zwly(^(a6} z5av7J*EciwzK+%()UBHp7K%RuH;v&iAY)w`R_6; zv8`}fhivom<;{mWnoW0fd!NgqZN{Fz)WZDo+>`^}AwCExSc(bM-#GbS17wlHD6b1pi>}$~mTdjNIeV%mvEM#^Kn#S*VIb>-nVYHkk{ z1hvE7kHK#YvIyBr4=fT!n9v!qdOa1`m34*!QUn{#U-RV}7BqI{mi8Ad`;+0=8d}(G zT677lYH={``P3X{4k`-a*03C;=zpTUV+2B6JHVQEOy#w~Q7PvbFUkWZn^|a%Q0qMI z%6h36XFHsYjTB<6v+>d*`xI(*K_n#))XkyB6We!p+yQRWQ5s ze-MWWl``(49HGqQqtoI%Vct!vA`)#~|G0-iMEPCDPIAPRFr;bg#W`!{v_jw@M6=-M zYw4t~)|2>(b>JE5Qj8& z;>vEs`#`@4wl`njM zKt9FrMP30&-~+YVXS+iq9K6>8jtu z$g57Ju8d5M495#PDO1-AP7zPW=QfWF9%cqGV1lvcg6_XJHj%>hd+w6Qg*Pk&YIRE{}k_p88w(%m`LzwHx6NDRUP!hT~-Q54N2l9 zYBgQOCSA2h#IkIEM&C#GKAe_;yPT$e^ylc&s@(h64)&zI*p#3JY?+*CV)c&VCuTK1 zxrIV}JPQ+8#RKvSjT-ODhm}=aauhBoJM5v|e*HOT)+sG)_h}{-Js+%K!k*$E?L}S} zUJpRdDo54IX34~7WiDKuN!`WBS7(Zo&3zx~yqOAKG~~2S&n=zlG~a+4t5G2JF(yxG zOurJzq$N}2dC-K`R%CoXpiU;3I^}7dWU<~(L+B%{N1p=-oilov7VJ{;C6Vi0MxMO{ zlTt}LsCFo?L_8BN--XDqzh@7ju2+K7B_2njVdw2bDy8NAjZW&Od{24s63yTI0gioM_oxp>OM;crAI zI=)fo`-$oMy7oM5>l%?-wlV!oy6c4b@7Xh?y2#Meo4Iy1OiFCc2h%j&=N~%nWH#+n zkax4X7c|JIuy+NdN<%MSgwuA+1L||F%Pibs_g#3H3EVMv5u8dFRH5Yg1qU2seP;2J z-^XRgvFN_u?NqN%HwulQE;eWK8YrY|;N}tWstQF zpxXNWY5orE(XYIH(LSF$PD}z3gdv|Tkkf3sOeE&Xbs!23Ag?Xd?+jG)3BBLf5t#Lp zXcc6Z&#`NCH9Z_M=D1S~$NcQ^B1rNlmptbbw9(x{qaUm1+9pWisk=5m4Nz&82qb5T zc?^m5;lA+fs^v#MNPGBQn8uH#2~6KQlkP$PfQ?AIpXn1*yi(r-N&cnvp5|~=GZS5- zIdOVxtWs$$bE*xt2PtGpt#042pIp__WGv~kg5GX&a$kMzn%L|DUI1A45h z+;D><(zLh}o-`Z+q0Bne8{qE8_vh|tCC;ow_z*nJ!K~S23c(p)B2DNUISrocpNCgS z-j|1851y=ar%={sGU+KX5YpjfP!~lH3#DBFZ+f5zQQM6uPkgo~BINaQ#PLTK2jNCI zIX!qqRBy(!+1RlRVpJoVQLN@w`(*g|0>HiP$J)9cJ$oR1oO5U(Dd5$mRFlRNNnu|; zrNXaKuo4o!8-GaoCaBhtcT8_^7O!oRucZ>;f!96}6eU!3f>6PZXZ3^fD+rqeuQEin zOY&&er<b0qm|Ed>TbaHYv<2DnV${I*hx!_QJiEVQ2*R`D>laY zkf2F|^7_7#7Tk2caNgO5^R zM;QXQBsasHwippikGbTfJ|}NX_`}qr;|G4)B(FlU)Et4|oVl1dY@$sL$nb@1E_IB( zekgkcq5CbDAwsy#bpshggN1;RlR`BGgJa2KuIpdv=iC$tsD8~%mc8!dgKe7F= zp!EyH%digsXjTd?6s{+C_{;pnxZz%PG~LTJG`>86-JHl z{#%zZWw{x>agytOWOj0i4{dVh?S_vM!~29m_vsgv)ur{~5+V^~PR*WIR;uZ#e>o2g zjnQ}9OBNMe>(ZWz;Xo~H(rM)ZSyFmC&l2yMh*BFeK-*t5arzBJHFg`L;fj*$4H2xv`8Yx%)U!%yXGie_QMxG!A#Ysv5=kZ%Z)nUHUn-g5`)180_$XG4GR9YJsB4~|a(#k+D9X#zTs$bSUX>b8^-*J1 z&jiq_)b&11R`Tvd1Z7Ac$msie|NGoo+ z9DN)QRUJ}_G}}@2-+DyW@&i0O6%er=HxgEi_KqLqakMsu^7+=LkoDy8iOAXroLMP< zOP2Rr-3DvF^~W*|LCmW${^qvx@HAtTNwK+#3A7W>#k=~!D=R;zhiK?0El)e#6SY?v zt?t4PG0x@6{1L%j5an#bVGj|to9XWj;^>oyDOfwEe;od zqn=BC(6)NYT&ITfySGhru!{gYjH?pI&my}ew%BzAshd}jxs&8ewdS?nvxbV9{@B7; zwfBrmeSbkmDQF59aO&)P_Hw&kxT%k8_=z(1sftD8A?kSMH0-tWM;5(@LfBxBiZ=xG zhE=0=oLyN`QntITp8{h`8nPRmC0^ue@vYRpo%$ga>zJ985#=bZgHKb;h!H9|ydf=I zt9{6~O}B61Ud+x)%e?uR(cd9#VOxuk_p!;(A@6q}PLb6`Wtc_IeUTd zyT5-R$cMK@wNKexH0b!0&ag+Of0Ili*5{rQDizb4^-=5mJ6tw_%tMJ!U@08l7dbrQ z3c?J^&IzB$(B`jr#wsLd6X|XieGXFN@hu`@iOaaO(10wj`zfgf47FxKFbeSU(GNWp zHEi;+{QNYJ&@f6sTVgY@F4?TS{yBE){613os%%@3;@n)43WOszWdG+&ALmeTlLmQ& zJryKB=vlgtl;Z^)X9>RD?Z246hVwG-Barz*ph>2>FquV%w{tyyB7C z`F?!vde>chU(cQe8U@8AtDR7d!1KOJ^roG3!tQ}SyVO0|`j)qt&L2g-Ln{;Adgw)M zOVH3eS2!B9pMLh{RxlX0N+1MguksGFJUYue-*R%@X8ZWUGY`3?g4%Agp4??K6ZRh> z7Jg;q>6~5c_VGxFwQbwG?Ul?U@SuL5mf8~{5b*{s^auM!e7?{Qj$GE0k-n(O6QWfd zwq~4|w{GhNZ4{q4NEav_o?*WYul!I)VA>_P$3Bh7k4P4)cW@B?^X))QaxFwhu#3YC z6vxG-MBbuZaokk~TJk1G`a&Mio{^O)yilC7GA9@&?5obt?Ug0PjT>QMv#TyMdU4b^ zn2bP1vj)t1^n-API6HjVBf9NP+`cr5od3_4s~-vAzwXF|LOvHRQU#jR+Qs{zx(9fC zDbzUYeUdcci9T8GP6f7^N|NF02r1n?S)R5Lq~_(vNm<+S&Ze1HYR@)*{XwB10h!Xp zKbm6-^Ibje;BMuj4to>un-gAfr*&HnWFeq7^-WqG{+VM{+FQqnd!^2^>i2iBJu9b> zEZKOcosk6totTL?6=~;cWb)jn+Gt+A8L2W42cDvy_2*J!Q4Z)kGb^PKi;6>J77byK z^pC{}@H8pJ8?|;Li+{w+kras#FBD!QHUl!O6}?#!MpTwDE@?*{&97(NJ#4h)L|ytM zx5|4@jxXe8Fkgx`N?@E%HzDPgz32SrWbs5-WQ)||T1h^5%4V-JMRDvw#{2@+SJsek zF)X9({OP(Fa&anycRJB?8LOj@;uhYqgrw$aO;Dk((TJloxjZW??t0%NC(&2()PUd~ z1W#jSjs9Lb9g5{=Zz`|SHt~J-r6qQ*(}|WN6HE$ zfNq2l{$HV$>LRKV8WPu`mH)$=?BIVQE7@6Lk(JQ@-;tI7%Zu##Ec#9?1}p{+`i90< z#wM`xRms8J)XWJMS7~Vb`%QM!>-fswFR|O*e1qMY#rkGPPPsJj;r_Y z6|bIRcW`vNdR!iG9j>YWyTS_V>#4bslbIuca|>$Fj(*Z z8yI0FHD$T07xZCZV6m%L>^H$&1=ap9U_g+6gW#>7L1glpqPa8HJB^k`4bEH z*Jy7jh8+xxWBr$6ZeU@*9SF<%-(yjL9ZHq1u*gXK2P=WEH2sHSz_3u?e}lPcr7I8l z!%FP`wPIvN6{IEPU|P;K5{%s?9eN$scSQxskGi*VDbtGkO&4S@aH;@Yq*4!`vb`Fk$NIXhXI+g$Z{z3Kq|aqcU4zstWwfo}Bk z$690V1PgZm;DFLjRp+s?H_4|X8LxpWEs~0f8jMTH+6O}W(Hl8ei?(#4rZyVI_P>8 z0Q{=M#=!Q^n65vEje-5TeiP$wdB2*l{R!}%G&XcHx3zhEE&d;s z{EG&I0J@&60J?wCU@$<}E9VUwtUu5%Px?3Cl}fMIoSSfeOTWqXhfZ(KsNazPCHhLQ zw_!tIL%D`{Q_Rg4{}u)LQ#&_Tl3!Ef+T|1hkYBcgT%!j-t|i{={e~0%kDcF4wF28J zVg3ZUMtNguK&~|Q+kbu?3WW4ww?b@9QCZ}#rY_)mPQ%uN-!t#`Bw_ib8OW~orkY-@w?)k%xyx*4f%o69_BF(}C#u_(0bsR#=Jky2J)6v0azgVI^%? zE*BO#J7XKcYtH~&tKkN2=*`27ptF;itpgoBi}KavhW!gW(OAG-3RV(=rGtT;Rp_Mk zm5tQ^F6K^V05jMr$HBqa1YoCcXbBr4J&U}9t&ubAv_)rUWCCMj0x`1#nL(`dEKz zov{(@$fIxNXbe-dvWOb9sI!%ofxe9mEU68hvYELf0QN`5T{yR+v5L zegmYxp%GWukWhgDCb>~PZ}%Re~`h>{+C=f5EQo9{n-`>;`ob?m4g#D75?O7g=zdR8UzGe zId1ZSz)(&On0x+7<7B(?om(`HtHbdv8Wg6bKWIQ8EA(p1y2*D%gWi$>qj6p>2RHd( zSfE#{*i9M`$OcpDpEMAdll5vpyv+yxOD}AotIgylAFM4W`)$k|Q1I=s0f7)0oCC-nB%IG`N2eH*(f>|M~w|x=}gLm8JU^ejW@dCl@ ztbg~%4u#(KKQIUTU%H1tIR9!3fwEqG*ZX6IfJ_Lo??KU4L1bDUk{Lz*Z!V11M z4iFH^3B6?_*uwNT9~+R3^OjyfY(VJkIRmp0$JMrWQ!b1Kz3nd`4hZLMTY@;Cu$z^) z+Jd1RR|mU4`h%^pSErR*G|<)Y{uYhxFTaNX+5f|u4Zb~RVCy*K>O1!#(Z;f&^Na-c0lFf0k9~UyBlBaGc1a>wy-lZ4Dr?XO9>kjTfp_Ud{q$!X!3x; zP*GtKkta_?pie|$8zrj ... ]__ClassDeclarationNode: class Cons { ... }__AttrDeclarationNode: xcar : Int <- __NONE__AttrDeclarationNode: xcdr : String <- __NONE__FuncDeclarationNode: isNill() : Bool { }__ BooleanNode: false__FuncDeclarationNode: init(hd:Int, tl:String) : Cons { }__BlockNode: {; ... ;}__AssignNode: xcar <- __ VariableNode: hd__AssignNode: xcdr <- __ VariableNode: tl__ VariableNode: self""" - tree = tree.replace("\t", "") - tree = tree.replace("\n", "") - tree = tree.replace("\\", "") - - print(tree) - assert tree == final_tree - diff --git a/customized_tests/test_1.py b/customized_tests/test_1.py deleted file mode 100644 index 4efd04d6b..000000000 --- a/customized_tests/test_1.py +++ /dev/null @@ -1,74 +0,0 @@ -from run_pipeline import run_pipeline -from src.type_collector import TypeCollector -from src.type_builder import TypeBuilder -from src.type_checker import TypeChecker -from src.tset_builder import TSetBuilder -from src.tsets_reducer import TSetReducer -from src.tset_merger import TSetMerger -from src.cool_visitor import FormatVisitor - -# Trabajando con self. Arreglado el error de la primera entrega -# Se infiere: -# main() : Main -# pp : Main -def test(): - text = """ - - class Main { - pp : AUTO_TYPE; - main() : AUTO_TYPE { - pp <- self - }; -}; - - """ - - ast = run_pipeline(text) - errors = [] - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - print(errors) - if errors != []: - print(errors) - assert False - - tset_builder = TSetBuilder(context, errors) - tset = tset_builder.visit(ast, None) - - tset_reducer = TSetReducer(context, errors) - reduced_set = tset_reducer.visit(ast, tset) - - tset_merger = TSetMerger(context, errors) - tset_merger.visit(ast, reduced_set) - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - formatter = FormatVisitor() - tree = formatter.visit(ast) - - print("Errors:", errors) - print("Context:") - print(context) - print(reduced_set) - print(tree) - - assert errors == [] diff --git a/customized_tests/test_10.py b/customized_tests/test_10.py deleted file mode 100644 index 1ce7ad84a..000000000 --- a/customized_tests/test_10.py +++ /dev/null @@ -1,107 +0,0 @@ -from run_pipeline import run_pipeline -from src.type_collector import TypeCollector -from src.type_builder import TypeBuilder -from src.type_checker import TypeChecker -from src.tset_builder import TSetBuilder -from src.tsets_reducer import TSetReducer -from src.tset_merger import TSetMerger -from src.cool_visitor import FormatVisitor - - -def test(): - text = """ -class Main inherits IO { - main(): IO { - let vector: AUTO_TYPE <- (new Vector2).init(0, 0) in - vector.print_vector() - }; -}; - -class Vector2 { - x: AUTO_TYPE; - y: AUTO_TYPE; - - init(x_: AUTO_TYPE, y_: AUTO_TYPE): AUTO_TYPE { { - x <- x_; - y <- y_; - self; - } }; - - - get_x(): AUTO_TYPE { - x - }; - - get_y(): AUTO_TYPE { - y - }; - - add(v: Vector2): AUTO_TYPE { - (new Vector2).init(x + v.get_x(), y + v.get_y()) - }; - - print_vector(): AUTO_TYPE { - let io: IO <- new IO in { - io.out_string(" ( "); - io.out_int(get_x()); - io.out_string("; "); - io.out_int(get_y()); - io.out_string(" ) "); - } - }; - - clone_vector(): AUTO_TYPE { - (new Vector2).init(x, y) - }; -}; - """ - - ast = run_pipeline(text) - errors = [] - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - print(errors) - if errors != []: - print(errors) - assert False - - tset_builder = TSetBuilder(context, errors) - tset = tset_builder.visit(ast, None) - - tset_reducer = TSetReducer(context, errors) - reduced_set = tset_reducer.visit(ast, tset) - - tset_merger = TSetMerger(context, errors) - tset_merger.visit(ast, reduced_set) - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - formatter = FormatVisitor() - tree = formatter.visit(ast) - - print("Errors:", errors) - print("Context:") - print(context) - print(reduced_set) - print(tree) - - assert errors == [] diff --git a/customized_tests/test_11.py b/customized_tests/test_11.py deleted file mode 100644 index b3f747da5..000000000 --- a/customized_tests/test_11.py +++ /dev/null @@ -1,81 +0,0 @@ -from run_pipeline import run_pipeline -from src.type_collector import TypeCollector -from src.type_builder import TypeBuilder -from src.type_checker import TypeChecker -from src.tset_builder import TSetBuilder -from src.tsets_reducer import TSetReducer -from src.tset_merger import TSetMerger -from src.cool_visitor import FormatVisitor - - -def test(): - text = """ -(* This program prints the first 10 numbers of fibonacci *) -class Main { - - main(): Object { - let total: AUTO_TYPE <- 10, - i: AUTO_TYPE <- 1 , - io: AUTO_TYPE <- new IO in - while i <= total loop { - io.out_int(fibonacci(i)); - io.out_string("n"); - i <- i + 1; - } - pool - }; - - fibonacci (n: AUTO_TYPE): AUTO_TYPE { - if n <= 2 then 1 else fibonacci(n - 1) + fibonacci(n - 2) fi - }; -}; """ - - ast = run_pipeline(text) - errors = [] - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - print(errors) - if errors != []: - print(errors) - assert False - - tset_builder = TSetBuilder(context, errors) - tset = tset_builder.visit(ast, None) - - tset_reducer = TSetReducer(context, errors) - reduced_set = tset_reducer.visit(ast, tset) - - tset_merger = TSetMerger(context, errors) - tset_merger.visit(ast, reduced_set) - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - formatter = FormatVisitor() - tree = formatter.visit(ast) - - print("Errors:", errors) - print("Context:") - print(context) - print(reduced_set) - print(tree) - - assert errors == [] diff --git a/customized_tests/test_12.py b/customized_tests/test_12.py deleted file mode 100644 index bc2192eae..000000000 --- a/customized_tests/test_12.py +++ /dev/null @@ -1,106 +0,0 @@ -from run_pipeline import run_pipeline -from src.type_collector import TypeCollector -from src.type_builder import TypeBuilder -from src.type_checker import TypeChecker -from src.tset_builder import TSetBuilder -from src.tsets_reducer import TSetReducer -from src.tset_merger import TSetMerger -from src.cool_visitor import FormatVisitor - -# Probando inferir los tipos de los parametros de un metodo a partir de los argumentos con los que se llama -# Se infiere: -# ---En el let de la clase Main ---- -# id : Int por la asignacion id <- self.in_int(); -# name : String por la asignacion name <- self.in_string(); -# email : String por la asignacion email <- self.in_string(); -# --- En el metodo init() de la clase User--- -# id_ : Int porque en el llamado (new User).init(id, name, email) id es de tipo Int -# name_ : String porque en el llamado (new User).init(id, name, email) name es de tipo String -# email_ : String porque en el llamado (new User).init(id, name, email) email_ es de tipo String -# -def test(): - text = """ -(* Testing IO *) -class Main inherits IO { - - main(): Object { - let id: AUTO_TYPE, name: AUTO_TYPE, email: AUTO_TYPE in { - out_string("Introduzca su id: "); - id <- self.in_int(); - out_string("Introduzca su nombre: "); - name <- self.in_string(); - out_string("Introduzca su email: "); - email <- self.in_string(); - let user: AUTO_TYPE <- (new User).init(id, name, email) in - out_string("Created user: "); - } - }; -}; - -class User { - id: AUTO_TYPE; - name: AUTO_TYPE; - email: AUTO_TYPE; - - init(id_: AUTO_TYPE, name_: AUTO_TYPE, email_: AUTO_TYPE): AUTO_TYPE { { - id <- id_; - name <- name_; - email <- email_; - self; - } }; - - get_name(): AUTO_TYPE { - name - }; -}; - """ - - ast = run_pipeline(text) - errors = [] - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - print(errors) - if errors != []: - print(errors) - assert False - - tset_builder = TSetBuilder(context, errors) - tset = tset_builder.visit(ast, None) - - tset_reducer = TSetReducer(context, errors) - reduced_set = tset_reducer.visit(ast, tset) - - tset_merger = TSetMerger(context, errors) - tset_merger.visit(ast, reduced_set) - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - formatter = FormatVisitor() - tree = formatter.visit(ast) - - print("Errors:", errors) - print("Context:") - print(context) - print(reduced_set) - print(tree) - - assert errors == [] diff --git a/customized_tests/test_2.py b/customized_tests/test_2.py deleted file mode 100644 index 0a2a282fc..000000000 --- a/customized_tests/test_2.py +++ /dev/null @@ -1,79 +0,0 @@ -from run_pipeline import run_pipeline -from src.type_collector import TypeCollector -from src.type_builder import TypeBuilder -from src.type_checker import TypeChecker -from src.tset_builder import TSetBuilder -from src.tsets_reducer import TSetReducer -from src.tset_merger import TSetMerger -from src.cool_visitor import FormatVisitor - -# Infiriendo el tipo de retorno del metodo a partir del body. Probando inicializar variables en el let. Arreglado el error del case. -# Se inferiere: -# main() : String. -# x : Int -# y : Int - - -def test(): - text = """ - - class Main{ - main() : AUTO_TYPE { - let x : AUTO_TYPE <- 3 in - case x of - y : Int => "Ok"; - esac - }; -}; - - """ - - ast = run_pipeline(text) - errors = [] - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - print(errors) - if errors != []: - print(errors) - assert False - - tset_builder = TSetBuilder(context, errors) - tset = tset_builder.visit(ast, None) - - tset_reducer = TSetReducer(context, errors) - reduced_set = tset_reducer.visit(ast, tset) - - tset_merger = TSetMerger(context, errors) - tset_merger.visit(ast, reduced_set) - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - formatter = FormatVisitor() - tree = formatter.visit(ast) - - print("Errors:", errors) - print("Context:") - print(context) - print(reduced_set) - print(tree) - - assert errors == [] diff --git a/customized_tests/test_3.py b/customized_tests/test_3.py deleted file mode 100644 index 4adf7bd7e..000000000 --- a/customized_tests/test_3.py +++ /dev/null @@ -1,69 +0,0 @@ -from run_pipeline import run_pipeline -from src.type_collector import TypeCollector -from src.type_builder import TypeBuilder -from src.type_checker import TypeChecker -from src.tset_builder import TSetBuilder -from src.tsets_reducer import TSetReducer -from src.tset_merger import TSetMerger -from src.cool_visitor import FormatVisitor - - -def test(): - text = """ -class Main { - main() : AUTO_TYPE { - let x : AUTO_TYPE <- 3 in "Ok" - }; -}; - - """ - - ast = run_pipeline(text) - errors = [] - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - print(errors) - if errors != []: - print(errors) - assert False - - tset_builder = TSetBuilder(context, errors) - tset = tset_builder.visit(ast, None) - - tset_reducer = TSetReducer(context, errors) - reduced_set = tset_reducer.visit(ast, tset) - - tset_merger = TSetMerger(context, errors) - tset_merger.visit(ast, reduced_set) - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - formatter = FormatVisitor() - tree = formatter.visit(ast) - - print("Errors:", errors) - print("Context:") - print(context) - print(reduced_set) - print(tree) - - assert errors == [] diff --git a/customized_tests/test_4.py b/customized_tests/test_4.py deleted file mode 100644 index 832fd7b4a..000000000 --- a/customized_tests/test_4.py +++ /dev/null @@ -1,82 +0,0 @@ -from run_pipeline import run_pipeline -from src.type_collector import TypeCollector -from src.type_builder import TypeBuilder -from src.type_checker import TypeChecker -from src.tset_builder import TSetBuilder -from src.tsets_reducer import TSetReducer -from src.tset_merger import TSetMerger -from src.cool_visitor import FormatVisitor - -# Trabajando con IO. Probando inferir el tipo de 'a' a partir del tipo que recibe el metodo out_string() -# Se infiere: -# main(): IO -# a : String -# x : Int -# y : IO - - -def test(): - text = """ -class Main { - main(a : AUTO_TYPE) : AUTO_TYPE { - let x : AUTO_TYPE <- 3 in - case x of - y : IO => y.out_string(a); - esac - }; -}; - """ - - ast = run_pipeline(text) - errors = [] - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - if errors != [ - '"main" method in class Main does not receive any parameters', - ]: - print(errors) - assert False - - tset_builder = TSetBuilder(context, errors) - tset = tset_builder.visit(ast, None) - - tset_reducer = TSetReducer(context, errors) - reduced_set = tset_reducer.visit(ast, tset) - - tset_merger = TSetMerger(context, errors) - tset_merger.visit(ast, reduced_set) - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - formatter = FormatVisitor() - tree = formatter.visit(ast) - - print("Errors:", errors) - print("Context:") - print(context) - print(reduced_set) - print(tree) - - assert errors == [ - '"main" method in class Main does not receive any parameters', - '"main" method in class Main does not receive any parameters', - ] diff --git a/customized_tests/test_5.py b/customized_tests/test_5.py deleted file mode 100644 index 3e4e21342..000000000 --- a/customized_tests/test_5.py +++ /dev/null @@ -1,81 +0,0 @@ -from run_pipeline import run_pipeline -from src.type_collector import TypeCollector -from src.type_builder import TypeBuilder -from src.type_checker import TypeChecker -from src.tset_builder import TSetBuilder -from src.tsets_reducer import TSetReducer -from src.tset_merger import TSetMerger -from src.cool_visitor import FormatVisitor - - -def test(): - text = """ - - class Main { - main (): Object { - 0 - }; -}; - -class Point { - x: AUTO_TYPE; - y: AUTO_TYPE; - - init(x0: Int, y0: Int): AUTO_TYPE {{ - x <- x0; - y <- y0; - self; - }}; -}; - - """ - - ast = run_pipeline(text) - errors = [] - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - print(errors) - if errors != []: - print(errors) - assert False - - tset_builder = TSetBuilder(context, errors) - tset = tset_builder.visit(ast, None) - - tset_reducer = TSetReducer(context, errors) - reduced_set = tset_reducer.visit(ast, tset) - - tset_merger = TSetMerger(context, errors) - tset_merger.visit(ast, reduced_set) - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - formatter = FormatVisitor() - tree = formatter.visit(ast) - - print("Errors:", errors) - print("Context:") - print(context) - print(reduced_set) - print(tree) - - assert errors == [] diff --git a/customized_tests/test_6.py b/customized_tests/test_6.py deleted file mode 100644 index c99a49acb..000000000 --- a/customized_tests/test_6.py +++ /dev/null @@ -1,86 +0,0 @@ -from run_pipeline import run_pipeline -from src.type_collector import TypeCollector -from src.type_builder import TypeBuilder -from src.type_checker import TypeChecker -from src.tset_builder import TSetBuilder -from src.tsets_reducer import TSetReducer -from src.tset_merger import TSetMerger -from src.cool_visitor import FormatVisitor - -# Probando inferencia en funciones recursivas -# Se infiere: -# m : Int porque se usa en operacion aritmetica -# n : Int porque se usa en operacion aritmetica -# ackerman() : Int porque es la interseccion entre los tipos que devuelve el then (Int) y los que devuelve el else(todos pues es AUTO_TYPE) - - -def test(): - text = """ - - class Main { - main (): Object { - 0 - }; -}; - -class Ackermann { - ackermann(m: AUTO_TYPE, n: AUTO_TYPE): AUTO_TYPE { - if m = 0 then n + 1 else - if n = 0 then ackermann(m - 1, 1) else - ackermann(m - 1, ackermann(m, n - 1)) - fi - fi - }; -}; - - """ - - ast = run_pipeline(text) - errors = [] - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - print(errors) - if errors != []: - print(errors) - assert False - - tset_builder = TSetBuilder(context, errors) - tset = tset_builder.visit(ast, None) - - tset_reducer = TSetReducer(context, errors) - reduced_set = tset_reducer.visit(ast, tset) - - tset_merger = TSetMerger(context, errors) - tset_merger.visit(ast, reduced_set) - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - formatter = FormatVisitor() - tree = formatter.visit(ast) - - print("Errors:", errors) - print("Context:") - print(context) - print(reduced_set) - print(tree) - - assert errors == [] diff --git a/customized_tests/test_7.py b/customized_tests/test_7.py deleted file mode 100644 index 9af43578f..000000000 --- a/customized_tests/test_7.py +++ /dev/null @@ -1,89 +0,0 @@ -from run_pipeline import run_pipeline -from src.type_collector import TypeCollector -from src.type_builder import TypeBuilder -from src.type_checker import TypeChecker -from src.tset_builder import TSetBuilder -from src.tsets_reducer import TSetReducer -from src.tset_merger import TSetMerger -from src.cool_visitor import FormatVisitor - -# Probando inferencia en funciones recursivas -# Se infiere: -# a : Int porque se usa en una operacion aritmetica -# b : Int porque se usa en una operacion aritmetica -# f() : Int -# g() : Int -# Una vez inferido el tipo de a y b, en las proximas pasadas se infiere que el if devuelve Int en ambos metodos - - -def test(): - text = """ - - class Main { - main (): Object { - 0 - }; - - f(a: AUTO_TYPE, b: AUTO_TYPE): AUTO_TYPE { - if a = 1 then b else - g(a + 1, b / 1) - fi - }; - - g(a: AUTO_TYPE, b: AUTO_TYPE): AUTO_TYPE { - if b = 1 then a else - f(a / 2, b + 1) - fi - }; -}; - """ - - ast = run_pipeline(text) - errors = [] - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - print(errors) - if errors != []: - print(errors) - assert False - - tset_builder = TSetBuilder(context, errors) - tset = tset_builder.visit(ast, None) - - tset_reducer = TSetReducer(context, errors) - reduced_set = tset_reducer.visit(ast, tset) - - tset_merger = TSetMerger(context, errors) - tset_merger.visit(ast, reduced_set) - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - formatter = FormatVisitor() - tree = formatter.visit(ast) - - print("Errors:", errors) - print("Context:") - print(context) - print(reduced_set) - print(tree) - - assert errors == [] diff --git a/customized_tests/test_8.py b/customized_tests/test_8.py deleted file mode 100644 index f7731ae37..000000000 --- a/customized_tests/test_8.py +++ /dev/null @@ -1,86 +0,0 @@ -from run_pipeline import run_pipeline -from src.type_collector import TypeCollector -from src.type_builder import TypeBuilder -from src.type_checker import TypeChecker -from src.tset_builder import TSetBuilder -from src.tsets_reducer import TSetReducer -from src.tset_merger import TSetMerger -from src.cool_visitor import FormatVisitor - -# Aqui no inferimos el tipo de x0 y y0 a partir de x e y. -# En la asignacion solo se reduce la variable al tipo de la expresion que se le esta asinando, no viceversa. - - -def test(): - text = """ - - class Main { - main (): Object { - 0 - }; -}; - -class Point { - x: Int; - y: Int; - - init(x0: AUTO_TYPE, y0: AUTO_TYPE): AUTO_TYPE { { - x <- x0; - y <- y0; - self; - } }; -}; - """ - - ast = run_pipeline(text) - errors = [] - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - print(errors) - if errors != []: - print(errors) - assert False - - tset_builder = TSetBuilder(context, errors) - tset = tset_builder.visit(ast, None) - - tset_reducer = TSetReducer(context, errors) - reduced_set = tset_reducer.visit(ast, tset) - - tset_merger = TSetMerger(context, errors) - tset_merger.visit(ast, reduced_set) - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - formatter = FormatVisitor() - tree = formatter.visit(ast) - - print("Errors:", errors) - print("Context:") - print(context) - print(reduced_set) - print(tree) - - assert errors == [ - 'Cannot convert "Object" into "Int".', - 'Cannot convert "Object" into "Int".', - ] diff --git a/customized_tests/test_9.py b/customized_tests/test_9.py deleted file mode 100644 index 9e7f8e5c1..000000000 --- a/customized_tests/test_9.py +++ /dev/null @@ -1,80 +0,0 @@ -from run_pipeline import run_pipeline -from src.type_collector import TypeCollector -from src.type_builder import TypeBuilder -from src.type_checker import TypeChecker -from src.tset_builder import TSetBuilder -from src.tsets_reducer import TSetReducer -from src.tset_merger import TSetMerger -from src.cool_visitor import FormatVisitor - -# En este caso todas las variables son Int porque d participa en una operacion aritmetica. f tambien se infiere que devuelve Int. -def test(): - text = """ - - class Main { - main (): Object { - 0 - }; - - f (a: AUTO_TYPE, b: AUTO_TYPE, c: AUTO_TYPE, d: AUTO_TYPE): AUTO_TYPE { - { - a <- b; - b <- c; - c <- d; - d <- a; - d + 1; - a; - } - }; -}; - """ - - ast = run_pipeline(text) - errors = [] - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - print(errors) - if errors != []: - print(errors) - assert False - - tset_builder = TSetBuilder(context, errors) - tset = tset_builder.visit(ast, None) - - tset_reducer = TSetReducer(context, errors) - reduced_set = tset_reducer.visit(ast, tset) - - tset_merger = TSetMerger(context, errors) - tset_merger.visit(ast, reduced_set) - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - formatter = FormatVisitor() - tree = formatter.visit(ast) - - print("Errors:", errors) - print("Context:") - print(context) - print(reduced_set) - print(tree) - - assert errors == [] diff --git a/customized_tests/test_IO.py b/customized_tests/test_IO.py deleted file mode 100644 index a51ff44b1..000000000 --- a/customized_tests/test_IO.py +++ /dev/null @@ -1,74 +0,0 @@ -from run_pipeline import run_pipeline -from src.type_collector import TypeCollector -from src.type_builder import TypeBuilder -from src.type_checker import TypeChecker -from src.tset_builder import TSetBuilder -from src.tsets_reducer import TSetReducer -from src.tset_merger import TSetMerger -from src.cool_visitor import FormatVisitor - - -def test(): - text = """ - - class Main inherits IO { - main() : AUTO_TYPE { - let x : AUTO_TYPE <- 3 + (let y: AUTO_TYPE <- 8 in y ) in - case x of - y: Int => out_string("ok"); - esac - }; - }; - - - """ - - ast = run_pipeline(text) - errors = [] - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - print(errors) - if errors != []: - print(errors) - assert False - - tset_builder = TSetBuilder(context, errors) - tset = tset_builder.visit(ast, None) - - tset_reducer = TSetReducer(context, errors) - reduced_set = tset_reducer.visit(ast, tset) - - tset_merger = TSetMerger(context, errors) - tset_merger.visit(ast, reduced_set) - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - formatter = FormatVisitor() - tree = formatter.visit(ast) - - print("Errors:", errors) - print("Context:") - print(context) - print(reduced_set) - print(tree) - - assert errors == [] diff --git a/customized_tests/test_adr.py b/customized_tests/test_adr.py deleted file mode 100644 index dea30bbcc..000000000 --- a/customized_tests/test_adr.py +++ /dev/null @@ -1,92 +0,0 @@ -from run_pipeline import run_pipeline -from src.type_collector import TypeCollector -from src.type_builder import TypeBuilder -from src.type_checker import TypeChecker -from src.tset_builder import TSetBuilder -from src.tsets_reducer import TSetReducer -from src.tset_merger import TSetMerger -from src.cool_visitor import FormatVisitor - -# Probando case y let anidados -def test(): - text = """ - - class Main { - a : AUTO_TYPE<- "Hola"; - main ( ) : Int { { - case {let i: AUTO_TYPE <- 12 in {let i: AUTO_TYPE <- "Hola" in {"Hi"; - case 12 of - x : Int => x; - y : AUTO_TYPE => y; - z: String => let i : AUTO_TYPE in { - i<- case self of - x: Int => 12; - x: AUTO_TYPE => if 12<12 then x else "Hola" fi ; - esac - ;}; - esac - ;};};} of - x : Int => 12; - y : AUTO_TYPE => let i: AUTO_TYPE <- y in y ; - esac ; - a.length();} } ; - } ; - - """ - - ast = run_pipeline(text) - errors = [] - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - # print(errors) - # if errors != []: - # print(errors) - # assert False - - tset_builder = TSetBuilder(context, errors) - tset = tset_builder.visit(ast, None) - - tset_reducer = TSetReducer(context, errors) - reduced_set = tset_reducer.visit(ast, tset) - - tset_merger = TSetMerger(context, errors) - tset_merger.visit(ast, reduced_set) - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - formatter = FormatVisitor() - tree = formatter.visit(ast) - - # print("Errors:", errors) - # print("Context:") - # print(context) - # print(reduced_set) - # print(tree) - - final_tree = """__ProgramNode [ ... ]__ClassDeclarationNode: class Main { ... }__AttrDeclarationNode: a : String <- __ StringNode: Hola__FuncDeclarationNode: main() : Int { }__BlockNode: {; ... ;}__CaseNode: case of esac__BlockNode: {; ... ;}__LetNode: let in __VarDeclarationNode: i : Int <- __ ConstantNumNode: 12__BlockNode: {; ... ;}__LetNode: let in __VarDeclarationNode: i : String <- __ StringNode: Hola__BlockNode: {; ... ;}__ StringNode: Hi__CaseNode: case of esac__ ConstantNumNode: 12__CaseItemNode: x : Int => ;__ VariableNode: x__CaseItemNode: y : Object => ;__ VariableNode: y__CaseItemNode: z : String => ;__LetNode: let in __VarDeclarationNode: i : Object <- __NONE__BlockNode: {; ... ;}__AssignNode: i <- __CaseNode: case of esac__ VariableNode: self__CaseItemNode: x : Int => ;__ ConstantNumNode: 12__CaseItemNode: x : Object => ;__IfNode: if then else fi__ LessNode __ ConstantNumNode: 12__ ConstantNumNode: 12__ VariableNode: x__ StringNode: Hola__CaseItemNode: x : Int => ;__ ConstantNumNode: 12__CaseItemNode: y : Object => ;__LetNode: let in __VarDeclarationNode: i : Object <- __ VariableNode: y__ VariableNode: y__CallNode: .length(, ..., )__ VariableNode: a""" - - tree = tree.replace("\t", "") - tree = tree.replace("\n", "") - tree = tree.replace("\\", "") - - assert tree == final_tree - assert errors == [] diff --git a/customized_tests/test_cycher.py b/customized_tests/test_cycher.py deleted file mode 100644 index 4eec7ecf0..000000000 --- a/customized_tests/test_cycher.py +++ /dev/null @@ -1,38 +0,0 @@ -from run_pipeline import run_pipeline -from src.type_collector import TypeCollector -from src.type_builder import TypeBuilder -from src.type_checker import TypeChecker -from src.tset_builder import TSetBuilder -from src.tsets_reducer import TSetReducer -from src.tset_merger import TSetMerger -from src.cool_visitor import FormatVisitor - -# Probando detectar herencia ciclica -def test(): - text = """ - class B inherits A { - a : String ; - b : AUTO_TYPE ; - }; - class A inherits B { } ; - """ - - print("corriendo") - ast = run_pipeline(text) - errors = [] - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - print(errors) - assert errors == [ - "B is involved in a cyclic heritage", - "A class Main with a method main most be provided", - ] diff --git a/customized_tests/test_cycher2.py b/customized_tests/test_cycher2.py deleted file mode 100644 index fc7dcf4ab..000000000 --- a/customized_tests/test_cycher2.py +++ /dev/null @@ -1,48 +0,0 @@ -from run_pipeline import run_pipeline -from src.type_collector import TypeCollector -from src.type_builder import TypeBuilder -from src.type_checker import TypeChecker -from src.tset_builder import TSetBuilder -from src.tsets_reducer import TSetReducer -from src.tset_merger import TSetMerger -from src.cool_visitor import FormatVisitor - - -# Probando detectar herencia ciclica - - -def test(): - text = """ - class B inherits A { - a : String ; - b : AUTO_TYPE ; - }; - class A inherits A { } ; - """ - - print("corriendo") - ast = run_pipeline(text) - errors = [] - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - err = [ - "A is involved in a cyclic heritage", - "A class Main with a method main most be provided", - ] - - if errors != err: - print(errors) - assert False - - assert True - diff --git a/customized_tests/test_cycher3.py b/customized_tests/test_cycher3.py deleted file mode 100644 index 766a63170..000000000 --- a/customized_tests/test_cycher3.py +++ /dev/null @@ -1,55 +0,0 @@ -from run_pipeline import run_pipeline -from src.type_collector import TypeCollector -from src.type_builder import TypeBuilder -from src.type_checker import TypeChecker -from src.tset_builder import TSetBuilder -from src.tsets_reducer import TSetReducer -from src.tset_merger import TSetMerger -from src.cool_visitor import FormatVisitor - -# Probando detectar herencia ciclica - - -def test(): - text = """ - class C inherits J { } ; - class A inherits B { } ; - class B inherits A { } ; - class C { } ; - class D inherits E { } ; - class E inherits F { } ; - class F inherits D { } ; - class G inherits F { } ; - """ - - ast = run_pipeline(text) - errors = [] - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - err = [ - "Type with the same name (C) already in context.", - 'Type "J" is not defined.', - "Parent type is already set for C.", - "A is involved in a cyclic heritage", - "D is involved in a cyclic heritage", - "A class Main with a method main most be provided", - ] - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - if errors != err: - print(errors) - assert False - - assert True - - -test() diff --git a/customized_tests/test_hello_world.cl b/customized_tests/test_hello_world.cl deleted file mode 100644 index 04c789999..000000000 --- a/customized_tests/test_hello_world.cl +++ /dev/null @@ -1,192 +0,0 @@ - Class List inherits IO { - (* Since abort() returns Object, we need something of - type Bool at the end of the block to satisfy the typechecker. - This code is unreachable, since abort() halts the program. *) - isNil() : Bool { { abort(); true; } }; - - cons(hd : Int) : Cons { - (let new_cell : Cons <- new Cons in - new_cell.init(hd,self) - ) - }; - - (* - Since abort "returns" type Object, we have to add - an expression of type Int here to satisfy the typechecker. - This code is, of course, unreachable. - *) - car() : Int { { abort(); new Int; } }; - - cdr() : List { { abort(); new List; } }; - - rev() : List { cdr() }; - - sort() : List { cdr() }; - - insert(i : Int) : List { cdr() }; - - rcons(i : Int) : List { cdr() }; - - print_list() : Object { abort() }; -}; - -Class Cons inherits List { - xcar : Int; -- We keep the car in cdr in attributes. - xcdr : List; - - isNil() : Bool { false }; - - init(hd : Int, tl : List) : Cons { - { - xcar <- hd; - xcdr <- tl; - self; - } - }; - - car() : Int { xcar }; - - cdr() : List { xcdr }; - - rev() : List { (xcdr.rev()).rcons(xcar) }; - - sort() : List { (xcdr.sort()).insert(xcar) }; - - insert(i : Int) : List { - if i < xcar then - (new Cons).init(i,self) - else - (new Cons).init(xcar,xcdr.insert(i)) - fi - }; - - - rcons(i : Int) : List { (new Cons).init(xcar, xcdr.rcons(i)) }; - - print_list() : Object { - { - out_int(xcar); - out_string("\n"); - xcdr.print_list(); - } - }; -}; - -Class Nil inherits List { - isNil() : Bool { true }; - - rev() : List { self }; - - sort() : List { self }; - - insert(i : Int) : List { rcons(i) }; - - rcons(i : Int) : List { (new Cons).init(i,self) }; - - print_list() : Object { true }; - -}; - - -Class Main inherits IO { - - l : List; - - (* iota maps its integer argument n into the list 0..n-1 *) - iota(i : Int) : List { - { - l <- new Nil; - (let j : Int <- 0 in - while j < i - loop - { - l <- (new Cons).init(j,l); - j <- j + 1; - } - pool - ); - l; - } - }; - - main() : Object { - { - out_string("How many numbers to sort? "); - iota(in_int()).rev().sort().print_list(); - } - }; -}; - - - - -(* class Main inherits IO { - main(): IO { - out_string("Hello, World.\n") - }; -}; -*) - - -(* class Main inherits IO { - msg : String <- "Hello World"; - - main() : IO{ - self@IO.out_string(msg) - }; -}; - -*) - - - - - (* class Main inherits IO{ - main (): Object { - out_int((new Point).init(5, 6)) - - }; -}; - -class Point{ - x: Int; - y: Int; - - init(x0: AUTO_TYPE, y0: AUTO_TYPE): AUTO_TYPE { - x0 + y0 - }; -}; -*) - - - - (* class Main inherits IO{ - main (): Object { - self.out_int((new Point).init(5, 6)) - }; -}; - -class Point inherits Main{ - x: Int; - y: Int; - a: Point; - s: String; - - init(x0: AUTO_TYPE, y0: AUTO_TYPE): AUTO_TYPE {{ - a <- new Point; - s <- "Hello World"; - case a of - b: Int => x0 + y0; - d: String => s; - c: Main => new Main; - esac; - } - }; -}; -*) - - - - - - diff --git a/customized_tests/test_let.py b/customized_tests/test_let.py deleted file mode 100644 index 777a8017b..000000000 --- a/customized_tests/test_let.py +++ /dev/null @@ -1,73 +0,0 @@ -from run_pipeline import run_pipeline -from src.type_collector import TypeCollector -from src.type_builder import TypeBuilder -from src.type_checker import TypeChecker -from src.tset_builder import TSetBuilder -from src.tsets_reducer import TSetReducer -from src.tset_merger import TSetMerger -from src.cool_visitor import FormatVisitor - - -def test(): - text = """ - class A { - b : AUTO_TYPE ; - a : AUTO_TYPE ; - - f ( ) : Int { { - let x : AUTO_TYPE <- a + b in x ; - } }; - }; - """ - - ast = run_pipeline(text) - errors = [] - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - if errors != ["A class Main with a method main most be provided"]: - print(errors) - assert False - - tset_builder = TSetBuilder(context, errors) - tset = tset_builder.visit(ast, None) - - tset_reducer = TSetReducer(context, errors) - reduced_set = tset_reducer.visit(ast, tset) - - tset_merger = TSetMerger(context, errors) - tset_merger.visit(ast, reduced_set) - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - formatter = FormatVisitor() - tree = formatter.visit(ast) - - print("Errors:", errors) - print("Context:") - print(context) - print(reduced_set) - print(tree) - - assert errors == [ - "A class Main with a method main most be provided", - "A class Main with a method main most be provided", - ] diff --git a/customized_tests/test_main.py b/customized_tests/test_main.py deleted file mode 100644 index d423a8164..000000000 --- a/customized_tests/test_main.py +++ /dev/null @@ -1,55 +0,0 @@ -from run_pipeline import run_pipeline -from src.type_collector import TypeCollector -from src.type_builder import TypeBuilder -from src.type_checker import TypeChecker -from src.tset_builder import TSetBuilder -from src.tsets_reducer import TSetReducer -from src.tset_merger import TSetMerger -from src.cool_visitor import FormatVisitor - - -def test(): - text = """ - class Main inherits Point { - x : String ; - init ( n : String , m : Int) : Int { - { - n <- "Testing main" ; - m <- 1 + 2 ; - } } ; - } ; - class Point { - x : AUTO_TYPE ; - y : AUTO_TYPE ; - init ( n : String , m : Int ) : Int { - { - x <- n ; - y <- m ; - } } ; - main ( n : String , m : Int ) : Int { - { - x <- n ; - y <- m ; - } } ; - } ; - """ - - ast = run_pipeline(text) - errors = [] - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - assert errors == [ - 'Attribute "x" is already defined in Main.', - "A class Main with a method main most be provided", - ] - diff --git a/customized_tests/test_main1.py b/customized_tests/test_main1.py deleted file mode 100644 index e70bc933a..000000000 --- a/customized_tests/test_main1.py +++ /dev/null @@ -1,55 +0,0 @@ -from run_pipeline import run_pipeline -from src.type_collector import TypeCollector -from src.type_builder import TypeBuilder -from src.type_checker import TypeChecker -from src.tset_builder import TSetBuilder -from src.tsets_reducer import TSetReducer -from src.tset_merger import TSetMerger -from src.cool_visitor import FormatVisitor - - -def test(): - text = """ - class Main inherits Point { - x : String ; - init ( n : String , m : Int) : Int { - { - n <- "Testing main" ; - m <- 1 + 2 ; - } } ; - - main ( n : String , m : Int ) : Int { - { - n <- "Buen dia" ; - m <- 3 ; - } } ; - } ; - class Point { - x : AUTO_TYPE ; - y : AUTO_TYPE ; - init ( n : String , m : Int ) : Int { - { - x <- n ; - y <- m ; - } } ; - } ; - """ - - ast = run_pipeline(text) - errors = [] - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - assert errors == [ - 'Attribute "x" is already defined in Main.', - '"main" method in class Main does not receive any parameters', - ] diff --git a/customized_tests/test_main2.py b/customized_tests/test_main2.py deleted file mode 100644 index 74ef06757..000000000 --- a/customized_tests/test_main2.py +++ /dev/null @@ -1,53 +0,0 @@ -from run_pipeline import run_pipeline -from src.type_collector import TypeCollector -from src.type_builder import TypeBuilder -from src.type_checker import TypeChecker -from src.tset_builder import TSetBuilder -from src.tsets_reducer import TSetReducer -from src.tset_merger import TSetMerger -from src.cool_visitor import FormatVisitor - - -def test(): - text = """ - class Main inherits Point { - x : String ; - init ( n : String , m : Int) : Int { - { - n <- "Testing main" ; - m <- 1 + 2 ; - } } ; - - main ( ) : String - { - "Buen dia" - }; - } ; - class Point { - x : AUTO_TYPE ; - y : AUTO_TYPE ; - init ( n : String , m : Int ) : Int { - { - x <- n ; - y <- m ; - } } ; - } ; - """ - - ast = run_pipeline(text) - errors = [] - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - assert errors == [ - 'Attribute "x" is already defined in Main.', - ] diff --git a/customized_tests/test_merger.py b/customized_tests/test_merger.py deleted file mode 100644 index b613b283b..000000000 --- a/customized_tests/test_merger.py +++ /dev/null @@ -1,107 +0,0 @@ -from run_pipeline import run_pipeline -from src.type_collector import TypeCollector -from src.type_builder import TypeBuilder -from src.type_checker import TypeChecker -from src.tset_builder import TSetBuilder -from src.tsets_reducer import TSetReducer -from src.tset_merger import TSetMerger -from src.cool_visitor import FormatVisitor - - -def test(): - text = """ - - class A { - a : String ; - b : AUTO_TYPE ; - c : AUTO_TYPE <- 0 ; - d : Object <- while c loop c + 1 pool ; (*first and second errors*) - j : AUTO_TYPE ; - l : AUTO_TYPE ; - fact ( n : AUTO_TYPE ) : AUTO_TYPE { if n < 0 then 1 else n + fact ( n - 1 ) fi } ; - step ( p : AUTO_TYPE ) : AUTO_TYPE { - b <- - { - p + 5 ; - j <- p ; (*third error*) - p <- false ; - isvoid d ; - - l @ Point . main ( ) ; - l.main(); - } - } ; - } ; - class Point inherits A { - h : AUTO_TYPE <- "debe ser tipo string" ; - k : AUTO_TYPE ; - main ( ) : AUTO_TYPE { - let i : AUTO_TYPE <- new A in { - isvoid i ; (*Puede lanzar error semantico*) - } - } ; - ackermann ( m : AUTO_TYPE , n : AUTO_TYPE ) : AUTO_TYPE { - if m < 0 then 1 else - if n < 0 then ackermann ( m - 1 , 1 ) else - ackermann ( m - 1 , ackermann ( m , n - 1 ) ) - fi - fi - } ; - } ; - - """ - - ast = run_pipeline(text) - errors = [] - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - if errors != ["A class Main with a method main most be provided"]: - print(errors) - assert False - - tset_builder = TSetBuilder(context, errors) - tset = tset_builder.visit(ast, None) - - tset_reducer = TSetReducer(context, errors) - reduced_set = tset_reducer.visit(ast, tset) - - tset_merger = TSetMerger(context, errors) - tset_merger.visit(ast, reduced_set) - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - formatter = FormatVisitor() - tree = formatter.visit(ast) - - print("Errors:", errors) - print("Context:") - print(context) - print(reduced_set) - print(tree) - - assert errors == [ - "A class Main with a method main most be provided", - "A class Main with a method main most be provided", - "Expression after 'while' must be bool, current is Object", - 'Operation is not defined between "Object" and "Int".', - 'Cannot convert "Object" into "Int".', - ] diff --git a/customized_tests/test_mnotfound.py b/customized_tests/test_mnotfound.py deleted file mode 100644 index 3e93fd2af..000000000 --- a/customized_tests/test_mnotfound.py +++ /dev/null @@ -1,45 +0,0 @@ -from run_pipeline import run_pipeline -from src.type_collector import TypeCollector -from src.type_builder import TypeBuilder -from src.type_checker import TypeChecker -from src.tset_builder import TSetBuilder -from src.tsets_reducer import TSetReducer -from src.tset_merger import TSetMerger -from src.cool_visitor import FormatVisitor - - -def test(): - text = """ - class A inherits B { }; - class B inherits A { - f ( ) : Int { - g() - } ; - } ; - """ - - print("corriendo") - ast = run_pipeline(text) - errors = [] - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - if errors != [ - "A is involved in a cyclic heritage", - "A class Main with a method main most be provided", - 'Method "g" is not defined in B.', - ]: - print(errors) - assert False - - assert True - diff --git a/customized_tests/test_parser1.py b/customized_tests/test_parser1.py deleted file mode 100644 index 5e00d43b9..000000000 --- a/customized_tests/test_parser1.py +++ /dev/null @@ -1,37 +0,0 @@ -from run_pipeline import run_pipeline -from src.cool_visitor import FormatVisitor - - -def test(): - text = """ - class Cons inherits List { - xcar : Int ; - xcdr : List ; - - isNill ( ) : Bool { - false - } ; - - init ( hd : Int , tl : List ) : Cons { - { - xcar <- hd ; - xcdr <- tl ; - self ; - } - } ; - } ; - """ - - ast = run_pipeline(text) - - formatter = FormatVisitor() - tree = formatter.visit(ast) - - tree = tree.replace("\t", "") - tree = tree.replace("\n", "") - tree = tree.replace("\\", "") - - assert ( - tree - == "__ProgramNode [ ... ]__ClassDeclarationNode: class Cons inherits List { ... }__AttrDeclarationNode: xcar : Int <- __NONE__AttrDeclarationNode: xcdr : List <- __NONE__FuncDeclarationNode: isNill() : Bool { }__ BooleanNode: false__FuncDeclarationNode: init(hd:Int, tl:List) : Cons { }__BlockNode: {; ... ;}__AssignNode: xcar <- __ VariableNode: hd__AssignNode: xcdr <- __ VariableNode: tl__ VariableNode: self" - ) diff --git a/customized_tests/test_parser2.py b/customized_tests/test_parser2.py deleted file mode 100644 index 579bcf56b..000000000 --- a/customized_tests/test_parser2.py +++ /dev/null @@ -1,37 +0,0 @@ -from run_pipeline import run_pipeline -from src.cool_visitor import FormatVisitor - - -def test(): - text = """ - class Cons inherits List { - xcar : String ; - xcdr : List ; - - isNill ( ) : Bool { - false - } ; - - init ( hd : Int , tl : List ) : Cons { - { - xcar <- " testing strings " ; - xcdr <- tl ; - self ; - } - } ; - } ; - """ - - ast = run_pipeline(text) - - formatter = FormatVisitor() - tree = formatter.visit(ast) - - tree = tree.replace("\t", "") - tree = tree.replace("\n", "") - tree = tree.replace("\\", "") - - assert ( - tree - == "__ProgramNode [ ... ]__ClassDeclarationNode: class Cons inherits List { ... }__AttrDeclarationNode: xcar : String <- __NONE__AttrDeclarationNode: xcdr : List <- __NONE__FuncDeclarationNode: isNill() : Bool { }__ BooleanNode: false__FuncDeclarationNode: init(hd:Int, tl:List) : Cons { }__BlockNode: {; ... ;}__AssignNode: xcar <- __ StringNode: testing strings __AssignNode: xcdr <- __ VariableNode: tl__ VariableNode: self" - ) diff --git a/customized_tests/test_parser3.py b/customized_tests/test_parser3.py deleted file mode 100644 index ff92d22fb..000000000 --- a/customized_tests/test_parser3.py +++ /dev/null @@ -1,31 +0,0 @@ -from run_pipeline import run_pipeline -from src.cool_visitor import FormatVisitor - - -def test(): - text = """ - class Main inherits IO { - main ( ) : AUTO_TYPE { - let x : AUTO_TYPE <- 3 + 2 in { - case x of - y : Int => out_string ( " Ok " ) ; - esac ; - } - } ; - } ; - """ - - ast = run_pipeline(text) - - formatter = FormatVisitor() - tree = formatter.visit(ast) - - tree = tree.replace("\t", "") - tree = tree.replace("\n", "") - tree = tree.replace("\\", "") - - assert ( - tree - == "__ProgramNode [ ... ]__ClassDeclarationNode: class Main inherits IO { ... }__FuncDeclarationNode: main() : AUTO_TYPE { }__LetNode: let in __VarDeclarationNode: x : AUTO_TYPE <- __ PlusNode __ ConstantNumNode: 3__ ConstantNumNode: 2__BlockNode: {; ... ;}__CaseNode: case of esac__ VariableNode: x__CaseItemNode: y : Int => ;__CallNode: out_string(, ..., )__ StringNode: Ok " - ) - diff --git a/customized_tests/test_parser4.py b/customized_tests/test_parser4.py deleted file mode 100644 index 50975bd99..000000000 --- a/customized_tests/test_parser4.py +++ /dev/null @@ -1,30 +0,0 @@ -from run_pipeline import run_pipeline -from src.cool_visitor import FormatVisitor - - -def test(): - text = """ - class Point { - x : AUTO_TYPE ; - y : AUTO_TYPE ; - init ( n : Int , m : Int ) : SELF_TYPE { - { - x <- n ; - y <- m ; - } } ; - } ; - """ - - ast = run_pipeline(text) - - formatter = FormatVisitor() - tree = formatter.visit(ast) - - tree = tree.replace("\t", "") - tree = tree.replace("\n", "") - tree = tree.replace("\\", "") - - assert ( - tree - == "__ProgramNode [ ... ]__ClassDeclarationNode: class Point { ... }__AttrDeclarationNode: x : AUTO_TYPE <- __NONE__AttrDeclarationNode: y : AUTO_TYPE <- __NONE__FuncDeclarationNode: init(n:Int, m:Int) : SELF_TYPE { }__BlockNode: {; ... ;}__AssignNode: x <- __ VariableNode: n__AssignNode: y <- __ VariableNode: m" - ) diff --git a/customized_tests/test_parser5.py b/customized_tests/test_parser5.py deleted file mode 100644 index 009a531da..000000000 --- a/customized_tests/test_parser5.py +++ /dev/null @@ -1,24 +0,0 @@ -from run_pipeline import run_pipeline -from src.cool_visitor import FormatVisitor - - -def test(): - text = """ - class Point { - succ ( n : Int ) : AUTO_TYPE { n + 1 } ; - } ; - """ - - ast = run_pipeline(text) - - formatter = FormatVisitor() - tree = formatter.visit(ast) - - tree = tree.replace("\t", "") - tree = tree.replace("\n", "") - tree = tree.replace("\\", "") - - assert ( - tree - == "__ProgramNode [ ... ]__ClassDeclarationNode: class Point { ... }__FuncDeclarationNode: succ(n:Int) : AUTO_TYPE { }__ PlusNode __ VariableNode: n__ ConstantNumNode: 1" - ) diff --git a/customized_tests/test_parser6.py b/customized_tests/test_parser6.py deleted file mode 100644 index 5d44a53fb..000000000 --- a/customized_tests/test_parser6.py +++ /dev/null @@ -1,29 +0,0 @@ -from run_pipeline import run_pipeline -from src.cool_visitor import FormatVisitor - - -def test(): - text = """ - class Point { - step ( p : AUTO_TYPE ) : AUTO_TYPE { p . translate ( 1 , 1 ) } ; - main ( ) : Object { - let p : AUTO_TYPE <- new Point in { - step ( p ) ; (*Puede lanzar error semantico*) - } - } ; - } ; - """ - - ast = run_pipeline(text) - - formatter = FormatVisitor() - tree = formatter.visit(ast) - - tree = tree.replace("\t", "") - tree = tree.replace("\n", "") - tree = tree.replace("\\", "") - - assert ( - tree - == "__ProgramNode [ ... ]__ClassDeclarationNode: class Point { ... }__FuncDeclarationNode: step(p:AUTO_TYPE) : AUTO_TYPE { }__CallNode: .translate(, ..., )__ VariableNode: p__ ConstantNumNode: 1__ ConstantNumNode: 1__FuncDeclarationNode: main() : Object { }__LetNode: let in __VarDeclarationNode: p : AUTO_TYPE <- __ InstantiateNode: new Point()__BlockNode: {; ... ;}__CallNode: step(, ..., )__ VariableNode: p" - ) diff --git a/customized_tests/test_redefinitions.py b/customized_tests/test_redefinitions.py deleted file mode 100644 index 17549030f..000000000 --- a/customized_tests/test_redefinitions.py +++ /dev/null @@ -1,57 +0,0 @@ -from run_pipeline import run_pipeline -from src.type_collector import TypeCollector -from src.type_builder import TypeBuilder -from src.type_checker import TypeChecker -from src.tset_builder import TSetBuilder -from src.tsets_reducer import TSetReducer -from src.tset_merger import TSetMerger -from src.cool_visitor import FormatVisitor - - -def test(): - - text = """ - - class B inherits Point { - x : String ; - init ( n : String , z : Int , z : Int) : Bool { - { - n <- "ok" ; - z <- 1 + 3 ; - } } ; - } ; - class Point { - x : AUTO_TYPE ; - y : AUTO_TYPE ; - init ( n : Int , m : Int ) : Int { - { - x <- n ; - y <- m ; - } } ; - } ; - - """ - - print("corriendo") - ast = run_pipeline(text) - errors = [] - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - checker.visit(ast, None) - - assert errors == [ - 'Attribute "x" is already defined in B.', - "A class Main with a method main most be provided", - "More tan one param in method init has the name z", - 'Cannot convert "Int" into "Bool".', - 'Method "init" already defined in "an ancestor of B" with a different signature.', - ] - diff --git a/customized_tests/test_reducer.py b/customized_tests/test_reducer.py deleted file mode 100644 index 143a70d62..000000000 --- a/customized_tests/test_reducer.py +++ /dev/null @@ -1,77 +0,0 @@ -from run_pipeline import run_pipeline -from src.type_collector import TypeCollector -from src.type_builder import TypeBuilder -from src.type_checker import TypeChecker -from src.tset_builder import TSetBuilder -from src.tsets_reducer import TSetReducer - - -def test(): - text = """ - - class A { - a : String ; - b : AUTO_TYPE ; - c : AUTO_TYPE <- 0 ; - d : Object <- while c loop c + 1 pool ; - j : AUTO_TYPE ; - l : AUTO_TYPE ; - fact ( n : AUTO_TYPE ) : AUTO_TYPE { if n < 0 then 1 else n + fact ( n - 1 ) fi } ; - step ( p : AUTO_TYPE ) : AUTO_TYPE { - b <- - { - p + 5 ; - j <- p ; - p <- false ; - isvoid d ; - - - l @ Point . main ( ) ; - } - } ; - } ; - class Point inherits A { - h : AUTO_TYPE <- "debe ser tipo string" ; - k : AUTO_TYPE ; - main ( ) : AUTO_TYPE { - let i : AUTO_TYPE <- new A in { - isvoid i ; (*Puede lanzar error semantico*) - } - } ; - ackermann ( m : AUTO_TYPE , n : AUTO_TYPE ) : AUTO_TYPE { - if m < 0 then 1 else - if n < 0 then ackermann ( m - 1 , 1 ) else - ackermann ( m - 1 , ackermann ( m , n - 1 ) ) - fi - fi - } ; - } ; - - """ - - ast = run_pipeline(text) - errors = [] - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - __ = checker.visit(ast, None) - - tset_builder = TSetBuilder(context, errors) - tset = tset_builder.visit(ast, None) - - tset_reducer = TSetReducer(context, errors) - reduced_set = tset_reducer.visit(ast, tset) - - print("Errors:", errors) - print("Context:") - print(context) - print(reduced_set) - - assert errors == ["A class Main with a method main most be provided"] diff --git a/customized_tests/test_reducer2.py b/customized_tests/test_reducer2.py deleted file mode 100644 index 16516061d..000000000 --- a/customized_tests/test_reducer2.py +++ /dev/null @@ -1,53 +0,0 @@ -from run_pipeline import run_pipeline -from src.type_collector import TypeCollector -from src.type_builder import TypeBuilder -from src.type_checker import TypeChecker -from src.tset_builder import TSetBuilder -from src.tsets_reducer import TSetReducer - - -def test(): - text = """ - - class A { - a : String ; - } ; - class Point inherits A { - ackermann ( m : AUTO_TYPE , n : AUTO_TYPE ) : AUTO_TYPE { - if m < 0 then 1 else - if n < 0 then ackermann ( m - 1 , 1 ) else - ackermann ( m - 1 , ackermann ( m , n - 1 ) ) - fi - fi - } ; - - } ; - - """ - - ast = run_pipeline(text) - errors = [] - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - __ = checker.visit(ast, None) - - tset_builder = TSetBuilder(context, errors) - tset = tset_builder.visit(ast, None) - - tset_reducer = TSetReducer(context, errors) - reduced_set = tset_reducer.visit(ast, tset) - - print("Errors:", errors) - print("Context:") - print(context) - print(reduced_set) - - assert errors == ["A class Main with a method main most be provided"] diff --git a/customized_tests/test_reducer3.py b/customized_tests/test_reducer3.py deleted file mode 100644 index 8e0fefe96..000000000 --- a/customized_tests/test_reducer3.py +++ /dev/null @@ -1,55 +0,0 @@ -from run_pipeline import run_pipeline -from src.type_collector import TypeCollector -from src.type_builder import TypeBuilder -from src.type_checker import TypeChecker -from src.tset_builder import TSetBuilder -from src.tsets_reducer import TSetReducer - - -def test(): - text = """ - - class A { - a : String ; - } ; - class Point inherits A { - f ( a : AUTO_TYPE , b : AUTO_TYPE ) : AUTO_TYPE { - if ( a = 1 ) then b else - g ( a + 1 , b / 2 ) - fi - } ; - g ( a : AUTO_TYPE , b : AUTO_TYPE ) : AUTO_TYPE { - if ( b = 1 ) then a else - f ( a / 2 , b + 1 ) - fi - } ; - } ; - - """ - - ast = run_pipeline(text) - errors = [] - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - __ = checker.visit(ast, None) - - tset_builder = TSetBuilder(context, errors) - tset = tset_builder.visit(ast, None) - - tset_reducer = TSetReducer(context, errors) - reduced_set = tset_reducer.visit(ast, tset) - - print("Errors:", errors) - print("Context:") - print(context) - print(reduced_set) - - assert errors == ["A class Main with a method main most be provided"] diff --git a/customized_tests/test_tset_builder.py b/customized_tests/test_tset_builder.py deleted file mode 100644 index c641539ce..000000000 --- a/customized_tests/test_tset_builder.py +++ /dev/null @@ -1,79 +0,0 @@ -from run_pipeline import run_pipeline -from src.type_collector import TypeCollector -from src.type_builder import TypeBuilder -from src.type_checker import TypeChecker -from src.tset_builder import TSetBuilder - - -def test(): - text = """ - class A { - a : String ; - b : Bool ; - c : Int <- 0 ; - d : Object <- while c < 1 loop c = c + 1 pool ; - step ( p : AUTO_TYPE ) : AUTO_TYPE { p . translate ( 1 , 1 ) } ; - } ; - - class Point { - step ( p : AUTO_TYPE ) : AUTO_TYPE { p . translate ( 1 , 1 ) } ; - main ( ) : Object { - let p : AUTO_TYPE <- new Point in { - step ( p ) ; (*Puede lanzar error semantico*) - } - } ; - } ; - class B inherits A { - e : Bool ; - step ( p : AUTO_TYPE ) : AUTO_TYPE { p } ; - test ( e : Int ) : Bool { - { - let x : Int <- 4 in e + ~ x ; - - case 5 + 4 of - f : Bool => f ; - g : Bool => not g ; - esac ; - self . step ( e ) ; - } - } ; - } ; - - class C { - a : B ; - b : Int <- 8 ; - c : Bool <- false ; - - m ( ) : Bool { - { - a @ A . step ( b ) ; - if not c then true else false fi ; - a . step ( b ) ; - } - } ; - } ; - """ - - ast = run_pipeline(text) - errors = [] - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - scope = checker.visit(ast, None) - - tset_builder = TSetBuilder(context, errors) - tset = tset_builder.visit(ast, None) - - print("Errors:", errors) - print("Context:") - print(context) - print(tset) - - assert errors == ["A class Main with a method main most be provided"] diff --git a/customized_tests/test_type_builder.py b/customized_tests/test_type_builder.py deleted file mode 100644 index 2a8516f83..000000000 --- a/customized_tests/test_type_builder.py +++ /dev/null @@ -1,39 +0,0 @@ -from run_pipeline import run_pipeline -from src.type_collector import TypeCollector -from src.type_builder import TypeBuilder - - -def test(): - text = """ - class A { - a : String ; - b : Bool ; - c : Int <- 0 ; - d : Object <- while c < 1 loop c = c + 1 pool ; - } ; - class Point { - step ( p : AUTO_TYPE ) : AUTO_TYPE { p . translate ( 1 , 1 ) } ; - main ( ) : Object { - let p : AUTO_TYPE <- new Point in { - step ( p ) ; (*Puede lanzar error semantico*) - } - } ; - } ; - """ - - ast = run_pipeline(text) - errors = [] - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - print("Errors:", errors) - print("Context:") - print(context) - - assert errors == ["A class Main with a method main most be provided"] diff --git a/customized_tests/test_type_checker.py b/customized_tests/test_type_checker.py deleted file mode 100644 index 9bdd5f4c9..000000000 --- a/customized_tests/test_type_checker.py +++ /dev/null @@ -1,75 +0,0 @@ -from run_pipeline import run_pipeline -from src.type_collector import TypeCollector -from src.type_builder import TypeBuilder -from src.type_checker import TypeChecker - - -def test(): - text = """ - class A { - a : String ; - b : Bool ; - c : Int <- 0 ; - d : Object <- while c < 1 loop c = c + 1 pool ; - step ( p : AUTO_TYPE ) : AUTO_TYPE { p . translate ( 1 , 1 ) } ; - } ; - - class Point { - step ( p : AUTO_TYPE ) : AUTO_TYPE { p . translate ( 1 , 1 ) } ; - main ( ) : Object { - let p : AUTO_TYPE <- new Point in { - step ( p ) ; (*Puede lanzar error semantico*) - } - } ; - } ; - class B inherits A { - e : Bool ; - step ( p : AUTO_TYPE ) : AUTO_TYPE { p } ; - test ( e : Int ) : Bool { - { - let x : Int <- 4 in e + ~ x ; - - case 5 + 4 of - f : Bool => f ; - g : Bool => not g ; - esac ; - self . step ( e ) ; - } - } ; - } ; - - class C { - a : B ; - b : Int <- 8 ; - c : Bool <- false ; - - m ( ) : Bool { - { - a @ A . step ( b ) ; - if not c then true else false fi ; - a . step ( b ) ; - } - } ; - } ; - """ - - ast = run_pipeline(text) - errors = [] - - collector = TypeCollector(errors) - collector.visit(ast) - - context = collector.context - - builder = TypeBuilder(context, errors) - builder.visit(ast) - - checker = TypeChecker(context, errors) - scope = checker.visit(ast, None) - - print("Errors:", errors) - print("Context:") - print(context) - print(scope) - - assert errors == ["A class Main with a method main most be provided"] diff --git a/customized_tests/test_type_collector.py b/customized_tests/test_type_collector.py deleted file mode 100644 index a94e8cf8e..000000000 --- a/customized_tests/test_type_collector.py +++ /dev/null @@ -1,30 +0,0 @@ -from run_pipeline import run_pipeline -from src.type_collector import TypeCollector - - -def test(): - text = """ - class A { } ; - class Point { - step ( p : AUTO_TYPE ) : AUTO_TYPE { p . translate ( 1 , 1 ) } ; - main ( ) : Object { - let p : AUTO_TYPE <- new Point in { - step ( p ) ; (*Puede lanzar error semantico*) - } - } ; - } ; - """ - - ast = run_pipeline(text) - errors = [] - - collector = TypeCollector(errors) - collector.visit(ast) - - # context = collector.context - - # print("Errors:", errors) - # print("Context:") - # print(context) - - assert errors == [] diff --git a/src/errors.py b/src/cmp/errors.py similarity index 100% rename from src/errors.py rename to src/cmp/errors.py diff --git a/src/cmp/evaluation.py b/src/cmp/evaluation.py index 48c5c28eb..269ff5225 100644 --- a/src/cmp/evaluation.py +++ b/src/cmp/evaluation.py @@ -1,5 +1,5 @@ from cmp.pycompiler import EOF -from shift_reduce_parsers import ShiftReduceParser +from parsing.shift_reduce_parsers import ShiftReduceParser def evaluate_reverse_parse(right_parse, operations, tokens): diff --git a/src/cmp/utils.py b/src/cmp/utils.py index b0308a277..af4bf37c4 100644 --- a/src/cmp/utils.py +++ b/src/cmp/utils.py @@ -158,75 +158,6 @@ def transform_to(self, token_type): def is_valid(self): return False - -def tokenizer(G, fixed_tokens): - def decorate(func): - def tokenize_text(text): - tokens = [] - collecting_str = False - str_token = "" - - # ---------Removing Comments(Comments starting with "--" are yet to implement)------------ - no_comments_text = "" - collecting_comment = False - for lex in text.split(): - if lex[0] == "*" and not collecting_comment: - collecting_comment = True - - elif lex[-1] == "*": - collecting_comment = False - continue - - if not collecting_comment: - no_comments_text += lex + " " - - text = no_comments_text - for lex in text.split(): - - # ------Building strings------------ - if lex[0] == '"' and not collecting_str: - collecting_str = True - if len(lex) > 1: - str_token += lex[1:] + " " - continue - - if lex[-1] == '"': - collecting_str = False - if len(lex) > 1: - str_token += lex[:-1] - token = Token( - str_token, G.terminals[39] - ) # 39 is the index of "string" terminal - tokens.append(token) - str_token = "" - continue - - if collecting_str: - str_token += lex + " " - continue - - try: - token = fixed_tokens[lex] - except KeyError: - token = UnknownToken(lex) - try: - token = func(token) - except TypeError: - pass - tokens.append(token) - tokens.append(Token("$", G.EOF)) - return tokens - - if hasattr(func, "__call__"): - return tokenize_text - elif isinstance(func, str): - return tokenize_text(func) - else: - raise TypeError('Argument must be "str" or a callable object.') - - return decorate - - class DisjointSet: def __init__(self, *items): self.nodes = {x: DisjointNode(x) for x in items} diff --git a/src/code_gen/__init__.py b/src/code_gen/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/ast_typed_nodes.py b/src/code_gen/ast_typed_nodes.py similarity index 100% rename from src/ast_typed_nodes.py rename to src/code_gen/ast_typed_nodes.py diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index f24013083..b49a9c9f4 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -2,7 +2,7 @@ import cmp.nbpackage import cmp.visitor as visitor -import ast_typed_nodes as cool +import code_gen.ast_typed_nodes as cool from cmp.cil import ( ProgramNode, @@ -49,7 +49,7 @@ ExitNode, CompareTypes ) -from cool_visitor import FormatVisitor +from semantic.cool_visitor import FormatVisitor from cmp.semantic import Attribute, Method, Type from cmp.semantic import VoidType, ErrorType, IntType diff --git a/src/main.py b/src/main.py index d3190f10c..4520a750b 100644 --- a/src/main.py +++ b/src/main.py @@ -1,19 +1,19 @@ -from lexical_analizer import tokenize_cool_text -from cool_grammar import define_cool_grammar -from cool_visitor import FormatVisitorST -from visitor_type_ast import FormatVisitorTypedAst +from parsing.lexical_analizer import tokenize_cool_text +from parsing.cool_grammar import define_cool_grammar +from semantic.cool_visitor import FormatVisitorST +from parsing.visitor_type_ast import FormatVisitorTypedAst -from type_collector import TypeCollector -from type_builder import TypeBuilder -from type_checker import TypeChecker +from semantic.type_collector import TypeCollector +from semantic.type_builder import TypeBuilder +from semantic.type_checker import TypeChecker -from shift_reduce_parsers import LR1Parser, DerivationTree -from errors import parsing_table_error, Error +from parsing.shift_reduce_parsers import LR1Parser, DerivationTree +from cmp.errors import parsing_table_error, Error from cmp.evaluation import evaluate_reverse_parse from pathlib import Path -from errors import InvalidInputFileError -from cool_visitor import FormatVisitor +from cmp.errors import InvalidInputFileError +from semantic.cool_visitor import FormatVisitor from code_gen.cil_builder import CILBuilder from code_gen.mips_builder import MIPSBuilder from code_gen.mips_writer import MIPSWriter diff --git a/src/parsing/__init__.py b/src/parsing/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/cool_grammar.py b/src/parsing/cool_grammar.py similarity index 97% rename from src/cool_grammar.py rename to src/parsing/cool_grammar.py index 25e416b43..60eeae8c3 100644 --- a/src/cool_grammar.py +++ b/src/parsing/cool_grammar.py @@ -1,5 +1,5 @@ from cmp.pycompiler import Grammar -from ast_nodes import ( +from semantic.ast_nodes import ( ProgramNode, ClassDeclarationNode, FuncDeclarationNode, diff --git a/src/cool_tokenizer.py b/src/parsing/cool_tokenizer.py similarity index 100% rename from src/cool_tokenizer.py rename to src/parsing/cool_tokenizer.py diff --git a/src/lexical_analizer.py b/src/parsing/lexical_analizer.py similarity index 93% rename from src/lexical_analizer.py rename to src/parsing/lexical_analizer.py index 0ce8d40c1..27f2dd339 100644 --- a/src/lexical_analizer.py +++ b/src/parsing/lexical_analizer.py @@ -1,7 +1,6 @@ import ply.lex as lex -import tokens_rules as tokens_rules +import parsing.tokens_rules as tokens_rules from cmp.utils import Token -from utils import find_column def pprint_tokens(tokens): indent = 0 @@ -17,6 +16,9 @@ def pprint_tokens(tokens): indent += 1 print(" ".join([str(t.token_type) for t in pending])) +def find_column(input, lexpos): + line_start = input.rfind('\n', 0, lexpos) + 1 + return (lexpos - line_start) + 1 def tokenize_cool_text(grammar, idx, type_id, string, num, data, errors, printing=False): # lexer starts with: lexpos = 0, lineno = 1, last_new_line = 0 diff --git a/src/methods.py b/src/parsing/methods.py similarity index 95% rename from src/methods.py rename to src/parsing/methods.py index 8723d7c20..dd8ca0947 100644 --- a/src/methods.py +++ b/src/parsing/methods.py @@ -10,7 +10,7 @@ Grammar, ) from cmp.utils import ContainerSet -from errors import parsing_table_error, invalid_sentence_error +from cmp.errors import parsing_table_error, invalid_sentence_error from cmp.automata import State diff --git a/src/parser_automatons.py b/src/parsing/parser_automatons.py similarity index 96% rename from src/parser_automatons.py rename to src/parsing/parser_automatons.py index 437f4d16b..32f2124a0 100644 --- a/src/parser_automatons.py +++ b/src/parsing/parser_automatons.py @@ -1,7 +1,7 @@ from cmp.pycompiler import Item from cmp.automata import State, lr0_formatter, multiline_formatter from cmp.utils import ContainerSet -from methods import compute_firsts, compute_local_first, compute_follows +from parsing.methods import compute_firsts, compute_local_first, compute_follows # LR0 automaton -> for SLR and LALR parsers def build_LR0_automaton(G): diff --git a/src/shift_reduce_parsers.py b/src/parsing/shift_reduce_parsers.py similarity index 95% rename from src/shift_reduce_parsers.py rename to src/parsing/shift_reduce_parsers.py index 7464ee7ad..47353ce52 100644 --- a/src/shift_reduce_parsers.py +++ b/src/parsing/shift_reduce_parsers.py @@ -1,11 +1,11 @@ -from parser_automatons import ( +from parsing.parser_automatons import ( build_LR0_automaton, build_LR1_automaton, build_LALR_automaton, ) -from methods import compute_firsts, compute_local_first, compute_follows +from parsing.methods import compute_firsts, compute_local_first, compute_follows from cmp.automata import State -from errors import shift_reduce_error, invalid_sentence_error, SyntacticError +from cmp.errors import shift_reduce_error, invalid_sentence_error, SyntacticError class ShiftReduceParser: SHIFT = "SHIFT" diff --git a/src/tokens_rules.py b/src/parsing/tokens_rules.py similarity index 99% rename from src/tokens_rules.py rename to src/parsing/tokens_rules.py index db13e12a7..13a358020 100644 --- a/src/tokens_rules.py +++ b/src/parsing/tokens_rules.py @@ -1,7 +1,7 @@ # https://www.dabeaz.com/ply/ply.html # file for PLY rules -from errors import ( +from cmp.errors import ( tokenizer_error, LexicographicError, UnexpectedCharError, diff --git a/src/visitor_type_ast.py b/src/parsing/visitor_type_ast.py similarity index 99% rename from src/visitor_type_ast.py rename to src/parsing/visitor_type_ast.py index 79e47a705..a51fdd601 100644 --- a/src/visitor_type_ast.py +++ b/src/parsing/visitor_type_ast.py @@ -1,5 +1,5 @@ import cmp.visitor as visitor -from ast_typed_nodes import ( +from code_gen.ast_typed_nodes import ( ProgramNode, ClassDeclarationNode, FuncDeclarationNode, diff --git a/src/semantic/__init__.py b/src/semantic/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/ast_nodes.py b/src/semantic/ast_nodes.py similarity index 100% rename from src/ast_nodes.py rename to src/semantic/ast_nodes.py diff --git a/src/cool_visitor.py b/src/semantic/cool_visitor.py similarity index 96% rename from src/cool_visitor.py rename to src/semantic/cool_visitor.py index 676e9290f..42afa90d6 100644 --- a/src/cool_visitor.py +++ b/src/semantic/cool_visitor.py @@ -1,5 +1,5 @@ import cmp.visitor as visitor -from ast_nodes import ( +from semantic.ast_nodes import ( ProgramNode, ClassDeclarationNode, FuncDeclarationNode, diff --git a/src/tset.py b/src/semantic/tset.py similarity index 100% rename from src/tset.py rename to src/semantic/tset.py diff --git a/src/type_builder.py b/src/semantic/type_builder.py similarity index 98% rename from src/type_builder.py rename to src/semantic/type_builder.py index befe70a4e..d4107b999 100644 --- a/src/type_builder.py +++ b/src/semantic/type_builder.py @@ -3,17 +3,17 @@ from cmp.semantic import Attribute, Method, Type from cmp.semantic import VoidType, IntType, ErrorType, StringType, BoolType from cmp.semantic import Context -from ast_nodes import ( +from semantic.ast_nodes import ( ProgramNode, ClassDeclarationNode, AttrDeclarationNode, FuncDeclarationNode, ) import cmp.visitor as visitor -from tset import Tset +from semantic.tset import Tset from collections import deque -from cool_visitor import CopyVisitor -from errors import SemanticError, TypeError +from semantic.cool_visitor import CopyVisitor +from cmp.errors import SemanticError, TypeError class TypeBuilder: def __init__(self, errors=[]): diff --git a/src/type_checker.py b/src/semantic/type_checker.py similarity index 98% rename from src/type_checker.py rename to src/semantic/type_checker.py index 5d4b1435a..414b49ff7 100644 --- a/src/type_checker.py +++ b/src/semantic/type_checker.py @@ -2,10 +2,10 @@ import cmp.nbpackage import cmp.visitor as visitor -from ast_nodes import LessEqualNode, LessNode, Node, ProgramNode, ExpressionNode -from ast_nodes import ClassDeclarationNode, FuncDeclarationNode, AttrDeclarationNode -from ast_nodes import VarDeclarationNode, AssignNode, CallNode -from ast_nodes import ( +from semantic.ast_nodes import LessEqualNode, LessNode, Node, ProgramNode, ExpressionNode +from semantic.ast_nodes import ClassDeclarationNode, FuncDeclarationNode, AttrDeclarationNode +from semantic.ast_nodes import VarDeclarationNode, AssignNode, CallNode +from semantic.ast_nodes import ( AtomicNode, BinaryNode, ArithmeticOperation, @@ -18,7 +18,7 @@ BlockNode, IsvoidNode, ) -from ast_nodes import ( +from semantic.ast_nodes import ( ConstantNumNode, VariableNode, InstantiateNode, @@ -32,7 +32,7 @@ BooleanNode, StringNode, ) -from cool_visitor import FormatVisitor +from semantic.cool_visitor import FormatVisitor from cmp.semantic import SemanticError as SError from cmp.semantic import Attribute, Method, Type @@ -43,8 +43,8 @@ from cmp.utils import find_least_type import copy -from errors import TypeError, NameError, SemanticError, AttributeError -import ast_typed_nodes as cool_type_nodes +from cmp.errors import TypeError, NameError, SemanticError, AttributeError +import code_gen.ast_typed_nodes as cool_type_nodes # some predefined errors WRONG_SIGNATURE = 'Method "%s" already defined in "%s" with a different signature.' diff --git a/src/type_collector.py b/src/semantic/type_collector.py similarity index 92% rename from src/type_collector.py rename to src/semantic/type_collector.py index 7377a7bfb..3d5789ac3 100644 --- a/src/type_collector.py +++ b/src/semantic/type_collector.py @@ -12,10 +12,10 @@ IOType, ) from cmp.semantic import Context -from ast_nodes import ProgramNode, ClassDeclarationNode +from semantic.ast_nodes import ProgramNode, ClassDeclarationNode import cmp.visitor as visitor -from cool_visitor import CopyVisitor -from errors import SemanticError +from semantic.cool_visitor import CopyVisitor +from cmp.errors import SemanticError class TypeCollector(object): def __init__(self, errors=[]): diff --git a/src/utils.py b/src/utils.py deleted file mode 100644 index 6ac51a3d2..000000000 --- a/src/utils.py +++ /dev/null @@ -1,3 +0,0 @@ -def find_column(input, lexpos): - line_start = input.rfind('\n', 0, lexpos) + 1 - return (lexpos - line_start) + 1 \ No newline at end of file From f81c14811a89bc34760b0eea3be36d1601238079 Mon Sep 17 00:00:00 2001 From: gabriela Date: Fri, 11 Mar 2022 17:26:00 -0500 Subject: [PATCH 161/162] Remove extra comments --- src/code_gen/cil_builder.py | 4 ++-- src/code_gen/mips_builder.py | 27 +-------------------------- src/code_gen/mips_writer.py | 2 -- src/semantic/ast_nodes.py | 2 -- src/semantic/type_builder.py | 1 - src/semantic/type_checker.py | 17 ++--------------- src/semantic/type_collector.py | 1 - 7 files changed, 5 insertions(+), 49 deletions(-) diff --git a/src/code_gen/cil_builder.py b/src/code_gen/cil_builder.py index b49a9c9f4..520a44de9 100644 --- a/src/code_gen/cil_builder.py +++ b/src/code_gen/cil_builder.py @@ -411,7 +411,7 @@ def io_instring(self): def io_inint(self): self.params.append(ParamNode("self")) ret_vinfo = self.define_internal_local() - self.register_instruction(ReadIntNode(ret_vinfo)) # TODO: ReadInt? + self.register_instruction(ReadIntNode(ret_vinfo)) self.register_instruction(ReturnNode(ret_vinfo)) def reset_state(self): @@ -763,7 +763,7 @@ def get_asserted_branch(least_type:str): @visitor.when(cool.CaseItemNode) def visit(self, node, return_var=None): - pass # TODO: Pending!!! + pass # Arithmetic and comparison operators @visitor.when(cool.PlusNode) diff --git a/src/code_gen/mips_builder.py b/src/code_gen/mips_builder.py index 107e4f8cf..2f6cb178e 100644 --- a/src/code_gen/mips_builder.py +++ b/src/code_gen/mips_builder.py @@ -1,9 +1,3 @@ -# from atexit import register -# from email.quoprimime import body_length -# from operator import le -# from tkinter.tix import Select -# from soupsieve import select - import cmp.visitor as visitor import cmp.cil as cil import random @@ -91,7 +85,6 @@ class MemoryManager: def __init__(self): - # self.all_reg = [t0,t1,t2,t3,t4,t5,t6,t7,t8,t9] self.all_reg = [t0, t1, t2, t3, t4, t5, t9] self.used_reg = [] @@ -215,9 +208,6 @@ def generate_copy(self): # copies from t1 to t6 a0 bytes self.memo.save() self.current_procedure = mips.ProcedureNode(COPY) - #r = self.memo.get_unused_reg() - #self.register_instruction(mips.LoadInmediate,r,-1) - #self.register_instruction(mips.BranchOnEqualNode,r,a0,"copy_end") self.register_instruction(mips.Label, "copy_loop") self.register_instruction(mips.BranchOnEqualNode, zero, a0, "copy_end") @@ -859,8 +849,6 @@ def visit(self,node): def visit(self, node): self.register_instruction(mips.CommentNode,"Executing Substring") - #self.detect_substring_out_of_range(node.idx.offset, node.length.offset, node.source.offset) - #allocating new char array if isinstance(node.length,int): self.register_instruction(mips.LoadInmediate,s0,node.length) @@ -1028,22 +1016,11 @@ def visit(self,node): mips.MoveNode, reg3, v0 ) # saving pointer to char array - - - #self.register_instruction(mips.AddNode, a0, a0, -1) ####?????????? - - - self.register_instruction( mips.CommentNode, "Copying bytes from one char array to another" ) self.register_instruction(mips.JumpAndLink, "Input") - - - #self.register_instruction(mips.CommentNode, "Null-terminating the string") - #self.register_instruction(mips.StoreByteNode, zero, 0, t6) - self.register_instruction(mips.CommentNode, "Allocating new String instance") _size = STRING_SIZE self.register_instruction(mips.LoadInmediate, v0, SYSCALL_SBRK) @@ -1142,8 +1119,6 @@ def visit(self,node): def visit(self, node): pass - - - @visitor.when(cil.LocalNode) #No hace falta + @visitor.when(cil.LocalNode) def visit(self,node): pass diff --git a/src/code_gen/mips_writer.py b/src/code_gen/mips_writer.py index 8dabf5e26..5801ed400 100644 --- a/src/code_gen/mips_writer.py +++ b/src/code_gen/mips_writer.py @@ -1,5 +1,3 @@ -#from cool.utils.config import * -#import cool.structs.mips_ast_hierarchy as mips import code_gen.mips_nodes as mips import cmp.visitor as visitor diff --git a/src/semantic/ast_nodes.py b/src/semantic/ast_nodes.py index 9d354765e..bb0e00c79 100644 --- a/src/semantic/ast_nodes.py +++ b/src/semantic/ast_nodes.py @@ -86,7 +86,6 @@ def __init__(self, exp, case_items, token): self.case_items = case_items self.token = token -#este no existe en la otra jerarquia class CaseItemNode(ExpressionNode): def __init__(self, idx, typex, exp, token): self.id = idx @@ -119,7 +118,6 @@ def __init__(self, token): self.token = token -#aqui y abajo se llama symbol class UnaryNode(ExpressionNode): def __init__(self, expr, token): self.expr = expr diff --git a/src/semantic/type_builder.py b/src/semantic/type_builder.py index d4107b999..fb86153f0 100644 --- a/src/semantic/type_builder.py +++ b/src/semantic/type_builder.py @@ -185,7 +185,6 @@ def visit(self, node): ) except SError as error: # method already defined node_row, node_col = node.id.location - # print("--------aqui se esta reportando el error del metodo doble---------") self.errors.append(SemanticError(node_row, node_col,error.text)) @visitor.when(AttrDeclarationNode) diff --git a/src/semantic/type_checker.py b/src/semantic/type_checker.py index 414b49ff7..33f0887aa 100644 --- a/src/semantic/type_checker.py +++ b/src/semantic/type_checker.py @@ -158,7 +158,6 @@ def visit(self, node, scope): except SError as e: # ERROR already reported in type builder - # return ErrorType() type_not_found = True if node.init_exp != None: @@ -171,7 +170,6 @@ def visit(self, node, scope): self.errors.append(TypeError(line, col,INCOMPATIBLE_TYPES % (init_expr_type.name, typex.name))) else: init_exp = None - # return typex AQUI SE RETORNABA UN TIPO PERO NO ES NECESARIO return cool_type_nodes.AttrDeclarationNode(node.id.lex, node.type.lex, init_exp) @visitor.when(FuncDeclarationNode) @@ -186,11 +184,11 @@ def visit(self, node, scope): # ------------parameters most have differente names------------ param_names = self.current_method.param_names param_types = self.current_method.param_types - param_used = {} # VERIFICAR SI ESTOS TIPOS SON STRING O DE LOS .NAME + param_used = {} new_params = [] for i, param_name in enumerate(param_names): - param_n, param_t = node.params[i] # AQUI A ESTO NO LE DEBERIA PREGUNTAR POR EL LEX? + param_n, param_t = node.params[i] new_params.append((param_n.lex, param_t.lex)) if param_name == "self": node_row, node_col = param_n.location # location of param name @@ -248,17 +246,6 @@ def visit(self, node, scope): except SError: pass # parent has no method named like this - # try: - # return_type = self.context.get_type(node.type.lex) - # # if return_type.name == "SELF_TYPE": - # # return self.current_type - # # return return_type ESTAS LINEAS ESTAN DE MAS PUES NO HACE FALTA RETORNAR TIPO - - # except SError as e: - # # Error already reported in type builder - # # return ErrorType() - # pass #it is not necessary to return a type in func declaration ndoes - return cool_type_nodes.FuncDeclarationNode(node.id.lex, new_params, node.type.lex, body_exp) @visitor.when(AssignNode) diff --git a/src/semantic/type_collector.py b/src/semantic/type_collector.py index 3d5789ac3..1b391e4d1 100644 --- a/src/semantic/type_collector.py +++ b/src/semantic/type_collector.py @@ -29,7 +29,6 @@ def visit(self, node): @visitor.when(ProgramNode) def visit(self, node): self.context = Context() - # TODO: Es necesario crear estos tipos especificos? self.context.types["Object"] = ObjectType() self.context.types["Int"] = IntType() self.context.types["String"] = StringType() From 1855d7fa54e2162a7d2349b90a7d73197a6cf87e Mon Sep 17 00:00:00 2001 From: gabriela Date: Fri, 11 Mar 2022 17:26:54 -0500 Subject: [PATCH 162/162] Finish report. --- doc/Report.md | 81 ++++++++++++++++++++++++++++++++++++++++++++----- doc/Report.pdf | Bin 0 -> 118567 bytes 2 files changed, 73 insertions(+), 8 deletions(-) create mode 100644 doc/Report.pdf diff --git a/doc/Report.md b/doc/Report.md index 0918e2ec5..7c89841c2 100644 --- a/doc/Report.md +++ b/doc/Report.md @@ -17,7 +17,7 @@ Para utilizar _El Compi_ y ejecutar un programa en el lenguaje COOL se han de se $ pip install -r requirements.txt ``` -2- Para compilar un código dado en COOL a ensamblador, ejecute: +2- Para compilar un código dado en COOL a MIPS, ejecute: ```bash $ ./coolc.sh @@ -47,13 +47,9 @@ _El Compi_, para tener la funcionalidad completa de un compilador, transita por Más adelante se analizan a profundidad cada una. -El código fuente del proyecto se encuentra en la carpeta _src_. En esta se hallan distribuidos los scripts según su funcionalidad. +El código fuente del proyecto se encuentra en la carpeta **src**. En esta se hallan distribuidos los scripts por módulos según su funcionalidad. -**FOTO de los archivos del proyecto** - -Si lo miramos como módulos, podemos decir que el módulo de lexe... en _code_gen_ encontramos todo lo referente al proceso de generación de código... en tools todo los utils para... - -**COMPLETAR** +En el módulo de **parsing** se halla definida nuestra gramática, y se brindan herramientas para trabajar con el lexer de **PLY** y el parser LR1 definido. El módulo **semantic** implementa los nodos del ast de **Cool** con que se trabaja y los recorridos para las definiciones de tipos y el chequeo semántico en general. En **code_gen** encontramos todo lo referente al proceso de generación de código, desde los nodos de **CIL** hasta los de **MIPS** y el pipeline para hacer dichas conversiones. Finalmente, en **cmp** se mantienen algunos útiles proporcionados por el claustro de Compilación, algunos adaptados a los requerimientos del proyecto actual. Analicemos ahora los prometidos detalles de implementacion y diseño tan anunciados. @@ -174,4 +170,73 @@ El tipo dinámico **C** no se conoce hasta el momento de ejecución, que es cuan ### De CIL a MIPS: -... +Para la generación de código MIPS se definió un visitor sobre el ast de CIL generado en el paso anterior, este visitor generará a su vez un ast de MIPS que representa las secciones .data y .text con sus instrucciones; donde cada nodo conoce su representación en MIPS. Posteriormente se visitará en nodo principal del ast de MIPS y se producirá el código que será ejecutado por el emulador de SPIM. + + Al visitar el cil.Program se visitarán los nodos de la sección dottype, para representar en .data la tabla de métodos virtuales, para cuando se produzcan llamadas a métodos no estáticos. Por cada TypeNode se registra en .data un label con el nombre del tipo, .word como tipo de almacenamiento, y una serie de labels, cada una correspondiente a un método del tipo. + +```mips +Object : .word, Object_abort, Object_copy, Object_type_name +``` + + Para acceder a un método específico de un tipo se busca en la dirección de memoria dada por el label correspondiente a este, sumada con el índice correspodiente al método, multiplicado por 4 este índice está dado por el orden en que se declararon los métodos, aquí se hallará un puntero al método deseado. + +El siguiente paso es visitar la sección dotdata, para registrar los strings declarados en el código de COOL, de la siguiente forma: + +``` +string_1 : .asciiz, "Hello, World.\n" +``` + +Finalmente se visitarán los nodos de la sección dotcode, que corresponden a las instrucciones del programa. + +Cada uno de estos nodos es un FunctionNode, en cada uno se van generando nodos del ast siguiendo la siguiente línea: + +- Se reserva el espacio de las variables locales correspondientes a la función. + +- Se actualiza el frame pointer #$fp# con el stack pointer. + +- Se guarda la dirección de retorno $ra en la pila. + +- Se guarda el frame pointer anterior en la pila. + +- Se visitan las instrucciones de la función. + +- Se restaura el puntero al bloque remplazándolo con el que había sido almacenado. + +- Se restaura la dirección de retorno. + +- Se libera el espacio que había sido reservado en la pila. + + Siempre se conocerá el offset, con respecto a $fp correspondiete a las variables locales y parámetros que se utilizan en el cuerpo de una función. + + Para realizar llamadas a funciones que reciban argumentos es obligatorio guardar los argumentos en la pila antes de llamar a la función. + + El recorrido por las instrucciones no es presenta gran complejidad, es simplemente traducir sencillas expresiones de CIL a expresiones de MIPS, sin embargo hay algunos casos interesantes que vale la pena destacar. + + - La reserva dinámica de memoria para instanciar tipos se realiza mediante Allocate, el compilador reservará un espacio de tamaño (CantidadAtributos + 1) * 4. En los primeros 4 bytes ser guarda la dirección del tipo de la instancia, y en las siguientes palabras están reservadas para los atributos. + + La representación de las instancias de tipos en memoria se estructuró así: + + | Tipo | Atributo 1 | Atributo 2 | .... | Atributo n | + | :-------: | :---------: | :---------: | :--: | :-----------: | + | Dirección | Dirección+4 | Dirección+8 | | Dirección+4*n | + + - Existen dos tipos de llamados a funciones, llamado estático y dinámico. + + El llamado estático es muy sencillo es simplementer saltar al label dado mediante la función de MIPS **jal** y al retornar, liberar el espacio en la pila correspondiente a los argumentos pasados a la función. + + Por otro lado el llamado dinámico es más complejo, pues dada la instancia y el índice del método, se busca en la pila la instancia, se toma la posición 0 que corresponde a la dirección(d) de su tipo, y a partir de esta se obtiene la función que está en d + 4 * i. Luego se salta al label de la función y por último se libera el espacio en la pila correspondiente a los argumentos pasados. + + Mucho nodos son importantes entre ellos los que corresponden a la entrada y salida, a las operaciones sobre cadenas, y operaciones lógicas y aritméticas, estos llevan más trabajo con la lógica de MIPS que no consideramos necesario de abordar. + + + + + + + + + + + + + diff --git a/doc/Report.pdf b/doc/Report.pdf new file mode 100644 index 0000000000000000000000000000000000000000..908046ce2cd356c73ce5f921f3e2fe87d154e53f GIT binary patch literal 118567 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%0A% z5Tf9RzZ2>IJPGU0n-uQsN`uB0|Go5Y$8V-PC~KOt#lLl=;r)+}H2N`t)k+<^pIh~p3%hx^H#UJhP_*De%`L-t z%mr9FYO#)dgo&O)Hr-r>4C#4?_+2ik`d#zK7Lp5|o9$G4d#G=sOhwzA_AwGjZ79xZ zY(czSzG8^j>wXi`U`_Rv+P&VZ>EDeUL} zc>cc_d&eM6f~{+`r!noGwryL}wr#tgw(V)#wrv~Jw)<(@w)M^VZp4jyBHp<1Mr35| zs;t@>l|Qm_?OM4uMfb;7Z>#+`dFxQDlVQO2mRj?_9cOc|-Mzc7kC!9zof6&NpHut{ zw$k)+bXr<|m+R~L!3v#-Kp3JX#G_OF+^@zvhEx6F-mKoEURdG1ce-fV>w#|8;T2Y3 zma(tq1_oay!>J}HFyZ)Z{q9lUjzE8A)7qQEm*%|2)enswjoq++IA>`p znzAY79B?ZapF&W=K0<}OX4I7vbnX}ygxzyPD=93mF zg5K+edW+_;c?}%f)Gl`E*t*#%F`&~%r?r3{G)#CJGSiBXEkGnh&|(jp-MKT2RP>O% zn8P;x)ae2&cuK&V_;}<{w3e(%jakxF#V!&YrCQ+MCD7hY>$OYHekdLy)C_37ywNN~ z&S0C52*)fbX{yX8N&Ujkrkm+Q=3hHZ2rGEu0_xh(gmZFrRc7}n1%H3tN)WFIzyJi5zsIQg8J=44)uH37|?RKa1vEZ3@i zFF)N!lch<|b~AWsZA)yjO%x&7YA2p+W9j3a_jOJBbu@|-mG5Db9!Uy-LR8SkF?VFw z+3k5Ebx8F^(a@M>yu<>EVoz9!2`DwIBDNhWXn3p&SOKd>Y#(CAGnJaB<+}ZE@5?@_ z>Pu+&lq=~XK^PORPQ#)85;uZ@fKpX%Qr3?eH(!RZC$kqNa+q}>{Yb}eptg!JZC0|I z=xE=}mI>1*m0HZ6#?Gn@dv|dx4i)8H5P0F!F7bbdaMx(CA6$)6 z<(|Cnx?4)(&AEaDD-;G0tP)P5uabqf_ucn5F&Js+T&pg8Z-Gz66vs3M^O!(|%4z0qDU za*|3a$O`0M%gQGDjbJD?FlGIBX7ZIwCmuX$1Y{cC;V;hI5sM>v95jjJRg6~PH&XcC z-l4m~YaB@Z)dhFNFvtYf(Z8jONtIF0@=(BY0C$k^K;0w7La25GZ{CvAOP;#JN!%-j zscgCHOa<9@>7~%axTPyQmQ_W=Z`; zO(%Q55PHMi+sS=l8mb2`Ns#U-PPzvgmK~(&rJCAG;y76>4Cm3vN#8%#hK4=eL3P%> ziho?d^)MV}_C6&LsmQ?_q-=dH!*T2|om5_K2=vW*cd~Y_aZdxDIv^TJlZ*)BvCL$c zT{eRUC;$=$>Oqj4GiWIvOOvSj#35u%r)DP7y@r*_)&X;>QNS`pS_@Y=o*8$mle{~d zOgSpa$T!|S>O&8M!Kuy)^Dnn%@U4W_Pl z(pANhZGC`t5?irWBp@?YM)1gi-U~+aDLSrL`7cpaarEjcBXCTuCMg|WBGs$k>=yT? z|577)R?*!9g*<*TE0*+{?bHc@^x7h@Tq~|R@d`SF;C5KJ+A-0eJQ*VFSql{YN^q!n z3`3H*BxMIJNBItoG?S#BuGfo`PZZf(uPrwUhn?LpMa^1)?)dkL6WC1WL^pY)bb3Hz zgzUc=7ly6DxTp;Mz)NJ?E(%xpO!sR!XsmNF7qLaTq^MY2&Nlk-d z1|>7Gg}e|y7&RWXLQkn|EJr%!8Lzwpb)@4}0euvKXAYHzom5Vhk=UDKqU7M}9s@;r zfmu+LLBz_~gkVms_FPY$)fk70ea!(Vk^5!=`TH!x*e=eMI{>uU!Rx1Nu; zl|W!pGbeU7)}dnLJq*e3%Mtfk<;W0SHDrz@vD*;brnfnQ=fYeUyC66pnH(IUKXifMdF+op4qDF$sUkI5tq@?)IXj|=YVIbV*m#fKn2I-K8MCn5)2A4xJmhTOu>DwyTmb%!Z*linrdwqAFo;v zg=`rnSjz%dBzRaZm`o2yt25Pjz7?O088-8LN5H1s31wz@z6S%LnOmI@N1cGCOuNK! zq9ze|+i>eBwlWdt9oPvyCOHU?^J_Z+0%CM%m0)h#eUF8RNmAJrbY(MIVHf4@rqYp| z^KceJWP~zz(c0JJpN;s1?tFhr!N<^6>%WJ{&hh*Yn@UT+^?wlu0#p^p{~Hq zz`J^GFFD&HtxY11Mso|bW94*Fs#dSC8|{}voaX$m7x}{!hVO8B_x5%d-j5}SZ}?5L zsiFA?>;ojV6GbxC0fbJyfec|Qiqz99aOQ637EI{poGqHLg!1Q|e5!|t#G)eR_K&-4 zJj%_(V1%TG9{vUY27(YF?3t4jjhAi>l)tcAuz0Wf>=r@*bzbo%xqlhl`Z^eabN92a z8EV0LULfZS{q2s_uBsn^=1po}=3f;DVtoU0MGV?GW))~!b8}vb8*l=+^Mn-GCaF`a z;HH=Y9N5;<+q`WV{+RlzZ;m3!hp(zAsLB&Eu3ng6R}--yI1r#dJ50A%AgROBBg1!_ zfq^Phk=X-^&N){^AXuEkA7=4+{-5l49tGJX%g71B>d_~p7|h;f6lT+ck2(hH8p?FD zZiUs+O=z+M+1v#$a@edYZDuW~mFra1D$WT%n6iqpA_Ya#-4q4UuVdP*&wHtD8=T93 z+a8l9YY)mM`yI57K6paT#6t;e78>~s>Vs=Og_S}Pn~ORqGbRa6FdH9K7oa_ytkq>6 z8V{ZvT&R+-DGnUg(*b%4vkm~&2W3B(`-ze8TB7gLVO+7|dq180ai>Ox^3%@oYX>n% z9KG8`uxM)5`}N5SIcS)k5F{mJopZp^M1>G}{dYG(&x@zS>kvTekI?o86aX>~&3HxXN0OfwO zF(22hy79!rkNAQT#{r#u>4qnV|pGQh`~zs zoah!qhcn?GT7PTUHY<~F;ftRm>d)SEUb#3#8Nzt8&nQalhKj*e(U;+CxAkj z<0LK@uU>HCOQuq4>D3)%S_tZJM{$=fH`mO@YgL?~OCQhtv4P|2L|GJXcgZb8?iHCP zAsDULM&G3czOWOZU1u8EOcpRIL7I)NuBNTTfwoHm6IMU);)8%C)UT*T}SSi%}w zF<|&@*Z(rH#mhItGczsVAUehWp8E|pc}y|$KVT3Rmj5jV;bi;oq}f9{vaz_WNZm8F zCr%)(uT!=Hh;@w_w^X5|ppNX|>w<_l;rk%3uSBb~cW7f@8j@nP(%b`Aq#f_Tr=@<|Mv!`MW7@}i zQ2bi}Hk3S|&xhOV){&8F@$Dzd_yP9hgWUAe66(x_YjZEigo9Hf&eW-`vaWu8j-zl$ z%;O~RL1TNhneluA3q5{p@T)){hVq;#kx49H0KDd(t{PM5t-{>><;limZ99!gt$ljB z7H5X|Q>{%KS|)rcJ^4xe^1SAod1A((nkC}D6KTgncXRe?JI-_w$v0U~?r;ZHUmP)3 z#mvI6n5656`>OkN9hKCx9_GsCGja%35FNqsg3vd`&sZ7}X#));YRO0(NwKJ8-rh10?07zkiw+v=pfiP)3*Ld{$NjEQYguw z6%<0`3JXiQWNLUKUQlO=e-Uk}-p)y)sq=TaM6U$Z99S*`-aqnxU1yAyjtW zZ$<=gC-qF{Y3oSAvIaOnaM8gy>r?fQTC0}?o3qQX%?3^cRh^|t1ek896IP`-GcAmx zfOnv@(~#VPxk>w+$mSM+i4dR8{)J;_OVK$7$Fl;Qr_RC<>ISHwNjSuu@Kg{DL59h0 znKL^VUgX`bAfrWe&fw=G&yktm2?BvPgYiraR2qG*||#94lltY*d@PlWPP8CFcl% zL|wlfgVDrLiI{`IGY$XKb?hGaSbi(*Y6lqK!~M;y{N&p(UoV9YN}Jsr4o0s;7tAva zmFLDSn5sFL#pHlUN}HZes2;!`1ug9-Om9#rF*F%nnO$5qr!95$=dV{kz~(G0aXFa> zG7&UmaxWtEpoou4o!8*KcGp#{x=}jas@X$_4EwHI#Fygh=%Gp{pxxDx^)XAiJ9{ai z;0Jft4oAgHG-!h_pwqBT2s3x?Z(I~kfmxF%AEe3)Iy1Zv%D-4fxJaZ(+GUGY1i6&K z)HKv>|612ZXCh0T#o+RF^&`E!WZLl2tu!4BiK1{&;#Hp0x%*|sK@O6vk8lpUWI{n1 z^WbX6<}{yIuTNs5XNQ+b3sO1SNZ{{yq+pQyY_t>vmWv$1^*!Zu3c_w0fLDNAT5^}l zb90{l2ufKbQq_St8TnB_w01HGWZF5VnSID_tEF(H&&(YiQRM)vDR?q!1D{-;>w49b zy@IF`OCJlE8b(YhMM~;juF9lU7=#=PWMG&~lA z@RE~%dcciRb=j?!vO^az{emUl&t*rNq#7bDVCs?ZsV{lEwruGU8cju|;}VHWi>s!3 z%|MhdoM+vRVST?2vZ<=SC$kxyKU@2Yhu%ifsUfK=V!XF6Y#X_4s)3srkyS z^PuI>{JjkF_uSG8=&Km9X>N!9NV@VdAPId?sc|CUo;DwUaX!2?A7U39&rq;AiSYL8 zDN%3rm@^xhR2al$Q5|Lo$2#V<;7Z$Eu{@gcb;#LPRGK}U!uQVn=#kZJ7Y-tiUD*N7N+)D@WZ;S6AG4E!)@fF@m{Ejui8w~ToQys49)eVszbO6a zI^c=90z8TwwFWRCiqtwXN$SxOO~uB5A>tPIgqN@U!JzcPDj~i!I)blZl3HL4li~sw zbk-OxBHlC54qFXspT&~OIIBmilAfh^=CIi@bSX`HOs-^GL!>1;c5UE{``_2b|^|Y(*-Y--Fp;bxbfPz+Xyp z?IP0_$_1O*=(N_TS}e?r3tBN*q#JAMZICLpFMxom#D&tACT&o`w(6x&Z|*IN-~>Ki zo8!2lij@)}DzA?c$dqlKP=L)*my^x)aU<9Y5d9oU2vRBld zoUh~^g{sa6pjCeN$~46m8m>k6_TEVCe6`WHMXXZvR`H{%X#z;(vC+kKEYzSg~vruacv|L48K| z`iJ_gJ6fGgS@H70en~*AnQd7$WX5qbr$#LPmg+atelV#B*T595S$owv;0Pux3Y3Bo z)}-MN6$c~iq@z)cz)Zo!qT+0O1J6l-ru9*!sNm7kD(d8Whb}%)F`mR0{p}x`bAHj*X7v zKUuwD_r{dFY>MpOp2_)V9FdY(w2jc#XlCkCsmIx87IU(7aPxR*-9l zvz5yh;AtbeL~SSRkN7~0R8@@9VulvuNJp^fgZCJLcMmm??%Ma^~*? zKXqtd1(WAE51G1(FSh_97Uh>W?D@`LxRx-x8DT?aIIInNSj7UKGCzD%hhiwkQ6;KG znMic0Cd1=`1tPOLUA0NeLbFf_m#uJp`r{+$?1ao*n|B9aJ<*Yw`tqrt>V^q3g^fck zJNGH~PS!S!e^p7D?@mtYt0#UM8&AyCS05g)pbzbQ;A;QoFHISrsoeR{VNhqM%vM?J zo1^}#(oT(}`buN!Um##RL@E$4ZU3GA0!jcMd?vV*arb(5C)2wuSlni}+F{bG0HqVapy zrRob}j74ohfNODD^BUTDl9qEYxwC|8lx3;j>yVuK7EfPlbw@xPV%Hic=Kv2aVXHWm zN+RuUqchOY`Gs4{>>)tErUV$MQFg2U_4>(hz2)N1In>B00Ai*y4 zydVcLaNm2ohP)zlDExRl`7Hf8HRnIrz2<`RB(m~g4S(6#O^I^Uk68jT8O#WOZ{?39 zwd=6rY>VCkBGtC*O2k~ca|E!=$wC=6UT}XiYReX6gl04pCcEfbz*wBef>6BqJvX;l zjAj0hNOJKyCLZ5{0`hN`%h+s1vlv;5@Kyda85va&$&zh|3z?NuUG}5FxH?(!yq@#Y z6(4z#@O4#DSgxNq#`vS|q#3i();0wlSl)>8AvQHVVJbLFFQ~H>i0ipVSc>U+nPb*^ zqeD7a$q?zCtp4Um5S6Z1Srhs`&V8k>c>(^T{s`q2WRPs714C)`mQG6El+Bn(=xzgw zp-l5?^Y^>=U4(Q{U!5rT^Y2v73cPgLk6^INMDE7 zhtF>!p7@@Qp(ez^L644;;-wJEv?}gd>()8x@3x$O zdtakNEMQ4hF2v(cgYFQUr=eWHHAOUW#s!8;M;&S1JXBeG%Q5$ig%5?*iX@bFjN)(e z`F!CxT(H@-dbZx6Tn36N^njAX`L43_dB~*Xw_ap(tts>$?WiUQ`UWJ&G6RW)KYqDZ zR-wlb)+nJRXdFmFBHTP<$1Sj1#ptpar2Lrnb_N!Cncat>KuWqm&pwf{Ya0%;EmCP7 z_@1wrjfP$B@b5T5Pu<<^>47?JOY3D|HNvY2slHmeXsMFF;gEr(K^X=Fv|B$_JpMp$ zeWdWZ&IN6$_dO0)A1bNUiJrQ{@Us70hLBfA04W65s6U{|Q*L|F41dZ|48{xp#@X z8nZEc>(di3^F!v@2So4>p2zTvB>E`iXnlYHjKSfz|AXr05=LfYrzU0tX?2RS34sfN zZdSGf&X@Jz=cl1KL3CbcF)-tDKXt+mV|>(>^LWzwB!THUNlD5!%c6nB^yTR>H`VXM z;yo5;z->G!P9}79f`aw$FBK*^SIOeL^VzBI&-EGYu9vsdyZssO_lNDsTmj{7i}ED> z-Q|htmX{gc?Apyg=l6#rog0+fIesqp5M3uFE9B{M>-VV>xzO=Ji20kbQN6|AQ=4|X zzWSSXXZSl1^dg>eBJP-8(lceOA;}IxL+5od5i^i&4vf)!G)=KMYhW3Ly7EPAhPA$S zzH;F?zpMs)GM~ifyL_{~`a_F8-#<4NG}ML%)^ZTgWDUOAcfsD(ZnH3+T zrZ{bUd;w;NU{$ksEtg_@DvqHE5dp9SX<60+lGZ-L%+SCW7!`2ZLsOD7hR(0i9W#%7 zvdB001pDaE`OF&jiKBn^TX|$%R9C6a4Se!!u60*COI%AS8#5M8QzDh#IB&TsU8dj) zYN!Y@4QQjsY2ARZ@zdvJjruK###1}q=J24M_URCtf|2ckp^)>TCU^xy42=S=gETX# z&~~szREn6u4zCCQF)nRgjRIw9;kbt6a%}bnxwCJ%{AEt?pZ;+aJOS|Lz4+TBIaMUP z&Gm`o)lSmba9T@iEV_+kwZ?HTuIS|jgqIR0Kd+^z$!VnCR{2B(pBrKGf+Q-_jC&*` z-E7QxPq7jwbO#exm?N&3y>wXBd`2SPOrYHcrK%niF)rjt9b|m_Hv}2C@ zkbc}={z^5Ssc9;KqD#zmBGegn9>Cr2Av>ZRlkOZ+YztS1s_j0QlN#52Cvx%{g79B(MrwykTsf4-lW z@)2Gh7lw!~;*x>3`t!~9%ekM;H)xFVUgsjRSnaRx5wOD~QLyLfjWp*M>CucB2;-N9 z1U6+Q^X_F^Y;KNc20%+;_aNxQE9xGWY0L$rVa{e>RyVigMs56x4@v^N7tJbFBtRLm z9OQ;)78bhU_zI)eOSU8jxxi*jvERHQp$w>vRDZIU9`no1s^7}*(ih3lJkpK5Rouxp zP@U!~=Qc_J#8zHlJ7p?WR9K)zF-}yma4@40qYZ8pb_qmDexQR9T5b7dUH}Ep9|ruR z7YfF2Tv{eh1gWfVZ$WwPKcxa0MAK)65K2T0v`=*zs~ zIt#*W!^P-(9E^#>k*RpYxU`5fybvkq1)!_Ij@--EFGDaf1%N+&hvefm>_1&2Phb zE`A_fzbn=9Cg90N?a+expu@TY*<-KkF)+=Yt)4`NT2v1;sq`lZ!Ols)blJVL9%y=V z1!eZks~S-A3XdAL0D`WL#i>ne4iec=P+QWU_I(7O+X=_gKCojrT`11gUp5>gh3|7lGYs7C9dYz{sqA^O+ela3~Hug{*2IwDvP~~LBfch>*r?B-! z^}tts#?0|-(axA~4Rt#oTKmDc@>Uz(JQn1~zIk^4j&hB&C*!(!JQBZ%`txpag z+ww~J!Wkn?XF3}=XKi9Rrvo8V3N&yc4Tma@g6Q@=NR}+rTCWrlB8*tfYpgpH-Z*Vd zXVIK*QGaF|mevLl!t>gne(r9J4@GuSG>r#(5V2Wv&=zT%CMf&hU#2Up|6Gp2W2NCk zHguEv2r2@tVz~YU8YTr7ZSUcuN&Yk(r6wfvG^^bUW>C^V>5@+`3a7zZEprjnqA(*i zL*S~(T8z;~t1=TI*JS&i8EEfSSlY!&?6>VK(y{AQ6C1MBfDLL`vFBFW`9$sK)iYpu z#Y~8W`-xx*;N^&nJDN3z_nv0V5=#oa1LnB!;Us~?4jxbbiTwy@N+Gc-3- zB=b~$P7_)vB1rz+{GjW2P+MX2))z(}n;|7^W;rX^AkVE9*(ZGuNr4Pkq@mW`XF+~c zBMZ6qHM!NWsQNR!(x0YmebD|20LH{N!{GG(XlHrtv+vg#dx07RE{NF|`2@bHEmenf zp4adqm=&yRCYo@lEBB8U%+Et;*RedZ=-Vm?vcM+F)vHje*g}N|(u;{V4Wq`dB`(MR ze#?4qze{CnD-VNK!a$?|WitZDjrGXhO-o1j==h5@DP`Z7Gp&bU9=Kd6RyJ(gj3nU; zEi6g|A5bf)x_HXeXy?VDj$`_=pp*akg_itd8U9*WjK;{rS>$@Oih$nF)f{7{JmW{W@NZ_V4 z`u90Js*&B2U=Yuk&k&~l`x-5Fa9SC7AH1mc1FH_?2>)ThjfwuE(PPu>z_DZTHU^YZ zdo)+u#5A2da=B`>_Xeo6mL2+mi}Z;a2_92>4_in`goqM&z)pdUIdvg8mj;~p`;x9W zSXJJUDgIZpaoS4GwBiLna#93mrmnZG1Cm=6tsXmL4pq^GB?HWP%KQhAwGbk0p!`hK zsjmiut}jEc3FO>!4!7xC6t=G9--V?5hBHxE1p=>woI375@yVJP7K%z zI%?hKVH^^=EWa8pdrK4_J8fQUaeCH6?AF=4s^nFX@ZMF*Jq&Xz3bOJBaT-GCxdYtc z64X_^Jr!|-_gE!DazD!9yENH(Ov{f6f~QoW@q0KSo_HmQI;`&_=Hmjv@yv?bc|h~O zn$sJj4fU0V9JIuRe433`xE4#1bMyd0wQ%{J$UGJG60#kn?#aO(4rRdMD%}f@X8jE_ zR@6DK_Ft+Dw6;r`0c8LdBL>}`VQS@1aHexqD>gxhj;DwHIB!|_{N%-bPveeIJBkqi^YL)6-$RC7j#uLHpDl;ZL;-pmdizD&qzsFxJ zcGsq-FfpG=Yt$6o_^;4V7G)a8cLN+jmdnbr5E@iL>1LMdcEoG^8@ICagf_DK`jNw^u6pCyt*i#=V%OPSCe-kz+OxfR=sNO7UnL)VD}Mje&q=<>2l1B=%Qy&^%EbtKkihuv&!_x&=; zi`AnK=o7cl49@^-`fog#ug|C9FB!S*hUwpUe(ztWp%gZYbedMOTx%m)8-{RQXhJuk zY>JyQqhBw#1oD2LQ?~?^#&&Dq$Fj7|vAr6)y-TY!E|FtKEN^{&eqZ~F{2wnfrQ4r# z_}?GbC@HaA_;aCu;Ju%nC+1!Pzxh$MgB3&>IsCvY_ilaOt&RA4cFjVK|4B|UMg+y$ z@@be^Cu^p%jSH!fA5tqLbVLLv#;j4G4r@34h}>|DkzA#A`jM+OTh7FILd>FOMr*Tc z0X3b^YCsijCq(xxw3c$KLlCEwabt2-e9C}vt55#Xf$r#gF)!?u(%Cc=7@ zJs$f-{%32cADV&!pYVaz$pBqp04(KXe*g`%!=bwM3mT5^P{=o!^~(fUP`*RVpKj3Q z+df%m%c=p~M?Z}eKH>P(TKQhD$IzCMHxqhB9iuBh6@agC%&wct)SQyF-mU?RU#cJRnh&q&rpD;sAH6=#T`eUH0R_kn0)<{2rePa%owU}5hRJS{V;x_AvLgJRXN!g zh3=f34s%7Q8n@Pr!8;AgWK7o14tCF^2G49xzlZy$LFE`N&S*rYl3Dv#u`<>l3*xL& z0hP1FT)@4?L*=d!;eZgcf_NOX07{v?x{;xXO~;z`Mb%8# z#7<#Oh~&d77OmYF;M>4wy^A)dEkU0BZ3zq#jI1fKd55E@I~$9PVHglwQ41x7w;q}nuDeY)2X0&D(sb_!9%iGo_tB~aD<74a9FVLeK zq0^{D+A(EM$8@q$bUheSN=Br?LKQI$N(D_w!H8ICO^U0Xgzz;uUC4lV{s0R_u*HZN z3PVPOJO(aRF;papQGym^8nluha4Vi%CtzA#A9wX>l)wExBVYuVGyq*5 zG$5zA85AZu21}gqn{zLI6^0nSQAz|nUTh%TlNCW{0-Y_!TSx?vJ`A&upAiQwP?cK* z{4^kpP#Y1+1m~X_71l>RRwPAC%(qLQuO?zrZO@?$ORUryyk3DvoIou?c!Gu$X^SC3 zN+TnvQNT^SBEBXnnG*+v#IL_b8YlFlv75T38U^IwKIx|d`|L2B6O z4SYh?m4`a52$LC9GVfiKqhHNsLA7h6aQcgQN8yWBR}IGA8|{)PJWvwGJUShg9y;;x zB`@dRHJW#zT?WkSf7J2wR6)W`Ct;8CWx8(5T7eemJrYf!X8#x$c0{-}Z);X;0YQbK_}2=jK&efIE=4AQHU>gj zn+Q^N>kckbYa)VRXEV5RvK%(F^@-GEokrW$DTE29GITn6TTrnA39Yb+3HPUC&WNxO z=ARRA1-(wPW0BPirvhg&%G%3-e@>BLidls6t;Hyls^MUZQ3gO2Tg%W8RdeiP>tIE0 z)!I^5u?jp}gBRA|MO;+F80}$2m<}Um9i^uwf!Ii%!HS57zl;{e2&Y zqoXrd@uKV4PJInSX|%=U-}R9f+k@C!J&i0*3I@aV*N4KX*NxGw5=0zb%yhE73$OO) zC_sV9gJx!F0S6RX{*t!>{3x~S#>(Nngvw3i2~WwB$Mik=eG1SHr&-o^Y+DX|yBGRx z+}ickgP?*+7?GGg$>cY|mEoQiV`V)2Wo%R5vah0KC2keDC9d^@?}+FmQ0F5=h-xKJ z?-0U;^x`Qi(89;dtFXcgv@n%aXoMpyAw?9Y;Haqmh0)+bxSvNRPs@?f@rs*+i5`9H z-3zZ8`)~&ih-6@P^W`G;(->7I=K`btDuzU`qqTeJ%6r-5CzvU79oxn5J_Od2=*y3On8Sj_jg6T4S2_QOl7;m#dUI& z3k3=4V9hJkKvlOf7Xhk~@>4lcFNZ3;NAhF=OQ}I{>%UB^N^2*zhbuNTOmp3qy~tnI z{t+xUOC6a1xZ;(^OdM8tKz?gJE`1-H4R@I@Ggp0<;Ms|HqDnn}8hE?)4|f4#S8G?& zI983f0I?qb!^%_UI#_;diy(S%qEHq1EJ){Wk$$c)G>&m9qKbY+9M!Jq- zJu>-^WWUllUX8boVwZ4@f_pNn^NjWG|8H9&|B=oA({}LRH+oDFIL#2;C-DQ)|MPfQ zwaFp5bJZu($v;Q?n0fX$|F27rM1DXD|B=_7IMnrX!TwC!G~4Wv{LOVJ#Xnr55-7mB zW@&GPf`I2RLz?N0$@79P%M1A0a=Q4H%O-qj%2=*;Ti24qw%}e@4K;>!BTN zAeG=zR^D?m9NCIWB-vFA&gUSV_u~Rc8>qL`zeDeyqOjcXFo)9TAf5v-_%g8=_J zqnA^z%%zrN9vB#|KKtgHJ-j1GrsL>dru6dbMt7u@rqw;^Z8N#IOSgUCRa4p~2o~P+ z9Up$)VE5UqW{&IigLt`Yy1zx1oiiV@&}=@sAl(@(Qcr?oTx~vjKHVA87-K%VA=tUl zo_LcoLy}`02mzfWSJWBy^AuqidY%{mR|JP8mPuSIhxz`=YF?@jNMLA#KlAXKYJZxI zI^KSt%vcnin-inb<`gJ)6@4_-4ZOwrW_#)$rZJ!JoVQd zte7+&tQZ$3>Vlrt$zw<_D4Kp<$DWp|XqU#IRNB4}v+M9oE*i$D0DD-Ikxk{+`WH38 z$27^><8Qk^i1m~8+7C?et``%sy|bttc};lt^Qr<3Hg|WsV|W|)dcJ$&W$`lc`&XwP z{CRnn7W`v|O5iwmdG+^vr#tG2OSRqDpUE`Nk0w_k?z>O-IWIYdyXG^h&bO0=>@TBv zcmWJXdRmUjCI2_0;hssc7|D_o41oD-j=oD;>WDkCR0UC}QR%=7^NOuxRT?2P1^cA6 zp`~y+WGm#>EGUSN6QCp*AAeBb0w5BD)q~Z`Fs=y0M^L-@;M$7i*a0Q^V}#!7;Ziqg zj{VO0@bp0`0wA|qBc9Zu5y23{l54H(q`TNcpM{PA5+xUovx8q6ow4QXKI)dY?OOU_ z?PtmSd;6buFFp{b(3SN&Z4fcxcd$UMM-1cstN7JQIE!4PaeaDTA&12hvsngSd$ed( zOY26;u;>qRTT#VMR6?iMM(#g`4}T%puM&K9HcgeuP~ zP^Tm*p9{Jxs!cy&7#a`9IWAR0pdyEh8LkHlFx_6N)S#VfY>67>NL9C!Yf{qU@~In6 zj3{iZ@JUU?qlcyBpykzN`3Mq`AyQh85k@dA%~l5_a9FA~B5iUhAj_Z{1#2Z6u_Z$5 zbt$ss5T0X?#hbewC|1Ri>>3qfwPO*qVOwk{Bw)X8DU@QT6RCGsNRpQKWJtb73#t+( z8Z*6$jX9X;=93FIYzlZJUKoSW39ONc?=xXEE{yV)*wm;pHXT@nP&}SmkyE-{Q&}Xr z-jQ`D{lo*R^=Nv%2)oqnvZ@H)*2W3jRkknNi=LrBYo7JmUo)v8!4zR2u@(s;83?Zv zV~#N^uc+a~^wqRptRpXsC6MZ!$>+t1VRBCD=vu>qU3uc)FdLZV3)X_|{?T&luHhGo6g>fZs>CW? zo18y~g*HN6VgmS@D(7h3pC8BSXk94F7q-t_gn>C~ppa+FkyckVpp03j!ybljlvF$_ z@3-->X?6|;o_BRLhl8gnzrJgL=>6$qJIddGm)V1tj(zGNtek0kUf@^$%>f+4-fDVs||#kFGNg`nW~{wAM~`g@4b> z)U3C?y7}l-SBKwT<=MW~#N}x8BEhJy=1pDwWCcSxW*YT^vN^MOausWnSgwirsZ*S! zowR*`W){Yvb7=`QYy{(=leap>CmGj6Wr?kouGyy{z-*6^%1qb6Se2;}G{Mvega#&C!4se+gqbrFRk)y}Y=Z zZQaZwxHT}1wW`3?jT(rrl0;=5r&cm9Xdk==i3K3XZc4{ehG1?b1d4_nyO^kU{?kbxnghG-i`=#y5*jT1fn}#AtDy~g{H?Ahq4sE_dq5JPm!#9d` zKo;vx4Go4Ox2FV{<5?mSB5G`C>beP zUG*uvo%ang<_y!Pn8tSQ4dJcN?WZS?dn-|*K|(1rFtEL*SnLNq#O?ML$KGL zXJ3*X1F$Ec0yb$wP}QH6f!ClFNol+nLG{T;nXj;J`&#O$L?m{2vllm7u(p%aImC*X ze#fnciDctYZ*Bg3VtMNCOYVSub&XdK%3l=6aqAZ?APLgzmPvZ8YOvvgZg&=z^QPQQ z#i?%PAo>7_K4^Q$O7Lfv9gglK;q&SY?7J?VQByOC);Cgme(nAyQ@N>Oz@%osJvb@y)S-S|!~(q+?$J%3!0OQ42JXD~YhK#N$y5vPscptvv0fDH zjD5Qg#d3`?H&kPWdvR=v@7k$X1c+hekm>8U_`BwP=fJXDX z(_L)Z?sZ0W^p!Y1b~wYCFMwPH`SrI22F5j}|FvbhdiCqYSm+=^V>}J5W%}3G@17jD z^;(O66bl45E6-5QOR}~7We;L4IGl|`|G0!i$mzM-o06+ z9lG$pTEcyX3u=4@~)R1^ZjXb($Js3+PQFYhXF+LGP$z$N!^>+)zsOX;( zv1|MiWmv!LS^31cxLQwTiAcH6H>{zP4v;j*u~SRO^|D5_8NpGw{&SwoIQ8|}2YGwp z&+oCrmz_LoMwT;!pOy%DnE-st^O!0bJPwu4a(%A4RVM3LfHdpiQr|n})FZ&l<7&+F z_XE2t;rC!#mv@hgW2)#=#k&-_$Bf1>7k{(%n@icsxB8&4$(FlA&wj=DTylYAz|k1~pT^<;yY)%N z)Yi<|oQaT$nT>-ThT;EDje(8vH^+aC%Ow}IGwMik?^~KQOU70E9N}W27>Nmya})xs zF)NTMA&%2|*CHPgnv}@azYhVi_ArnQOF<$k+eEXMmZ?QX15zu^VE1w2Ckg>)y(aKh zx=U|_lRa}2bDsy9yG5}2bBTo{sPSon%kH_mtF+?us^a^c;PbmyUzG(697M?wQR75s zBSGJp!p)6Zh<qJwuuVQp#Ud#oLA?8gvT7{jHofMpCBXq@2x zVeA}&L;>0?TefW*uWZ}4ZQI5x+qP}nwr$&-H=Bv+jz6M%ncK`w=FM~NcRYQi)q6}G z^r{{UBn}jFtKRBhvYH*c9cd%Q_dut<`<(2{n>Y@T)(AH$h2638`j#n)yS5v|X>+^F zUT5OX@&tsEM$zNvB=-w_QfXDs2mOf;IJuc#8UT*mn+s1UBKkF+6Qt|7JVZ}P20ZBm zGq`V#MwUFFrCGs0@ZlvCdJ^a*BP6X1^Z<`CN_#3NZ@~%L&(&Op%HBlT=Zt`0C~~FU z23nDac9D%6M{6r+4o2_My4d5z0g%M*?8x8>>4*vFM&7$1F42#5q- zH^3;kpH=q`uM2W?PQMypf5YTjvZ=bcxZPs>Km-~a8*OQIS=6$klFANJZK~H}N5*N= zj)t0+l4dM7kBy4B z?30Vv`w`EjMO&xvM6m{T8rc!6CY*#Smvl_=3b=1Iez((|r-&Mm!59)Bz@|bvSu&## zQ1c71$%O_jzF549X@!N8w@okwgoD+vdE~=tZmW(Yf<|;ScjH=(*b7DF?26bad8kq> z16$c_v7v0jSfr@uPw-x;Al%j&d>FD(iZ>e89E~|nlRW|dbe$J740T;09IMEo52Wf_ ztN=TonnJp4#JdC1p>1JWKZ$8zmy+l%Ym=}MRjSG^?P}hzn_GDhHGRj5{ODL<#z#IM z!6;6Fa!&1;5$RGzk5_Zig8(y_Q=nIJKF?f+6_v z`LfUq;^il0@{#!;7ikYHPZbvlTd)lgUKN)gf26R~u63A#;$ZzEdIj($QiZey1cL$f znuK z8qLaA@(!0=!Bz5k#VHcDrXdO^j(!CBM^9Aqw!d~L-<~^ph{Q%YDIigpJcfqE`}EOh zSU8H(HMcS2wDTSx=2JXwZ>>riaOMQC)yW=>46v#(W5#NW;%Qfw7O^=)(Sc2sES^z> z(kf=fjEu+*^NC1*=sA<}<)Mmj!(Ay#O|R0P?tc;u`~`3)&jGr79h3awm`DvkRAU$& z(h$&5mOw)S1YpodgA)rmg3}M`1aM1I5%b8PwchF|t>LsVu@CVHQJi52<@P6R$?k%a z*TVcj$}?Qvdr6D&y!dA8-L(}sw@QVA6yEV9U>_cyDaj* zS1h1kDxVnx!*_u336nl}J127EqcW(gL~bdSmy9K&=nCwkI!u+$sXK!p(t^(6-RHkIh#z6H%YQ*ExXKJh3n3azl zI$<15<+GM{HhP*&G{l^&zh3^=|J%DaMy@G=W-S4vJV?-W^k6GA2Ku7hv@B2UvmAxAqKhg z=TG&lnX8~g%v3~XN3`CBhWWLB1jkBu$&b*{;-p7tK_VuEgJ=TOuhKB79N2XNO-p9kn6`}*su!_PDwEyXuMmex=`p=Uh4*>(LL(r_$(8?o*emD;a~g)3 zOoCzUk`5P}n2-)TmN00+d&XnHg0)6o%)aaxYr5a%+-85hO)!c5y!_=U-SN3}+i2f( z-TCgz;ObpmruTeXdz}s)7?h!V{W=O^pflQQGyl}t^r8pj9HDEl+xv1Fgf(bgG-dW= z0O9tQtR8^YuT`PvC!glqwhRI7N_wK@R6~&mjuHW0xL3*tJx@ zvq5)ak|6hpMqg}fBHl3fjdvyWBin#FcFctNW6uv3JP6n*rmv)^s04gYL%qJOiZHED zU$jgG2AGxD%#WS?NkvtIIWF})ZYi82eXqE*foXt+`(q&x|$IGPT){aFN$DHf`kL-EM2!$$K~f`RWHZll8i7BWj)^ z!Gfenr{}3}`*oN8^q|W6Bf3Gr$>CCA6^9~(9wxL>X<^Z>C!HEWglv?;fpNcWq6ypf z&U4cEJ%t%NXU`f;tKPvj$S{T820Lh&V+x3roE)RdTs|<6+AiSWfm{z9m>FN|o&B== zxasrwSkEzu-02~h8i|8HSIxFCC$+KBBI-gS19~Wk-TgYoo-Ti!kQbZ@c1Boi=4b_< zw(Y@GL-!{iKRRbY){^e`CDyNzhp&MENyp_p`l}O1^QGlEmb=+tud_OnwWWzxhtWGs z>*v)2R*%y+^w?~s=Idtn`zRIs_4!KDjTSm&(=qTbE8lzIn9e@c#Rj?x3XLiHAFW2y z^+lB`hZf>qm=3~AHG(HRaL?dk&r8vZHU3>hjiuBCYO9U#E^v`|bL z{DMhynDfL$uA*!n-Zl*`DX3`C{8zQvpD4@@@1v(RlOQRs?C0heG2b7YkyT!8s2$;T zvbuq(y0P@>v>9tk*T_tU73wz4^OM@PmKTmlA(0QuzY?rVQ5ZI`HkQ?4oCc;v}^?L8!Ft8HOZS4i97PcAUl ziu%S@RzDKZA&G5n0C@^iI^9$q-cyC1llt2LYTKDd)sr_J}bKJIks z0_xuMA%lN=f7kBr3S%v9t@yBs$dcK``|+-kD~185m_`+#$xUx6>`P|#={4!0OQ1ys zpz6@-*0r0{;AC72@xN9T-3CyOk+BDh0=-RJt|YLCm5&f~q5_6V%5O2}l&kjFeFf%b ze3LReUi5OgdOy3F87H4Mc+XMAoOw^fZ z&Uc=|4p7ylgbivNLu^ANM)Cwi*htdI=S0jC^j~m9bQs^rY&0^&p3JWZO@W=h-F08 z9Xk_Lf+MN7`NJJ0G&II=?Tt(y>09Z}ce%fgj9&30a>$N19-r+d?EcE;7=O7v>vlOC zTn*4ZmcxBI%EQ5*|;1fsuNhKdPcI29J4V61qvZ}q_Ka0>~SeH$7wPj8wbE4wP zAV$H%cYgs@6gT6h-0Cd5PCiXr9RWKFHdCzSmTuH1e#PQ4hS-~+=gAsyG~iB4r`;mJ zt69)3prZ&~m_f-WmXw?XYICA5;GiB`IG}Fcvid>y+#04s?SFIk7PEw)7bp`g0c*42 z@jr(oQ-cw-g*?``{U@#6=@6lF#)D3^u+3@;o24hAw-%H;$^LVDk8LEN;6W;XI-%AR13%stPW zWWMN!#1m)Uh!7wW&I-PmPceVe4{j0O0;mNLnUC+O58T9$z5`AGPh~({6=ch8@RU~s zs2=?dOCUfv)nBO}D43BKPiAi0zaxpeS*;{BCikHYwXqSwcwjTps}J;A>b%VEh^nh~ zw-LiGxftC>>n=gzL9A#k)b6Z|FG%{vt1B{==r|+Q1ZBV~Xyx!E`u%&vvsO9qVp>%4 z`X`&u=aPf|-tYBZ_v81Sk9L3igg<+U46%i_FvcdcKgNv4;>nmscP+cVte%TlouGR0G)Ma?97%V8c{2h>B#&rJ_(wTL+Z*J)GNsZ7B)UtR5!NHk)qMY zb8PnnvVBw7&<T+-Rl}ndvAG7O?6Xh)c&vZ zRMQDbQl#1h-jU@@G!G}PIylnNc&4f-Sz@=o9qgSCI;5v~H|kH8r0T_DJ)c!tv)9XM zc4_=vc#RE5NMN~7Tj{B`KzR8!yW)Imw%cB_xd%opeM(2c8(|s)hMa&ci^O$AFQrGr z!?_6oDZeKY(k;FSdf6f#C&vz1BgdlSn3R=q3pkW=VKKs(3L?(2Nw{%vl!~%F#P3ue z1IY8llyqqc*@7pKlcB2XcB7ko#{w_>?Mnpkuw@VN5l84$NJ%bZ#YHywo88+fv^6Uq zJcq{zfvw9_u&tkLjqBQ*kHD(w+1>wX>)HOl6#M_Bw=4|*Q+mt6$ogM_E&Czt1n97=GXdbCs>MA~L^uzpJ zYLb{; zCRt> zna_2P$BIyJU|r0!D4Ff(y{O5-mz@$1J$HL;1Xtvuc`HHRp%Dm+NmqCHapFpqBVIte z9CeghUI?GY^WO5~?(K6dmM+g&XGW0`F4bb6=lb3boojqv2JH9(=jnx*mtgWms0Xh_ zSD|YX0lR&0X9V{mQ%DXvFi*;(05@7Jor_~}GeW<|L4Oa3OsGE9-9f0_2) z>uqYLtP@_seGZ-fo+Dt!5QSF}Rr~gI-aM`WHEZ?3q8ZJ{X;(q%_&E-0Bm&2Rqjt*E zux9cqv7$?ituludv=Nr$)G?uMAE1$%G_u(pi`?u8cSvC5Tv4`#?@dfXfuDS%MTHPdU$knYG`Bx|6~M%#hL5X^W1IX zEtlv<_Imy&)?y!qqZMw&6RIZ8=dD^SQ3af;hnCPw+P^!P#N@uTNw=#Q#;7OnGW91T zD<*C;5sFP!KXq1U`?fJK82a`skf^@vB>(Y)*{a}VQTy}K9f}F160E5f!}r>g(UB#Yhsb8J zq+z%s>@o|oRJ77p2$u7;J$x?H_DN91Ex+yb!J;5OhuBoNkX2#ncOUkUWnH>S`z%dy zcR6fb3~fS5@U5MatH$3!hP*Hj_0KS>???uZGWRy=YSFB!!BV;@t<<;0%~n!tU9yXK z9SvXqY2(NZ>6;+`Kpwin@#7BAR9^@vy+f0{GUE}QS9t{vJPzCS-fk|YS{v|);v;xC zD{c5{E83EQGy8MbQS(R5`FKTTMFrPfi(c0mbGU=7y2aKLt_~YD6*vso=C3OIcRMv{ zZ+!#UYhs|(EG^}emT1(USEU?nH5t^VKE2Shn@i_R&JmPfT{fT=04M)JTQ-Bi2w+}j zJgOg1;t60EbgbL0Nbm6bgxm@ep3x02Ym*`~0WZ1HCrLzOE%t`4nOS$Jiea3+w+O1= z!23KMr7(TrLcQO@McS2gnVKhI3Cv5N3aAS5&M#{idPq~38~{(Dk|oUKh@a8EYix3Y zFotxUb0U92d&i-yiM?GP7D9kN(5RVMcnU#__T5xi_@0WqA;%0)@`0!dNrbf{Ymu}c zVTX=gDpObS)VO3O594-5Qub-P>4zXT$e9Q76N=A?WF@t9T!Mf;B(WrX;hmOWb4dq| z+}8pW5|hOK7n-?-w5*PY3yGgGNi&wKPKg@F(#_jM{(%H_UIijcaGZ!w_|gKLgaYc~ z;}GKE0YubepP*n6P6+mqL?>*F`YlWVV5l>6?!d|{#|0!9X2Bq8biAP{K>O!MJV04u zdTk5Rh)j+?m6+@@ALh9ISf^v@DYzKo=Rf=!1+p6N*K_QOpzIp&vaLsOI6TM{XRe@# zgD?T~EWO>(Qz*_5dASD?lBe$YO80gGXY9#nI?v% zMw>tEn-Eh^z+?4C{-LJbl`^2JWK^<@2<>?Y`eTnJNiCu&L0sM@9>Px*5Rn(MDqouSNYrauIPu@5cZR&|AT(Gc-) z+6+-bsm7lq0VkgthlRk}mW-puqL9QV$>NfXv~E2HR}jE=HF`jRkjM@JvESs|%+9b_ zi^wG51!ge|(d1N=4URhO3bTmre--(iX5M$^$Yw2}wnk}|eUD8<2^l4segBvv8B9XJ zvOtJuhzsogIwpIJNdq=%{{`R+=oh$2LA?w<@x8=)p|l~!C!A~G$-fS8j3d=ZltdGD z$l8$FhH|583-6ZBcCXUUn9Dctt8+#^g|;Klp{%4_sZ0kxxhz{Ovs{8#{ZiSx0JBgv zm$eeJXgi;?Qts^0QQu*@?c$T*8~)=HG($ggm$WZLY=dL#J=eDD{@$x8y=0f-@Egr| z-NMMHz5+7IN+F{&asLZ_eDK>jZ2iGT#ULpPXm$qvicz79WrlGVlm|65RH~S$8uuCU z#zwcbwdN_%tb+lsf@=NKCy;-LP+CcdR*D#F{fU`TjFBNm!N4&eiQFB&Q?!HDI-U)7 z>d=vA;s^W8f2r8=o=V6vg_;KIf%r%~g5hH zYYzujC{Gq_!a-f?x@Z8$DU5sI2py$biu=c9utVIK8S}4HKC4nZ9C~`)Oc7H(+`k?w zg#xxgE7`y5M=@N|x^`WV9^JTZOtNxp9D8tVZJZ0qN*gMk_5Ifc4B1+VQB94f^?2qAr26xB%kI>``{QHxe*JKETmrxag(Y`h z=%hld+edcnh@n=gl9?(fUcm^rc==)}uQm`bKT0hTxQi8ZO%`SRP@lF7Y*drmf<~q~ ze6(`lNQCe9#qN1GE;aP9_&!S|hozcBk(U`wF8*@#U~BBe!W~pY2DW2rh@qAM_Tr|I zAXK5gN>%I;NRNgv$R9MxU92+<&`RGVua#^bi<_N(|D6s=r;FmH$n$}7Rs3nyzJlbL%3ftA-K$Eofnqfqnbd#zdc2{wHn1Qgsxf-e)@9r&*AYIm^}W$qCJF#3sr}>;<|#U zxBp(zjs>Mp*SKqDGIF8e3cU0!8#~i>CJQMwIk}a+Em%EE;zp0DXM-6)D6qRe3o-5A zwmF34YI()`rhNGVAwV1`NdGQU9fk--%;_CtCe<3U;*j(A>sY;C_v_nLU(5F*U$Mc% zShlOOQr-mgNf&qC9(2C2+hqKt)rryLSbLfq_+er{m`iq;;4H9g#X|F3g^)Ub7ERIN zNA=--ggI&_PU}tr&%PTp8A=P!sZm2Z7tc<8DUVVdI?eGk{0xiB=1*N5c!bJ+FweC` z3Y6hb9Ky6#0%+?-`cefQ3QP|iMr9)Z&D3LvKh$ug2Lj5Ll2I7L_w|4y3fwL2m~v8J zx@WmNZp%T1xix?M4mZ~6*m|k)3u|geB429!oR6xGfg?<>yuEIr-aqt?kb&l_>ig8l zS z6;Z&-5oMOrs!C&N6e3LyV9T_~Ddaj@Tu1Tj7HAMLDfI_@>JTs`8Z|PVC@$4pEI0in z^+?w|+ZK`?9B#lzug&MP3?Ecey{()w?}mSC#dt%9<3tSocqf8&E>o%FG%v|S25dw) zux5?Rk3MV)L3*WL**4T-G-@Pbkle?pn>dR(Frpp0f6Djt4N!R)eUO7c{xK=|MfG@Z zD-|tPxNW|9U0QhL<#W(TiEMd!Vzurc-?v!0fprWBvNuJOPlixzE;LWNMjn*LVrxT~ z5gv7K!t!~emndA-vZySSZwOrgdPDAkwmH|?66yOOa%&g_BPuetlRq4y82UGq9Xwua zPooXubQXi#dO(fOs`*vh>-vFjr=8|EtXH$y``Xh)zM?;3Nwrc#p_Hri@ubl{{wr-1H}?F?Bg&848sZtr*?4xN8)lH>C1_rN$VQz(0xL@RAj#0LCc`2ZEn%Ojp@Dlr?$At8i93p)nASDmchs^G&hUEQI&9zz z2G#FTs?^GLbt>OS11S0G_V4nQS&n;`!Q*5sUH|tHyct{>Hj@Kue54^{x@DaqtKo1|9tOlZ zuBTLd5t}QzovoRcL~oljB}00W;U+rpA3#^Jq}ebRPSxTD zP393I2_t0~A9NbrlbjoVhsnE5Q{V(&V7qm{3#~vhw!KVSf4h!gcH_r#j3L8NbaQ}Q z3}}Ak|`11l{ z9TaUyZ)p28d4)0ADUl+5$VNr<7Ds(2oliwbZ{Vv26jKAP}6 zi%_#DFdh{G3-#_C1B;i?f6`$IA>ObqYKf5{N1EpP)<%~dTXK8GL>xJ5 zhltmft+%eMG5l|Wj7)!RbcUJ+^(#0{X`dk;s8umI-Gv}%4+b=H4Qp`d#WGAScqT1| zAPk`pNsvJ7Q@#*MHzr4@IQ{Lbjqe$$*9A9&_GESYJy=D0GD@>^qSsR_jkNJn@Ni+o5 zba2-FEJI{NZ&gh@m2(TRFicc&Q_(@dUK$-85(p-!^r*4SEYm|_bjISe!tQZ|xrOiE z#9G5`KGv>|AEWoME*tcjHg^*@U*OARy@c9{+%fV6Jh{=yyCXS=^MHls!Ejf=(KW|C z3}JEO(F;se!?^W9fD$!jio)T=F=q?K)v#jg%Q(fBXq&Q`9Ei_Kn(LX4k>n zcz@4vz#@fpk}r=#tQ)(8eZj=`$}$%T>HS%NbwAAdDhYiny@ncR%;Q62%wZ@KTcB~oeeLwEv+wIEg3eyf^pP#J&TdaP$geN1e`-H02eK% zZNdP??F{^vK^gWoMqKXzx}GnP1;*=vle-}+>!9*cirt{3TkVf%0B*-Dn@fNsChKB= z!kfQ(+?<7O<~3rD(%%Z1)tBYJwx=%TCO(f;J{{iC^?KspKYZW8-*K--2rpO1z$x2V zwvmI>_AX}c@O3d%^r(7i^y29z%tXE%OPd=h7D~Yjhy73gz5#|oGqO-D73~PmZ?`B# z2fOrow=mGBW(xEO1MUifjLG(w3ObrL8#ITX5Wvk7$6VDs;v)7x^0{)JA;@r>Z`anPG| z;9r{!=fQNwTL%`75c8vc`4guMV?z;VK52IY=*BPmXNlv*GIAAU11mA~lh?*N7#Ch`zrTPlKA)qcuOhFT z%kGR>thcaAi>*oKY);}YXSoZOO1tax1q(F4S*bs2X&;&}@{Nc(!5w6MT@<+}w!r4K zKKvC-^+kbXHZZ%0Z9yduzwCL4QSutCKD_uGS^zF$TK-Y5PO6rwYM0Vto7dh&vmGya zuAiUZ1@!D6on5#42Wr2O$XLCp4aCH{I#+WQ3CaF(n@(9YK33JO%;7B{se^BxM8U{aYC+> z`G3pc%iuN9T5<}I&Wj;ho5yPBu{R%*vvPzT|II9wjSVtoUzV}6#+2iu>}`QyhGi7{ zfKdW$w_=`n^e6z45f(Nt)5z=JQOpSA4qxC;vtl}u%wscXN3sG>o_agA2<1`*QG(BJ zpHD0aHthGFH+>*^#S|}K2%9-aYL$O@$|{9dOc7c`T z2IXSg&lmmUwZFCS4ms`>)2wO6Vw=|YsANSw0<`TrH>ibp`M5i>HU6(7mhR*;tIubcG#}h z>$Ro?P}9LRh+xXQvEJ9{F!aN-M6ics*WWR}>V2czi0#KVLpN@n=`= zr3V$?$46i@u~uz2+HNp$f?(y5TF_w!#eVOfuY$~mE6M-ldR=Z4B%AIiz&V;^%bl zR2aeESbsRZr%c1!%_{+`X*#$~8KK@#`@OD?kIKP$(2U6V^>}@!n1wA35SGk2#g9og zAXchc zvUYt?)qD(Ay-i%zqpk_$noE?*p}=8;;UlAq%~Vbj_fkb9S4$(=mw-zO1ZQX41@f#9aupvxdLQ$tk zbneg^_&b_#PzqD-?r|&i@b_VNr?W%fG}c*9c3lTu4?meW^Fl3$&t>)lnF+7T-TdU0 zZ^kojJQs&(W^B_{`b=wusmIslQA%r7wHCG!r4+90jPRz*YnOT@Qyh!w_7CN$ttbDr zkKXSS!Pq!_3KRCzR!moqe77os@>op+m*5jsWBPdVlqicJ7505JZcdlaDzcOb6h$3n z+hLGtgsSuxpN=_mMPnblxyyUKmVt^e1(BdoO*$w5^&9^6{G728eff{ z?8;rB7KVw{nWEJ?ep*VV=sUfi7}o=U++aYd=n^;)Nw;S8JOs`lRMa@k&yG0?NXF`# zxlkVyDbPujKU6XJdc0ciQ5kiF(dY+Ny((+mX zy3~>nAq3P4YLyeVixp9#@~VXjHg7y8*A*}`HJBRBDh{z)>ror(N>qdpTsM=oq@2l zVy?X3Pc=Gzo*e-XV}7Z-HG@mJ{kX%EX2+R!K5zY-r*w$ax8Pc=QX0+JCU4sLSfQsO z;*I(-NSLsU7}o6x{bh_0vP;(~>9cL9+^*K@!wW${EpCQD_Zve?ZjMVs5?0tLoFICK zJhy(2+s)a}OCuvHn=KlVl2l^j!0kyN5r*$N?_LK@=aYYBy?WRkj-#3I5p)5IEudavC8SHSa*7Sak16Ra}z+&lKUv=Ag)pR+$Z?#KN6VT4_d+$`%|KQslKrgq? zf;@%AfO1Bc{hh5)DqpgMY7h;AE4PU-fe__7dHSO_zEODPdZNGu^}*4ggobaSZi@(Z zV>)8ahV{qRYJ2o3x5vtqV5QUwP>Ojiz&1cVx7m5gv-eLYKnF{J6;m8_l%KugOB~myfpn_9th#QdcA9kd67s`fA6@INk0k z@2Q~^I@NkYFN4R}eju->+#?n!I^IT4iECYZ4l7|=qnavuLYj#Xu6fveJn@OQFaTWO zUO*ru`y8nX?8u1tmQ=7lEhC_t^#O0lvUCcPlyGL8=P0$+dc1ll=qPn`X5s$Pg-lzx znr7x*QFo2=ADq-s=+<{5spfl{aR5Dxrdz3^wZz(~TFL~a8q`pEo$(TuK6JlR<6-TU z0{}IT$C7y`zqTaDLIbbhp_k_I0FtwGC}Y%LZ;Udu2@KVQxq8R&=rmLz>Z zDHSotbFjtmK9EDX2qKVZ%-ejs+@l(RsJB6zTZ;C~_q)}$@*d|P6Bh}+s3%@*+FY~7 zL*0?{aaZ!7%7L~*L17j3knWxm)E4ROIutlE(r0MbjZ0Xoq%w4h&?>||3+OSAcr{Xk zek|fXZSWrTHDW*&?l@+27qe1XeR^lWfxV|xx69#gN9;jFli0$AAzn>Lv&sQ_cY!&c z{or?3-MS(wT+F@!BYoYiYmDejTzi##=%}a7>MXAL(g+G1&|kTWd-@&zaVWFeFHlgjObRsQ#&@4-}p@Kz0DexEJcC4)Z!s7d0m(gif&IVP8fPfcN0E%E9OY=;nvgA zBJexjQihoTdT}&YjyNmyR5&sU z6VEaM5g|DUIU2*#Q&dJszFLl5U5>e7v2^dDE^jpmv;}(%C@nSX>jO_2tp3ddPXXUG zJk&f!7c4Oys!JogRY5%fvQw60N!SIZWR-9)av=xV>a?>>I<08g{pkg9M|BGQ+M#$` zB)+W1W5x4GcQIEuonKN{20G<8g~9^$VR;iv5~vm`PQtEMtJ>vchMXC+R~_U)n{j7H zALO83(<|%?xVJZLS{={M0h@1pKn0%>c7|eSkL~uCWoWkV$p2x@SWQPGL(4u`oTrra zZ{*7u&4S;t>wB|g4oQ!gqCb^S<#6)*>_t8MXhAFPMKk{adOvq6L%V67;#QVoDYQ4` zjxebq;v3GtMp^#yxKbUg`V+>tw(Tc`i!&JgU5Cd#)17Ye|Y6N4jz)Q1Qw zh((HAd_J3c{S6QDK%)Cq8wJ|!{%u_QZ4SEo$bA96$!sO~|8(>RqBBIqD83lHb#BhSp%Lc9$+hf<_^@I4|rBj}>0A zry1!PD3Tp^1A_0w*0crvBpqx;n-Nta&;(6uBBaOiG#$JcLIx1MI1fyp7*!FVioV8yE(t~jLCO;(Co$ni za?*chL4RZGe+YC@(%*GH(JUDtx3UTC@&#|aN%Fv#+{^2Yt$gFHmJThJByzH75|6ls z5RZ7T4Z>4JPv&Tz&(=V{ij0|PNb~4kI4MYL6VJVfHa>3?F9g*U4?1UdpD{^rL1ENI zpE&}?8RQ#N^5`f;+&eK`z*bR}xvF9Mx-lWWCU5$LH31V!1dM9IZk7iV$_hNJfRSuK zN0k|RQg}Mo8pc4>)fc1T4Zydd%*n{xa|f`is(7Y`8vAl+;yWwu_#9n!=QR0MR%Phy zfjm-KG#twv$T$f7Jx)CNU1MK9rw0o^a!1BBkz{FgcsRN;lZ7f5lYZaKbjXD-$r8+- z_Y1tijZg9)NFoc=lT>EUpQp}^kw$g(1M^%S| zy+-EGi9^AkRhe7ic!Zn3&oPPV!(`>3&^#PBndRe6A5^S*76$EYu!Ha}MdXCp>}V`3 zEelc{T`9Pbsf#ThHs9CGb~ZD_2Tpk6?o&{U%04oO@~Xy?KBVLcFX19d>*TKDtG{0p zVjIQfJyL`FJ+P?@iT8pRV@LRD-gAG9p-?D{HiD3ja7h*sd+w&3Ri(%Af~h2cI0F#U z2_M3!(&0V9NTJII!zm#&Rycq6<)(#rG9->X%SiHt42xaDJH>nE%_51`Qu)lx5UjJ5w{a$Ke~nzOe|V%Q$9d zFQ-SOMkY%REJ5EJ^|Zi zRBS3&cdxlj0q0NwF+S8jzii@w8~`Bk^SeEsJ7_B>xVmbA)OCe(b56+g3iqe8k11}2 zzXMG{5;|P40ZV9wJX{|?UZy|v68|ItW7r*btbpzE|I~K_gqNWOUixHiK6!j`_^12* zlZEfA?K*t5`pE#S7)Si7s+V{1FoW^9lYL9#|-KJ*5tY$+G^k)FBW5T9s(9a5Mn*icfC{3Rc# zBwi+&t&4l|2*_gpbgPoepX+A~fVtwZ=58^*3TM3_z!l?(0bxfYMCwm(W^iP5WXzy7 zeTuk)+6sv;8APkjLaptXiqWXGDv*am%33M;>9q7JjVz3NYnw^6U+2>e^k94TO4o3(@Xl3wd-j( ze~jyhbPbwMV6vOu|JzqPi>p1>fKCmVb_?4Zd~c>9icEkbPt0}?m>U!hndaoT$jM(ID38BAMZ(QH+WH`Jr!F^>5GD{D_=>Kl{2 zqTM;_11sxG^9Ey7#{(mTrw%JKwkzD@<^bJCgyq+0!R;)AP~(+xQz%|dti|ZY?huM6 za+$rFMpyIJq4UDh>i_!5-6j&l)5kNz6@^tz#_@_>cO?bb(9jRP&HBEwt}9zpQBQV7 z#WN{(b>WobXpI(_|j#^nWYDh zl#r;3(+wzH5bm50A@JlxJs1UYEP5a#iZw|ISgq0VD#M!KK@~LR0(NugF(9fF2^w&r zNXS7pa5QYn?F_=~4_9#1DsG-->zmS0JoQRyR#azA7sa*{#TAN;@Q7b1lP%tr(~PD{ z&nA|A4f+ms1FYE8gE4hL)Cze4mTt-^`o+!gNi>~*9d%1Eah9ds7-aO7nNDt!9c-vA zw*@MsXzh}4)$eh6vDCvmt!T9{)}>3mEt|*t%hAdSCJWak(^NbTvBIG&)JdMOZv8() z+d-x?=#LlA?E52-i!@3kK^a309B>*2u|KUXW%~h;&^9b$ZG$=4R3_pSyz5b&f*Ts= z22Y1UwUkO|$)*!F%^S2CTRLcHM>8~APmr7n$BR*NcNpk0j^}Eq#}S`WM3nUFk1Ssu z#v)-tP9#={J?P=NO{UyMDQ_B>#pbr#A|iCHh;`j6Nm`dhQQ>Rq#9Y}t)>;OkrZF2V zGY1Q=lR4c)s|{u#lfY-Yzi=H{aOit+JM5p|`Z z%EYWpXxc*SBeawWTSHKVD`{Za#2gtDhOW{%2+I1KI@Z^ZE^LqJJb_Lg-=y39u%5Um?u!11<{lx3hE-;+v7mvC$WPZt2@OTM?S}OR;sOQ%H;*9E+iS5?p9Qh{tsjC z7$a)1bz$~t+uf&a+qP}nwr$(CZQHhO+s2&9Bs1Tg+E+t^KS7aZ_h8 z{OsoEn?n`QgLa01j~7POIOvSD1Lq=%jSM0 ztU(ZF|MDOR=ipBY(%3oVGg#sSY*k_OwUr8^G%n#8Me6-R%#i_A7>IS`q9n2s#)$1# z;PvHj31$yCRk8dD!->Mx1kaQU`}GmQhsjsUgaN3N%tEqjW=ma`J7b9eJIuLdlm@_C zB_$YXSa?*h6bLuTHo2zxYeTiI=zvl|d4mw$@o5sf;F0D@7u?#*gGk1Rp=nLr?2%U) zxBN7drtr>i`kHGCg0B6FZ7_8b7N%0G_#Z)96mYuAfv0bc0XA zc-dm4aS}(5?wh&qFjHQ>b2?w*OFeKfH1sJtzzv=_U*2|!X?Wd__uraBSOJx)*Xn@o|@4ic+Q?!SmX zNptq*opiqs%pGuQprrMiMU=ofLzJ|8hy0}QNK(1fagKoQ(s;CxMY?#e5JlQ}kH7(L z4SaJY#$6idrJLLq+idhh*GS)wyQpK6faf@-)_=pCvu3k1;6hFsKnNg)sNxm@+4HC2 z;l(ofx-u}72~Mcs2Ol;^%mzbXC|S&!=tU++FM9yGt$~pLHdfRp=x7LDSry$Lo%1vS2rfay(SVNl-1e5 z=yiGen?>JI2G-(|$RwWl)GMR)r_)nrfk=8`HCg1v|3&LWhlp7YY?3e5R@P)p0Je>k zE&F8`il-$%=bN%HQt$`;Ec_n0CUlxUCy>03W#o|#4t2y|+A-Ih6*Cg~}jy z9qe)R???-D{PJ3w38e;eL5+Ol6aK2-igg``ce*lT0b&s$hv+0drsI@|4ZTKlfe-eF zq+G<8$dg4j-J#afkYz`0OlqW-G!{9Kmek@5@gz>N;KwG7vt< z9s!i0A%r|0x=;hSD8eWvek?LUPAuUCKR&3IuKXn&e6~Xvv<`l^D!3N@eR68JQ@U1_ z#9v;O#o^wHU1VN`>w}2>>%lDZHV3z1yH&f}y12WY_RC@3uF8lK*YJlL4nZ$dF%((2 zY-|jigXH`!kc+qsf}djnp)S51SMRg0#!K1uy^p=`S8ZRXfJ-i+q1|n#73Y+@n%&)@ zPM=9pp~cIC%d8dhUWxjOQrU!4u*jiY<>GK&Z+z`2EK=qD7CXGDP{Ke7A}(fC6tD;| z3NQ_@7C0=lGilJ*}uHg*lrQfI2?{)m0WAiag!Wt9(P0iWBl82FSDqXFNrHS4h5l4 zWsO7L+pA$EHuavKuBxs@nqxbKSNnjTVw$RXk(=AXpq(>L_Q{;8S618OzOvC_U^k?% z+nIzdpOM16IbxQQ@oNP$e@zpRSDW3*X#{a@7Y@rkoXK9PERW(oGm&$IwF!P6V8UlBI}-SvuGQui}Q0Wkg6*N^MGWB$7`mnOiVBr_W>%kO3_5*{~Lsef$=~45$!l>iy=Db;8&jDl*Qpaw)GG`arChQUZ(3mSeoN#7@K4>1g*7K z=p}OgFmTQ@ToNy_h zG}xvlKUlh=LS>OEtxP0pTLmm)8?)7i!Di z^3uhSp03B_?wg`QjY#$#4he{qU=BFAs*(666ur7LKn^hfZO54Z$BzBqb3lv?Ol%H{w)at3#dFV#K#7@Gz{2@}? zW5WZn1q80(!Q*VbfaX4K1|ho?R+)^h*_DQhX2rM0xX51GF4dtL4^UxE7on->D_<4XGiM( zxcapTs&UV4EX;kKCiF7te|uQXS_=p8(|uv+IZ>{RHqodz+uUxD!K~N{7N1b*tSs5R zt(>+H@FvyHXf4#$NGFTq0FM;R|v8H%ZHHY8UHIO_B8t}f}&~-vjRggQ+ln?5)+5@Z6MX>2?R-)~^r&&VLa!|P+` zQD+&H&Zv&k1$Y3kKJ=>Kp^!%BzmrB-{sXp&QUQ?lzz#by2;2tBB?p--2lb~76;%MU zD%3Gwu1K_Fp%C0ti7$Gg@DFM~avyq(T5uI>jz+Y(FIIwWg^sOq2f}0TO}sc!g``; zlueKEwQ?bHIz#S65A?Yqxq3E5S;0mn=D}O?mi24@rzQn*6)KgCJTZOpd*K8PeR8Uz z3c=R7%ol@I>u*pqXb$IT1IIzE-XWH~HJX*hW#>rb)1;B`;e|GsT%x@x%_64yH9~gs z)rX5nhY8wnq6CUzJV@p(Rq%?wXrO#`o^{y~y)l^mFF75uB zkRLhGLNc_W8lCK#%IQEm!DL+Zr_h|s7V(`;zy$m?2@((j#aES7$rAL&Z^Xm{6b;O{ z0AG*-?}BL@*LvAyT}#j)kbeH4YZpjC*IrDFdIIOEyU&O!9JG(78ni88|q zqM95b8Z@wQ5oVhY7`~}P#YrrYI6_^W{1;|Iw;eGUB1~fSyX#j5sq`{qv*2XjAWIcZ z?)iA-Sm1~;9bNz*FxU&mauoHu!Mro;a(;v}WJi(zAWrvTIeJI7(w2Y>@bG52j91{z zKI7U^Ag+Q#201%Z&{*^ELV?s&DpBOdVb%%iR9$A;6)C3r(Yok}=p^ZpL|fqy>}HlD&aAq3n^y^( zeyFfvKPdptoI++>qAbJgfDyGzACs0t59rT7;RwP5FiF^{2k$tT^R`fp{9s8;ICY_l9vFes0zz~#b8>Rtg3@Rub^L)p>PL!V$dkYq|I&o55P%FS@!BiD zoNSPBK#sxDAWsl9mv!Vjp{ar(uGYAe^7SNiO0OO4iV=%_>MuTZ9M9z%=ZX;~Ej!2@ z=?DJ7n-n0*pgKuM)|1ru{x*fxtJ3WysGvHj)^1Awb-W~+5TdfaLA3l*Oxi({-LS?i zqasX7eApOxVuH2~?j~4gC|s3pSz7wcW!}4KD_-&S!+tyH$KInmjt+n{7jP9f6E-|-IY7uLFVw;{yM_ckGXSE@0R0UU8Y(v< zv8SLIxGW;8FP4iyg(C0vTYwsH%2`-GD;Scna|7Gxksw$CGWoo2BML^SUGIQCEh`2@ zQ|f^3l~tAD#0U#OlRHEgiRJ9Pu00x$=YpB#VsiZ!@_~KqjaO1|71j~KAteoEU`$B& zqMz-dqV3-rWw4^z9PgP)Z~JU}ZTn-xcdVpc-J$r*QhR(!XM3`%Bw87{M14WJM9RF; zOBnfk$bR}O_5ypl&y^MWX!m1#505EsV*0IgEw07hoON%3yDGch0PO(XLN1B-&7<0Ik2_t zVKS;_zFAUrsbj6rx*Na-WE%(d(y#(7z&d1^I z?}Mro#bOL6ZG5kY_2U>hNv^uM>$gr7#lyqZ1y_6)j* zSq?p~uRw`56Z)fDGe>e;T7);Pw9Et~RvE$QjnOS$#YmR8Bx^!^n0Of`Jv|;6^N>IS zCrd^oak2lJ8tS}$wA`M63Hl5hUvYRgO86vELlt52sXB``i`OS$W>>GTZF^dtMEWxe zJGrUcRvPh;`ajthLlkeAqjcn?KvsTaZ;Hm8CZaP;2 z8-$?J(b{@NHBQr=6hJb%X(0$w@+jscAXg zrF)>4j!)cCT>6ky0$7emwh{NkOC{J$qvR2k!zOR#$B`mXhN;-Gt?%c4FpC9a(y(@D zLqY#O%j3oZz${XTd@?9nicm7>SlkdB;Ss4(o*spgwP|wbGM&g_nUeeD<_hBCEgAC0H7v@A9yE3I?aIq52N^u&O242q395Ad+LQERNw0% z8Y5AMvwT#z@+A}1+453E4PYvL4hIP3LzhN9Ap?HFe3;D`*GHSkH4~P1+L4!IY0A2I z!BOI;ZQJ??T!#|qZg7LYi}G$T$Tg<3(FfVloE zp@ABr{qae<*4D(J0}HKIGh8tif$d#k&Bia;>qRInTvzN=sh3mQbe@)?peZ{-_wb*9 z&A6(@x|I0hKTx9t9aZNHT=D?)j%^eQj&t@7^I_$%qB1NW(J0uX_%SE*g;n>3XfLqu zi*wF!$y{E0`-M=g*E-Tnz1AN8{&oYR+^oC|9aj4@AnZk_*|Uivx7FL;ipLx1&Yr5= zzrluI+A&Qx&Fza3wJ)r-qSZNqlDG;hVawRUQ5ITQ#eZUiz3uen68DVgeafzn7QKfE zbWKfnv58wN5?pUf9616CW%tZrYUJe*m?gdA3xXW^oYdxrI?{w5-s}6TCts_-4|Psp zP9pt50!`D9UtlqOBaR8DR^nvCaf9R!z>-I(Fxi+RoF_zW1bc0TwgR@WoDlygY@d+H zfKhah01|fnp*xe>@teWmhszCM8x{brcQ|fWqn9nZCnnuYn>0D5fHGi`RV8Y)pLwaD z7slk>uEIXfMH2mDDvKgPDPhtfjpg03TQj8+5M;cPl8-6u0@f6XM}|ldX9Xj!(e{wzO=rz zR)kGdx4x-FQfqe7bK3($vm+c>>rMN!CjQ&Sg)vlSjurFl>+SKh?s&epWlHzMlKA^+ zZG&md1n#v?$A|vG6?@OMS?PEvG#coy$Zrnb=Y zSal}D3Uf1er`@B4? xbT9k8q{4TAW#uK#`y?2r4X)*;3Vi(-L{=~QmD7)v6V+W_ zbDx++yjmnH{HGymxataIKFPa$CLLz%Y(xa6`g_~fs`YY{*ki}-?oYMh4y`J!&fLS2 zK+VsYx8?X(Zx;9Z&d0*fZrsTskoYW;{cD4A?06{-C(=p;chQs&Q?v%5VYh!gA%C@u zk{z8+$l!1pN(iA9^bAc!=v$_k`etVnlG zpD#kV7;R!U%9%8bc;i!- zwAJc9?g$^i9(r+q^*#lYA5H%%dB1BJ59_T*V|&|D_uTtCV-IQQGJ8w=_jWiuGiTY# z4=nA`&X_q+jIJ})uViw3=y)zipz zI+{FBp}X!yq(|LbVtF_qa^s>ER&)57MWRp}G6$Jn72HJf&jnd1P$!q+PU>h4SmYS* zY#VQ(yA>?%ECf=nn*AMJFF561>@wH%x^SM#cRzHget-MJp3JJc``P#N&f978DXpj( zJMKapvq!1!j8UjdHH5QLj?P`L_vS?o#VRm=WI%4T544b;^Dh$Bwew5Z+^~@yS3FHk zAy<{&Uu4fK%OBem9tz^dj7LSX!0$}C4Nd+zzc@5LEv%}5W3Wsd9qBXUil}_n*Zv=7 zNTFr5l^}au5Apb^-$vw>(H-43rMSN_8{tNZ!@>04Ys{|zdpWv|=LR2zdkuaht{23c z0>;pPyka%o;7M;)UBMmc7AA@gKd$CZ=fFW2Sz*peXpgC#KyO5M2su2JgYLUCN^#N> zS1tDKCw~)z`LdjSl2ypk1jlw`&3e1XHFaH)#c+1xNEq3|_PAq_H&u~s7t>PHR%^M( zXEJ(N5-e~kf2Fb{rIw>vaHT(PT7Fl^;<2uS18RBsiIC;jKShbVsja<;!OEdR;ZD!) zaOTaL%+!j1xWjk7(5x=MxYOHXQco^i%J(3lEge4a5}S~5Xr8THrq9`xoFVZp1Rf%a z=(FL@%7_K~Tkq5Lwfk)+hBs0AIx>aJ`FfB$pv)q_Wsw@Grpr95`Q(%N^BCYV%@iC*Td_DX?sM8v+zXa2CL0@HQY zu=VEr<79zmS?gA;Dpj55^C%r@q4t=Y*4H;x;A>sQn76gv(BNJrFSdoOpAOI$%^PvO zAfzvMg3kA$ZRE&k)<^GpOc?U2#~rGTz20@Wiqp9eD>zJ7Gg0Qcvfn!o?L9XClxmx7 z#h~6D2o*ubSw8ahgWovF<+xhTd71#5@ ze=D5Y@>EB)!D@c%p6K?cl-sigV^=F(S6$0Pv+gpyK@%yvkqfC3vSi9i!1_YaH2qb1 zm@c3OHgLYW@hn$VimO?1-Hw<`C6Ny2QAQfaucpXT~!lR;OBkrcF@9aeW zIx`ycb(m*!Crvbp@Q9W(I#DI|EQ+~STTyLtDOJUXq0atpUi}=YH1FxSO>y?ntBsUk z#lui3fM>)&s45zvJ-!g*SVoZkX7;N1n|)SDX3Kc%eAn~v>|~Vpy5#}`PHVG%up{sh zCIz&irTWth&iz;57xOxLJ6kc8Ay(lE)7~0gUWaLfk$ME*sVATca0_3nYSO5wEy^7& zQl|B_4e2d16c~veAjwSt*x_A=iGqCHy={Sh0{R-%0w1 zd-7|oyZ#+)QqOL$(pes1<5>vk8rFU?o6=iNkA(A4jOZ5tO-@B%^x&H z2nkVhlK3t{UY~%j-{YO{qN}zn-Z??ov1BP&!-Rj1;J{v7FR*v%k!Ld{EB|niS-Ct86+QM~X3=i^6*I&iJdRe+xHaC5fz4WAUjWQj;p`s7t~)XCz-WK10Xj21 zBYkQS-XjLT7JEtbyz=)@o}=SN@Aj}N9IKx+gL`@HC(m6W-`a6+6qX01XmVzrN0B~3 zr;gzGsxAIKu=>Qpft6nYbbETo&J4!>!~{sgpio|C=ErXWC9ZoW&x*WIni+8jvcy0* zD{vI%uk`=q3h<;nzCY5XFSNUC@H$DDJ083d=jq>scvxx9;P{CwBdAUHAYB;31(E!E zkA1BowqDuRpZwl38Aa|R%M7|fm+muVg)G`($PAjZ!Ib`14;k%sN6%rBIQgTP_(P)6 z@qteDTbff@MSq#-!aO$xrJDMo*fA-PxaDvEC1=bF1S2#?ortq+oAL)}k8gmq{VF6d z#*qYA%!kp?BVXbJ>QNQoNE)D^q74b23*yp{+mN859aQ;4LiS4<=Wd^5XP;#^+-4cK zQ1oP`!UjI3`Zg{Ph&*6HMLi-PKtTE!@q!yeEAj#8rLy1nXY;Jh#H!E`7^`0D9XA9; zqE@8{@(!3seJs^MHa3Zb4?{t+?v>%H7402dF6bDAEu#k$`3KqmKJV*R_zctQWbya- zP2XX+u=z8H!#}D*@}=H+yfDm1slTjLw0>~{dmQDs=E%WTqJeNzF7*IIG1Ux`xUyZ2 zVKyXTQbK#Yc+JEC{Zc8Y`cR84gV>|R&pX3dvMYRC*DaiFBbjT#xU#W>%Gq8>*VOL( z^6BH;gGBu|)Yehd1f+EK{_o|?F-CyWLWyYJ$e8C&9-G^VEIq#Si+=DARWB$t51!@_G>q+7d3ici-?y8it0@&xcAY))h}|mS%BSS& zo{AMmPsS54(7705d36Se?%nfZ#@cNFDv`~O_@3IWu9qC%;ZrNW;<2oSF!=$a|C2kW z8Wu5Bn}E`+YYeRMb9p=Nd_L@IDxdA{oKPelu7rRc=N6M>Uz9{fIw97MZ=8d;EH;X9 z?gg2I-EzdKm-9K^Njyr(A}cq-PRur+ekA?cBrG!Q5gt4o@es$bDG#r3@=gGeOHDjG z8wngatF~oTCN`n%F)MLCU<-ZdGbOfF^?caR>F)@EB#(i!Iub?FHt+~#1yq*#-|E5s z-z12CjxnbHU4md`W&2MQS+WO&my+;;+jHm1)D~m9k$?$_AR^u<5jrBUKbHVQh^Ii9 z5h5N0FgR75SpilgJS_V_xsVnth%H|dL>Tb#!`oLJ$nd2juYIucs;#yha;@@Mrtfp6 zxR{!=?=S25>h`ks^0M;3mG}n`z{3m_731p%!VuNh{gW2F-Je)rtDM!;evps~px&_8 zV`D1=lqS48<{M;fm;HK&WK~N4MhIXe;P@RKhVhi9+94`nEkF2s{%QKWSCg?vj-5dmY*| zCm-z3ixxW{U*D$jI0u90?aWXZZLw{N0OP}JuG5w2oZRy)cQ9A0`(N2G&(YEg1Y|&B z$7gPX+l!bozO6n;FP=bmk?6)9v7wkjSu zc-^V`kmmSQN`gpKfi7B{ea-f@;)VMR?BKNsC|~hK^qTRZ)pq{BP_O;H2ww0neYkht zz`LAee(j)e41)SNkI0(9miD2`Q)a-uA(pYhq~gR<{fg{R?EqHG&w0rMF+t0BqE_3B z-a)!Pg)mI}xABL~br9_7Ag=txQL(VNMrF;`df9E6r~7r#nycZISH_rWhEWZMm|T9j z^l#3N3$gpO`Utv1QGcx8EPrHKdjj3*FiHY&f9^LIq8?mP zpI8wGSJN)@4z2Q1b_A=1aa$0fvBk}#p$2xvmKDfn<{epn$bayDF{pwl^wCwpP;X`% zhPz3rhq-n5I^7_SK@YH#QTiVmAc_wq0S`xF(77#+!VWmUgo6j6Lc-q#L!o=T=lV85 zkB&`D-5D7dK8s3-USEjXvt1(p!PG3kwJ$XaU(;(m8JQVJ}N;+xEu z2Dt}ID;XE^rK|f(KsEDuaza=ZOv&OgrE&}St)a;b&l=hm3oz5jaKjAqNi6?;NP3YaHdl-+AzMs>6kLEMjn##SDK^qwC(3#16(b*qGmYYW<{Kq-4C?LI{5?mn}#J`dQJFu8_ct!M4Avy z_7F){O4>y=CSu?lw;va7jk{0cBruu-5S%b7uFSHp3Pm25paMm1 zgDwuyq+3&#!J1>oTnB%4Mvq#qWAFE@o=ChN6u| zpQKbaoGo}(V#gQ$!rr9@DzCm#KHoXPy~xckn@vdsI&r>J=4M1L8jL^5RZ$7S?Xevc zYyij#>*`WQC-}o8>bf6t6ZfgTeV`d4>IB=Vk(47}Or6w5Dght&h=89*LbYS!G}hyX zV+Qx3llmvN$tzEDLnt2Sq=P>x%v8uavb4#ojtld9+&f0ti5e-2ppXRFsHo7A((Eyg znb?{@T~R~cXUWffAp_zV41EB)mIl1#d8GcKkOmrq;s1)|_==(w@5mBLXAHbTHF#7CQ#K~VOiLl0 zTxM*5CW@J#7YObS;mCsGFQ|bih-DqdtOMGbc*2r=7B*!zf^HBr$ZX7-N>fS3TLdDM zxZ5W8$9qoe%DK!6no_t%!-6a_(3yIf-(#&Wq@te}ksv3(jAT~MNN6r(Dd!vnKf2U! z;E|k*7w|8cmOqJv74Uqf{Hs5FKB}Dh%?ROngzw_K!CQm{MVL(S@ZBpk#smGZVIMef zqk2ZVTL%x}-J|v_9DO466kkb#;!&w4uM`1ei24AQY0t+iT;|dt<8{hxc+D)xyJK|s z$n<{9WBAwh7dk&76{-$$4F$uUVvQTWy>xo9R{j@XvEp_yWOjeKu4tg89*L-+K6xEn=XJlV0@^5FZhlAq&popj~hI4{SMoGZHaZWx!jetjB5F zY`(Pe;3WHzEte9H2N6uyfRA%)F}44kRA~Dd)Zk0B12lO$x+4)WAEFYh zI)9It4TYI;m}9^?(As3edv%o$q_T|KC_49SMT1*_hIVzIuE;kcYq}j~$xh0?#_8-mA z*JoSn#*m{kPep&eci#5=Vhr&5IvWih%JSA3zt*Ufe=$4;J#{q&N)aNB87bg%<8wnIH#&c)P$@Y3Wh!^~yGGkw>hRilo`>6GPj(J) zHTRHF6mIN$C__t5ICW8a_>g%P3gRa)!I?+IoL@3lSFO@nK@+Sf4pmc3(nvv@g(o0m z)7b;&df%FnAnq+p06^t#*qI)YYIuMk7Pr36oLu;BXcs=y(Iv*j?&rL9u_0)MOLpr# zJMcr`lOuz$!x}t=dLB^lM-fVFR?~Y%Gnt2#r%H@}fv=rioz|LaAF3c&A$e)Ulx;+r zx;`B{+$;tw25ZT8XO4HUA@CGF`IWhMi6M(iP#C_S1$oxuZVlfY#@>5#OF@!uF^K7N z?59G+TQ2gq`{TuID8wP_=6!^gw+Yb63Uf_bJ^J8ARyX(TS)W^fTwRUW)FKf34TGGW z{fXojqW_GwFUF%YkV;_b6sts;=x7(&dSk;^6LGY#t-N=`v)L29l<2-$OnyrCJv!g; zk#B5X_JvF}sV_BWhhZHRP!0)-Y}86nq=yWNGV5?A@#y&A4P?B#YWyaD-5HHT==^O4 z;(PXXe?z%XGCn$wH^@ZKnZJ8uvtn?tQqTnSmhwxWe%G_7rV zRgz2ZM+y-IdUp(9Y1c_`8lH*&{ZyM6mzP1nC0Gf|&#n(TbHd|7?7O zRM{DHJrpi+@^T#Peu~vNF1%LX2vTvmq5`01^=MR0hZ#ABATp<@WrM?!p-!mVvTEcY zed|fwZRwphhR*XHj^}!*hP$WCZw{Uc8*JZ$onhgA58*(4mBE4a&(?%-F4xb95r|`v zh0kLaaz;4seraw?z}m&(H9XJ+u9P;uIWzhpzl{kF zdq=8m)NMr`mF=qCzt11#I8j$QU0Olv$UR)Sk;$zAUY`yRZ2`QvzdZr+bhA*jc3Q`- zM$eMITK97q$#AtgV?^S)lDbW%%jS4o7z^OA=g5 z;oJu<5~^{IK{g2VVYDAw2pY8!PT0^-LdbvOehC4?5g!b9%_5r{0fd zZ@usLFKzL2Uki)A$;_c9JhIYaa0o@@hSH}a&{pF0z>v$dt?AT&_yhT;K?D8Lw<-(UK<@F2QFc4F9iDxXYs2dJH{%Bxi*xFP%h6BF;!_1 zv=xU1HlzmC=5Q!#3?P7avRB9YZVdtg3U_r#EjdJfEXVYc5(3^I3`nSve=(*9AJF%al-8A@hTT``4`zTXUv1N)j zxs@ssQ(3^q*ZIV1pg@={%tS@{fW&&I2h-N;#r5S{^~dAkU=R#YS+p!Fwt%SoT7%9p z{1~lqy+LM;72*}UUZT}1Y?EW`0#)yQzC z&fcsU{*Y4zD1gXl^XS687SP%=dgJNBwlJ}w3o2eXFMwOnqOOzl6f3Ui(iKgDxj zeVP8sM*8jZ)F=Vzh_x_`B6X?3&$yR3>h76nPKplxZZ=Q1{h^OyxAx?~{9+$A7?caHMDLyTF_4MOqpnPEJ)dyN+wXQ~ktZ8!JL zcvQ8ol})?}eW6UQjNALR+u=u1^5gn%MAbAB%#AhT_Y1Zvt3imrB1+3=ReTk@}f}E z32Qb6(~Io$u!gr_xK)G$u^{1K6uV~{n@#OqTp!VLG-vEKZx{Oi~4`}(w|Ol%nI!H4SaTlpdGuCKS(bqjVTtL;v6ym(Sg z!HtJuUYM}mmj=!+dM{TG?hL)#&-J^gwzA?^62n@AaxHIMNz=8&`56DyWdtDapj>pLQsu_sWtLz&E_Ej1oWGS zFQ!aPyymRt&Ok8WJT%}OmW|oT%Xuu8qi9J}8d;WjUPho|+Dt#m-m@-}m7N*as!uFw zC9xd6o-`LVFfdGxG0r1q^R}Nx$l?GEhkYRX%||?$NlH!pC9e;cHqN&~ zPQ7wVIVqM({%){+e6tGPj_}r~)BT1nh(G48G36ZD@YY#nKhD_CMjRf5L|4&nKRkU) zQV$d2;%HepzMxC?e)=Kp+pgulLy)y{&G%O-MGY6U4r4T%d9!o@=)IjnOfE=P%vydm z`&rC9r=JgRSQlAD8MU;J{1d>a@$kvzR2nbByJdNQ*hJ(JX}#;~3(dFAikj0cHPf{n zviQ+C?qjf4-EYFTYa(3Hs#UmNRWzfN!(ks(XSwM`5cA9ghMY(iMHpN!5{xzBMB#qs zNKtXTA~2WeeNG4FY)bA&9OD~z>DsTU2v5^hnlfF|10m@X{lsexL39ian5zbGN|lDl zvF@v6O67-!*OMW;#T{c$d|(RqA><+jX3^VGoqZ5o9#MTKm&2r$$Nmx~GTZv4@5Fw< z8Q1myIJhkKEphwuIM_9CE_Zz-AJ?cAt4zwk#ly{3UA~br{G>hA=661h;g}y(v4^85 zyN=K+k3AzFdC)ji=f^9QE0m)I9jeWNbIsOKbq`nEr&Jw1TMgMRWNNf({cVqAlSR2N z3zPjZ%uSM!82ty0C>r@CIWOAHR3LOuz)FNncM>60PAKK*xphmGr~>Hj*LeR61|%FR zUTo-O5h!1%f?3UyEisI_8>{sz}8E#WWfoH02f0%Bpz<;B^Up&doqd?6}oI zmAG_^EU!ZGkmTb<}T zi_Z&+|6z$J@JqT|4>Ra`C-OiW`DXijt%|wW=J>>UI2L$qCS5h}(|`L-i*q`!+ZHwa z05j8#IcY#u{d?~F7XMy^amwPH@*9M7e0sl&o_UXJ=L@sq)`;DM6U=PL{tvsJf=cx& zdMT|IBXa3k@HwaFsnPl#THsi#?+!W%5rI@}Im{3|fjpU_dmL+FiXk3gP&O1dqv!T8 zKm_pekCgM%Bl-uWX}G+u8@EMd6BtpSziHYJ)M69#Ec22jbTm^@pov-!N{?wO zpqvi-CIn*%CG3yrY%a$g302Q9b*4~zjHQxX+g@Qev78?5;O>#vdCJF`X&jm4q8 z5y^xtY|PF#?g=V^5eX_s1Gwq(fm$_JBdF%0od^(>kQPTJY(C9d;9L(wtooQCYRgTZ z`ZF63*u6F#)}||=igzpuBR_TQ7f&;mRdlR_Je6Uop(XHvtRUq4uC4f^zJO99caA=J z5i&SBkg<_hQ%|B4U+xi+u^MMR4j2yu>V9E;$)TVgIC|8xUKTI-PtZe`>;4=ZTrQLof22`Mw=>#{Z644`` ze}hYcy&ZV<0v!L^I^C2QWIO=1V0@n)k({41e^YMkcmBZ?!x<>ks=#C$BGW0GA z)y)8&hPa;T^GrzgRZBJb4DY*QmO5M{9OKwvesv2l@3C;Rvgs4=3ddTzXIcbuzg|;4 zXF+o=a=5oeHXQqajQ6GgN@8`@+6Lt&ZOaDM+rq{72lWp1yJm__dq?nUuTYbmY*Rs` zyPaUfqyIwPFMlv1|U7_2L;MvpMZ=ZXFq zWx~N3?N_8hiPed!WUCd(1}Aoe)XJtGktJDfj8!hG`yn0F)5cVCFROIFjOvkk3M$dT z)Ubm*#$j4kp;GpK-r|Ba_VL{7s-X@*OUIaUXvPr+nowa$RU8*+mkV_VWJZ_Iey!5A z7-cJ5UrzbRaWOluzWpu@L>m2}gssgl191o3-_1V`_Dty4x5rq=v@W0<;euHbA_Y7m zc!tAjH+>F$vNRvHAL%B%JLOfzEm)T6@n@6J>>muEvKal3$$Mqa9MA6`6yFNmrK_IL zhfmKR(jSo@bvp5}b(J11ICJ80+bjc#E)DJ00_GYUWiG;QUuAI=a_9t>0^`L`)G10q zLCpAMm1R`6ghqyUKQNeid8=h|GUo1O9jbOpWvG}0)=Y+jbCuJeApIl%uArU^1aRRj znE2GyRLL7fF{U-6=M@aI-q|Kv? z5X^$roaBc{r11)w4=NqSi@Lw#mZ+kTD3mobFkQ=?BaWPa_@-!QOn!9xS;2 zi-OI<@IMsn|84A$k^cWRc9^jF&rtv!@-N4%=Zb~`Hh4iCyxdYbJQAB}1uQT8oFE!L z_$i=Ow@#gs8ZnRd=lW|c9QL`MWkc|3A9Ou0R0i|d4$DS{KmX82`SRW_S&=DzY(_3dk{el|-KW@4;-A^ZAkM zrC2w_1)I!a1evKsI%G){nK%A~i%@3L`A`$-1XKyqqCc6T@yrDEA`gjcWbD`M@*!!P zP(nRWO%hf*;ztl;IhQ0uj5X4Z7S@$p;^N~l5oM%-eV^$}b%v-%ZeSPtUlBgX(w$lD zRnS}2L0FfWj9gu<-9oniRsqKUQGx$wjFFv*?tk|Xu+Xv5{fEcnn$yxrc{zQTXZCZ7 z`xUz_C@WJCksyeRMjX0U>w$#!VaQWZ3P}tPFOH87bB=yV!wlYBxVpFomO`WmI)^N< zU%#0r;*CtfQaff+!+xorTCCivPLfP|ox!1GjOdD!H5e^y>S%yZ8J0w)+;6 z4*(DL!#}v?7zTa4m67vScud%9L&etWc7I}s^^X|J3tV-Nd*zi>Zp`5k!%J+{xq9dQ zt_PeokRA>&{A{iD?e!m^Hvp;DgEr&qkRE1#^XgcjHT#~%lFG*JL)+Wj@WCItm{S*g zJep}G$T+N_pQ@T@&0cmTi^KX|f1zfpGo9_9)}i_5Fk9Ax*{!voX&jz#abR$+$j4*p zYfMgW=XThuT+xh{SEtv1yaq5!00)gTx7n1LoYbg7R{h+CNA$X`Xm$`Tv^O9x097K9 zo~z5ckSGka5i5AL978l%Q^g*sq^e>VVLZcYBt+)FUYm8P5aWD5=`r@zUl1Lb4skUG z&&jBJdw;%2@UwtGcOUUEQTq|qAcgCoEAmk>@S%78aMnP*4-Yv)+~e5IWl(0!=T4gj zQQuD9-rm3xDK)*VeZK-N&3`Tk+WMgUkUjM=eFJzsugO*;?yvz4|BuGrF*viZYZL7x zoup&iww@Rrn;qwgZQHhOvt!$~ZQJhnN75wXKkC7`A=RsiLhuB=?oAjO5%tww z9Xqo9TUwjfRpsm^1MjP>!-ww6^f9_n~#tyffxH=&aF z9B@t1sv87Ok{1Y|x_-MECz6!sRPyUa>pB~>sN~ni=a0w8ZnXwa9i$TH*p#hPl;3Ts zB;8u!71oqnWmFVz=6RtuiXrTd(itXTMU5dSjFBa@e@2|3hgW=KvIlx|nizdgTl!?Q z+QVVk#?GTb{v7!J&HZ&@ctm21OMnizXd?cMy(;Ty~ zF$0l%K$=#aZYW4Vl63?Ho!Rvti*rG;LEdh@OkS5X>=M*-p+AKMNKCGz6*Fqb(p;;{E)z%Dke}i&4wX*7+ib6I{w1lJ=0D;0M)# ze6@0ii*#XQ6jI?lH>y4RlsTFm=yUkrMEIPJADeQqIN2i+A6=Ki!DA19DRByX16%__ z%yYGZp#&CYof?F@WbEc296{9n{ppL_(ju22<g21Z88#S#Bz@4b?4OSP1_=>=!soc!-%{BD(-$m^+s~)C7BhFOb>}} z$T$}Au>op3WCT`K*a9Jx=-q%J3jVm;^HopPf|u%Y;05C58)!K?Shg#N?~ygUs-k7d zP8A8tyx?hp<>Uwm3!fj>w?<$00}KT_vE51bu_3wI#n;0Y!#{3$>y$ zmiJD%QB`q5yxrKaB;hs4XRwNBBG$!O&!^$2OOIttN~^g_OROPPG01pWxhE|L@eH~0 zf?dC`l~fjEEn|fuW8n6Mp+M}Z*b@6h{;3Qag7G3li-jnVF=gd*tI$HB6Gr^C`l ze^cQWv3E+3;bR6XKi5QfL=Jg zEW=gcN~)P7EAL%H{EcH2Lmx-U?D!&lxaKNjgIpggvopM_76MSD%i7PF&}@{xmUA5M zX6&G4qeZ|>918{s*9;^6S?HMtt+W}iyzbSuor_(No0CkofTd*s5$rEeMyJGi0Ad6j z_MJmiFPs+LcF3^d-W&%>Dy*wz^rCO;?IQ}hsKSAc--MgYOF$l4+KkGh!0JP7L<s(j06!40ia6yHIU514=Tmr1@LaWAlD~&dnL|;xcfXZg5Vj4_Wr8CHzsDJs*?}z zl1JSCI@6;EAV*FfAsUDFygH?72m991n(hSz=Q5ecCyfvH) zTtiT4tskVww=!EYk&Keu2nv~4O(|gx_%}UC5Sk(P#{ZXQt}T*sqU$gEYq8bkvOx2m zu~-5bh3wBd8~)coN$N;=Q~p;#>SuL^c=FO)qfpos%FkXD!N}3 z@br?;8g;6VfqMD$sY>THpMiMC==LrS1b0;L_n^NVf}H%RGm+40l|98fh_#s}*dB1Q z*-aa;BO;%r7fZR6OU{(C%D%)NnLeuIit#wk|BY8}*U-JvV3N3;rNDGTK3-o_<73xG z;;~(_UJSO1MmEIt^*Fdrv+rtUgCiM3(BY0V(;6_^SNw{N%R;K*7WeM@t&3o2#P#9q zgU>r%J1&}YrT;qQd`rPweX{qN@Htm&^-gjJF$&4->Q4^Rqi=}QFG_(rQH$c`wDrEh z-!y!QoLHD>HA#c5(zL+dbYY>1RHoAfkftid>>l~Hm>>mU7(;5I_kw^9$T7F2ghUZr zXy6-{5V3`dMXH(+Bk#+BwjbP>fW`6nU1+u^=95BczJ#&?ilcmFTbTNy4>wxOgf!k{ za5U0f8nV`&M=A?bHU!!ly)UgVr@Onwr3c)1L9_D_d@BX4Q+L{O=SM&=e=%vm=8JPo zQO3GbQu0U7bjJPkAlw<5o*sL6yL5B&r!0>Dp;6E|cDKlkur0PVx03!FL23BfJ$S=E z)gpGf@x46uM??U#$p8`(&j2&?EJ=9es9qTqw{Y+TA+vd(BMJ}E!LS(bQ|hmq4v;n= zJh1Ozq9g=WF@+;xK3~TN~e0bxjtvG-kcgyy9x9a-S++x+MM3$+!Q^cKM zz12+5R7B<_ExD{AdS8P(B%6~9Rm=#(U$xZ}KX$WJAdCXnUl?q-4wNx4WDv`bpO9NO zrviGEG^7P;_f8CD^?4XOt)My{Ff$ z-|?BfLV(5=W+(M|!PA~QqMLJ_iZ=2TPDN#ThcX?11$K@5Rr!?ZY#Dpd`FW&)_ZYA- zzP8O^x@B(Ffc)t65pob*vK(DZ&yO7}p9B3z(M=q7$d1^apV0NFjFE#_1$mR1hFMoE zqY)uNvpAZMNr4GIZm|!iWept0pIK9v1qY6n0K=rw-L>~pH!@NeeU$@|62=K%0V45KjxA#xS}B=L0-zK`wiMhT3};ZsPbD>b zRw_W*5phqGNSH>FvUJh@mc0H9C~0VJ9CtCV&UFAFvC~*?)zqFRMdZYI4dwg`wa-U0 zIu!vH3raAKvU{}=ymyTIN2X;R-31KVq?tWTRX}@iE~%jzXQAN#B9`RN>qJ@<)Yr_6 zPc(maB^E9!oDwn+A@cZ}IBUE~A2WP@YpZ<;c8M^2{d>K^*x)GYt?NEZo%qvwymb<9 z-CGUGT*mC*>?-8Q2ZJ{zvAv$P%wuLg+4nXzgbJ_E=2oE3m~<(Fv__^*?HNlEA6)Bl z$OZ}#*$IF5II=#!%V-|CEp6Bhtp3$l6*r<5!TW^BC0b=l`5@%=pLFz>&eVBFi35m| zy!m~o{vX4)9kT<_p&1m!MUVORs~@Dlo8LU zB{K7|GccHR#gi7FfsDxtgA@r54p#w9|9T%phsb_<9lRK9zbsE3(|7m)JwA@OyPd9I z*9lCkae40!_C<-##WyXo_ z2R8YxS|#34b9U0wy7mCkA+qbz1UeOj%eLv6V$VgMW7<$>0c=-; z_XIhdoBQzZ*@i$`_D9Pree1QgwaxxV^J;USC3@5DjbCaIn2XvzjHLFAbX zsEPDi8qD6vX#!LFZl}>Ask}ED8t)x_^n{=B+D=SFK<;8V6GICUtom5K7KUcdu^inQ zn+NfVRa^`)EVA_t^cox{wLhQYTs}NHlLQB`-@8`_bU}T+Sz_Y@Hst@*l!_~oiW0|Q z9zDDfbiRu=k4n{j)y%9ldasLiy*06BG`EPe)gnt9wtXI^+X=#$C?pT5 z52AnYQo>PJ1nd{DUP8eqn2C0*_i|D9(bA|_{y}Pz%x`C*l`T#mBrFxoK9OB7rS`{}WL#?w{y^wUFk_-K+_ z^nBFmTjRx)>*apBWwYt9*%48%Sm5ouNluziiUDrYhADagT-t90b#>b#7S9+rP9Ezs z)^%Fvrv_6cNx(-dSQ6t*4VV~T1VcH@U7t>Gm~LByxf${Ovnk);fMXq8gh! zRjENP*Ue&}{|k#_B+W6H_+ln4!a+wzR+J0KByOFf>7&<)EHa(IS{dtcy_zi9v}xEn z39WGLIsW<_`JCE>s!HgLFK-FU@rvzCxbmp6Ry_ zX>=HVYc@R=Po|W#@b-AcnAnnw>12GO;_}Cc?_T#jS!T$Oz7{)lLwIKM1vdu2#PsSl ztV_2dXD6YDF_p6U4B#!1tf5=6$hrZ(|ww#KWLmg-C|UxT#h=md~EjI^>6T(piYm7<&y zSF!B=V8y!JFg}GAwGkKBK#_xDlix0sn4xNW%%O&^#39e3J4JQVfof8x4hNAiY77C* zIxtx4KRUTazK6vNuKJ-lU<@|uXYi!>*&L4V>7!JMx%0AELcEjm_o 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