--- a/hedgewars/GSHandlers.inc Wed Jul 25 16:31:34 2012 +0400
+++ b/hedgewars/GSHandlers.inc Wed Jul 25 22:46:03 2012 +0400
@@ -2406,7 +2406,7 @@
//DrawExplosion(gX, gY, 4);
if ((GameTicks and $7) = 0) and (Random(2) = 0) then
- for i:= 1 to Random(2)+1 do
+ for i:= Random(2) downto 0 do
AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
if Gear^.Health > 0 then
@@ -2420,7 +2420,7 @@
begin
DrawExplosion(gX, gY, 4);
- for i:= 0 to Random(3) do
+ for i:= Random(3) downto 0 do
AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
end;
@@ -2438,20 +2438,12 @@
if not sticky then
begin
if ((GameTicks and $3) = 0) and (Random(1) = 0) then
- begin
- for i:= 1 to Random(2)+1 do
- begin
+ for i:= Random(2) downto 0 do
AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
- end;
- end;
end
else
- begin
- for i:= 0 to Random(3) do
- begin
+ for i:= Random(3) downto 0 do
AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
- end;
- end;
DeleteGear(Gear)
end;
@@ -4398,7 +4390,7 @@
Gear^.State := Gear^.State and (not gstMoving);
if (Land[y, x] and lfBouncy <> 0)
- or not CalcSlopeTangent(Gear, x, y, tx, ty, 255)
+ or (not CalcSlopeTangent(Gear, x, y, tx, ty, 255))
or (DistanceI(tx,ty) < _12) then // reject shots at too irregular terrain
begin
loadNewPortalBall(Gear, true);
--- a/hedgewars/uAI.pas Wed Jul 25 16:31:34 2012 +0400
+++ b/hedgewars/uAI.pas Wed Jul 25 22:46:03 2012 +0400
@@ -434,7 +434,7 @@
end
end;
-PGear(Me)^.State:= PGear(Me)^.State and not gstHHThinking;
+PGear(Me)^.State:= PGear(Me)^.State and (not gstHHThinking);
Think:= 0;
InterlockedDecrement(hasThread)
end;
--- a/hedgewars/uAIMisc.pas Wed Jul 25 16:31:34 2012 +0400
+++ b/hedgewars/uAIMisc.pas Wed Jul 25 22:46:03 2012 +0400
@@ -439,21 +439,21 @@
end;
if fallDmg < 0 then // drowning. score healthier hogs higher, since their death is more likely to benefit the AI
if Score > 0 then
- inc(rate, KillScore + Score div 10) // Add a bit of a bonus for bigger hog drownings
+ inc(rate, (KillScore + Score div 10) * 1024) // Add a bit of a bonus for bigger hog drownings
else
- dec(rate, KillScore * friendlyfactor div 100 - Score div 10) // and more of a punishment for drowning bigger friendly hogs
+ dec(rate, (KillScore * friendlyfactor div 100 - Score div 10) * 1024) // and more of a punishment for drowning bigger friendly hogs
else if (dmg+fallDmg) >= abs(Score) then
if Score > 0 then
- inc(rate, KillScore)
+ inc(rate, KillScore * 1024 + (dmg + fallDmg)) // tiny bonus for dealing more damage than needed to kill
else
- dec(rate, KillScore * friendlyfactor div 100)
+ dec(rate, KillScore * friendlyfactor div 100 * 1024)
else
if Score > 0 then
- inc(rate, dmg+fallDmg)
- else dec(rate, (dmg+fallDmg) * friendlyfactor div 100)
+ inc(rate, (dmg + fallDmg) * 1024)
+ else dec(rate, (dmg + fallDmg) * friendlyfactor div 100 * 1024)
end;
end;
-RateExplosion:= rate * 1024;
+RateExplosion:= rate;
end;
function RateShove(Me: PGear; x, y, r, power, kick: LongInt; gdX, gdY: real; Flags: LongWord): LongInt;
@@ -651,7 +651,7 @@
Gear^.Y:= Gear^.Y + Gear^.dY;
if (not Gear^.dY.isNegative) and (TestCollisionYwithGear(Gear, 1) <> 0) then
begin
- Gear^.State:= Gear^.State and not (gstMoving or gstHHJumping);
+ Gear^.State:= Gear^.State and (not (gstMoving or gstHHJumping));
Gear^.dY:= _0;
case JumpType of
jmpHJump:
@@ -722,7 +722,7 @@
if TestCollisionYwithGear(Gear, 1) <> 0 then
begin
inc(GoInfo.Ticks, 410);
- Gear^.State:= Gear^.State and not (gstMoving or gstHHJumping);
+ Gear^.State:= Gear^.State and (not (gstMoving or gstHHJumping));
Gear^.dY:= _0;
// try ljump instead of fall
HHJump(AltGear, jmpLJump, GoInfo);
--- a/hedgewars/uAmmos.pas Wed Jul 25 16:31:34 2012 +0400
+++ b/hedgewars/uAmmos.pas Wed Jul 25 22:46:03 2012 +0400
@@ -374,7 +374,7 @@
with CurWeapon^ do
begin
s:= trammo[Ammoz[AmmoType].NameId];
- if (Count <> AMMO_INFINITE) and not (Hedgehog.Team^.ExtDriven or (Hedgehog.BotLevel > 0)) then
+ if (Count <> AMMO_INFINITE) and (not (Hedgehog.Team^.ExtDriven or (Hedgehog.BotLevel > 0))) then
s:= s + ' (' + IntToStr(Count) + ')';
if (Propz and ammoprop_Timerable) <> 0 then
s:= s + ', ' + IntToStr(Timer div 1000) + ' ' + trammo[sidSeconds];
@@ -386,7 +386,7 @@
end
else
begin
- if Gear <> nil then Gear^.State:= Gear^.State and not gstHHChooseTarget;
+ if Gear <> nil then Gear^.State:= Gear^.State and (not gstHHChooseTarget);
isCursorVisible:= false
end;
end
--- a/hedgewars/uCommandHandlers.pas Wed Jul 25 16:31:34 2012 +0400
+++ b/hedgewars/uCommandHandlers.pas Wed Jul 25 22:46:03 2012 +0400
@@ -766,7 +766,7 @@
procedure chGameFlags(var s: shortstring);
begin
GameFlags:= StrToInt(s);
-if GameFlags and gfSharedAmmo <> 0 then GameFlags:= GameFlags and not gfPerHogAmmo
+if GameFlags and gfSharedAmmo <> 0 then GameFlags:= GameFlags and (not gfPerHogAmmo)
end;
procedure chHedgehogTurnTime(var s: shortstring);
--- a/hedgewars/uCommands.pas Wed Jul 25 16:31:34 2012 +0400
+++ b/hedgewars/uCommands.pas Wed Jul 25 22:46:03 2012 +0400
@@ -95,7 +95,7 @@
begin
if TrustedSource or t^.Trusted then
begin
- if t^.Rand and not CheckNoTeamOrHH then
+ if t^.Rand and (not CheckNoTeamOrHH) then
CheckSum:= CheckSum xor LongWord(SDLNet_Read32(@CmdStr)) xor LongWord(s[0]) xor GameTicks;
t^.Handler(s);
end;
--- a/hedgewars/uGears.pas Wed Jul 25 16:31:34 2012 +0400
+++ b/hedgewars/uGears.pas Wed Jul 25 22:46:03 2012 +0400
@@ -211,7 +211,7 @@
RemoveGearFromList(curHandledGear);
// since I can't think of any good reason this would ever be separate from a remove from list, going to keep it inside this block
if curHandledGear^.Message and gmAddToList <> 0 then InsertGearToList(curHandledGear);
- curHandledGear^.Message:= curHandledGear^.Message and not (gmRemoveFromList or gmAddToList)
+ curHandledGear^.Message:= curHandledGear^.Message and (not (gmRemoveFromList or gmAddToList))
end;
if curHandledGear^.Active then
begin
@@ -634,8 +634,7 @@
if (GameFlags and gfArtillery) <> 0 then
cArtillery:= true;
-
-for i:= 0 to GetRandom(10)+30 do
+for i:= GetRandom(10)+30 downto 0 do
begin rx:= GetRandom(rightX-leftX)+leftX;
ry:= GetRandom(LAND_HEIGHT-topY)+topY;
rdx:= _90-(GetRandomf*_360);
--- a/hedgewars/uGearsHedgehog.pas Wed Jul 25 16:31:34 2012 +0400
+++ b/hedgewars/uGearsHedgehog.pas Wed Jul 25 22:46:03 2012 +0400
@@ -853,7 +853,7 @@
Gear^.State:= Gear^.State and (not gstMoving);
exit
end;
-isFalling:= (Gear^.dY.isNegative) or not TestCollisionYKick(Gear, 1);
+isFalling:= (Gear^.dY.isNegative) or (not TestCollisionYKick(Gear, 1));
if isFalling then
begin
if (Gear^.dY.isNegative) and TestCollisionYKick(Gear, -1) then
@@ -983,7 +983,7 @@
begin
Gear^.State:= Gear^.State and (not gstWinner);
Gear^.State:= Gear^.State and (not gstMoving);
- while (TestCollisionYWithGear(Gear,1) = 0) and not CheckGearDrowning(Gear) do
+ while (TestCollisionYWithGear(Gear,1) = 0) and (not CheckGearDrowning(Gear)) do
Gear^.Y:= Gear^.Y+_1;
SetLittle(Gear^.dX);
Gear^.dY:= _0
--- a/hedgewars/uGearsUtils.pas Wed Jul 25 16:31:34 2012 +0400
+++ b/hedgewars/uGearsUtils.pas Wed Jul 25 22:46:03 2012 +0400
@@ -420,10 +420,9 @@
Scale:= hwFloat2Float(Gear^.Density / _3 * Gear^.dY);
if Scale > 1 then Scale:= power(Scale,0.3333)
else Scale:= Scale + ((1-Scale) / 2);
- if Scale > 1 then Timer:= round(max(Scale,3))
+ if Scale > 1 then Timer:= round(min(Scale*0.0005/cGravityf,4))
else Timer:= 1;
// Low Gravity
- Timer:=round(0.0005/cGravityf);
FrameTicks:= FrameTicks*Timer;
end;
--- a/hedgewars/uIO.pas Wed Jul 25 16:31:34 2012 +0400
+++ b/hedgewars/uIO.pas Wed Jul 25 22:46:03 2012 +0400
@@ -402,7 +402,7 @@
TargetPoint.Y:= putY
end;
AddFileLog('put: ' + inttostr(TargetPoint.X) + ', ' + inttostr(TargetPoint.Y));
- State:= State and not gstHHChooseTarget;
+ State:= State and (not gstHHChooseTarget);
if (Ammoz[CurAmmoType].Ammo.Propz and ammoprop_AttackingPut) <> 0 then
Message:= Message or (gmAttack and InputMask);
end
--- a/hedgewars/uInputHandler.pas Wed Jul 25 16:31:34 2012 +0400
+++ b/hedgewars/uInputHandler.pas Wed Jul 25 22:46:03 2012 +0400
@@ -25,8 +25,9 @@
procedure initModule;
procedure freeModule;
-function KeyNameToCode(name: shortstring; Modifier: shortstring = ''): LongInt;
-procedure MaskModifier(var code: LongInt; modifier: LongWord);
+function KeyNameToCode(name: shortstring): LongInt; inline;
+function KeyNameToCode(name: shortstring; Modifier: shortstring): LongInt;
+//procedure MaskModifier(var code: LongInt; modifier: LongWord);
procedure MaskModifier(Modifier: shortstring; var code: LongInt);
procedure ProcessMouse(event: TSDL_MouseButtonEvent; ButtonDown: boolean);
procedure ProcessKey(event: TSDL_KeyboardEvent); inline;
@@ -60,6 +61,11 @@
KeyNames: array [0..cKeyMaxIndex] of string[15];
CurrentBinds: TBinds;
+function KeyNameToCode(name: shortstring): LongInt; inline;
+begin
+ KeyNameToCode:= KeyNameToCode(name, '');
+end;
+
function KeyNameToCode(name: shortstring; Modifier: shortstring): LongInt;
var code: LongInt;
begin
@@ -70,7 +76,7 @@
MaskModifier(Modifier, code);
KeyNameToCode:= code;
end;
-
+(*
procedure MaskModifier(var code: LongInt; Modifier: LongWord);
begin
if(Modifier and KMOD_LSHIFT) <> 0 then code:= code or LSHIFT;
@@ -80,7 +86,7 @@
if(Modifier and KMOD_LCTRL) <> 0 then code:= code or LCTRL;
if(Modifier and KMOD_RCTRL) <> 0 then code:= code or LCTRL;
end;
-
+*)
procedure MaskModifier(Modifier: shortstring; var code: LongInt);
var mod_ : shortstring;
ModifierCount, i: LongInt;
@@ -133,7 +139,7 @@
if CurrentBinds[code][0] <> #0 then
begin
- if (code > 3) and KeyDown and not ((CurrentBinds[code] = 'put') or (CurrentBinds[code] = 'ammomenu') or (CurrentBinds[code] = '+cur_u') or (CurrentBinds[code] = '+cur_d') or (CurrentBinds[code] = '+cur_l') or (CurrentBinds[code] = '+cur_r')) then hideAmmoMenu:= true;
+ if (code > 3) and KeyDown and (not ((CurrentBinds[code] = 'put')) or (CurrentBinds[code] = 'ammomenu') or (CurrentBinds[code] = '+cur_u') or (CurrentBinds[code] = '+cur_d') or (CurrentBinds[code] = '+cur_l') or (CurrentBinds[code] = '+cur_r')) then hideAmmoMenu:= true;
if KeyDown then
begin
--- a/hedgewars/uScript.pas Wed Jul 25 16:31:34 2012 +0400
+++ b/hedgewars/uScript.pas Wed Jul 25 22:46:03 2012 +0400
@@ -981,7 +981,7 @@
begin
prevgear := CurrentHedgehog^.Gear;
prevgear^.Active := false;
- prevgear^.State:= prevgear^.State and not gstHHDriven;
+ prevgear^.State:= prevgear^.State and (not gstHHDriven);
prevgear^.Z := cHHZ;
prevgear^.Message:= prevgear^.Message or gmRemoveFromList or gmAddToList;
--- a/hedgewars/uSound.pas Wed Jul 25 16:31:34 2012 +0400
+++ b/hedgewars/uSound.pas Wed Jul 25 22:46:03 2012 +0400
@@ -587,11 +587,8 @@
RegisterVariable('mute' , @chMute , true );
MusicFN:='';
- isMusicEnabled:= true;
- isSoundEnabled:= true;
isAudioMuted:= false;
isSEBackup:= isSoundEnabled;
- cInitVolume:= 100;
Volume:= 0;
defVoicepack:= AskForVoicepack('Default');
@@ -615,6 +612,11 @@
begin
if isSoundEnabled then
ReleaseSound(true);
+ // koda still needs to fix this properly. when he rearranged things, he made these variables get
+ // reset after argparsers picks them up
+ isMusicEnabled:= true;
+ isSoundEnabled:= true;
+ cInitVolume:= 100;
end;
end.
--- a/hedgewars/uTeams.pas Wed Jul 25 16:31:34 2012 +0400
+++ b/hedgewars/uTeams.pas Wed Jul 25 22:46:03 2012 +0400
@@ -473,7 +473,7 @@
begin
Gear^.Invulnerable:= false;
Gear^.Damage:= Gear^.Health;
- Gear^.State:= (Gear^.State or gstHHGone) and not gstHHDriven
+ Gear^.State:= (Gear^.State or gstHHGone) and (not gstHHDriven)
end
end
end;
--- a/hedgewars/uVisualGears.pas Wed Jul 25 16:31:34 2012 +0400
+++ b/hedgewars/uVisualGears.pas Wed Jul 25 22:46:03 2012 +0400
@@ -295,6 +295,8 @@
dy:= 0;
FrameTicks:= 740;
Frame:= 19;
+ Scale:= 0.75;
+ Timer:= 1;
end;
vgtDroplet:
begin
--- a/hedgewars/uWorld.pas Wed Jul 25 16:31:34 2012 +0400
+++ b/hedgewars/uWorld.pas Wed Jul 25 22:46:03 2012 +0400
@@ -1329,7 +1329,7 @@
r.w:= 3;
DrawTextureFromRect(TeamHealthBarWidth + 16, cScreenHeight + DrawHealthY + smallScreenOffset, @r, HealthTex);
- if not highlight and not hasGone and (TeamHealth > 1) then
+ if not highlight and (not hasGone) and (TeamHealth > 1) then
for i:= 0 to cMaxHHIndex do
if Hedgehogs[i].Gear <> nil then
begin
--- a/tools/PascalParser.hs Wed Jul 25 16:31:34 2012 +0400
+++ b/tools/PascalParser.hs Wed Jul 25 22:46:03 2012 +0400
@@ -19,7 +19,7 @@
pascalUnit = do
comments
- u <- choice [program, unit, systemUnit]
+ u <- choice [program, unit, systemUnit, redoUnit]
comments
return u
@@ -348,36 +348,46 @@
comments
return $ Implementation u (TypesAndVars tv)
-expression = buildExpressionParser table term <?> "expression"
+expression = do
+ buildExpressionParser table term <?> "expression"
where
term = comments >> choice [
builtInFunction expression >>= \(n, e) -> return $ BuiltInFunCall e (SimpleReference (Identifier n BTUnknown))
, try (parens pas $ expression >>= \e -> notFollowedBy (comments >> char '.') >> return e)
, brackets pas (commaSep pas iD) >>= return . SetExpression
- , try $ natural pas >>= \i -> notFollowedBy (char '.') >> (return . NumberLiteral . show) i
+ , try $ integer pas >>= \i -> notFollowedBy (char '.') >> (return . NumberLiteral . show) i
, float pas >>= return . FloatLiteral . show
- , natural pas >>= return . NumberLiteral . show
+ , try $ integer pas >>= return . NumberLiteral . show
, try (string "_S" >> stringLiteral pas) >>= return . StringLiteral
, try (string "_P" >> stringLiteral pas) >>= return . PCharLiteral
, stringLiteral pas >>= return . strOrChar
, try (string "#$") >> many hexDigit >>= \c -> comments >> return (HexCharCode c)
, char '#' >> many digit >>= \c -> comments >> return (CharCode c)
, char '$' >> many hexDigit >>= \h -> comments >> return (HexNumber h)
- , char '-' >> expression >>= return . PrefixOp "-"
+ --, char '-' >> expression >>= return . PrefixOp "-"
+ , char '-' >> reference >>= return . PrefixOp "-" . Reference
+ , try $ string "not" >> error "unexpected not in term"
, try $ string "nil" >> return Null
- , try $ string "not" >> expression >>= return . PrefixOp "not"
, reference >>= return . Reference
] <?> "simple expression"
- table = [
+ table = [
+ [ Prefix (try (string "not") >> return (PrefixOp "not"))
+ , Prefix (try (char '-') >> return (PrefixOp "-"))]
+ ,
[ Infix (char '*' >> return (BinOp "*")) AssocLeft
, Infix (char '/' >> return (BinOp "/")) AssocLeft
, Infix (try (string "div") >> return (BinOp "div")) AssocLeft
, Infix (try (string "mod") >> return (BinOp "mod")) AssocLeft
, Infix (try (string "in") >> return (BinOp "in")) AssocNone
+ , Infix (try $ string "and" >> return (BinOp "and")) AssocLeft
+ , Infix (try $ string "shl" >> return (BinOp "shl")) AssocLeft
+ , Infix (try $ string "shr" >> return (BinOp "shr")) AssocLeft
]
, [ Infix (char '+' >> return (BinOp "+")) AssocLeft
, Infix (char '-' >> return (BinOp "-")) AssocLeft
+ , Infix (try $ string "or" >> return (BinOp "or")) AssocLeft
+ , Infix (try $ string "xor" >> return (BinOp "xor")) AssocLeft
]
, [ Infix (try (string "<>") >> return (BinOp "<>")) AssocNone
, Infix (try (string "<=") >> return (BinOp "<=")) AssocNone
@@ -385,13 +395,13 @@
, Infix (char '<' >> return (BinOp "<")) AssocNone
, Infix (char '>' >> return (BinOp ">")) AssocNone
]
- , [ Infix (try $ string "shl" >> return (BinOp "shl")) AssocNone
- , Infix (try $ string "shr" >> return (BinOp "shr")) AssocNone
+ {-, [ Infix (try $ string "shl" >> return (BinOp "shl")) AssocNone
+ , Infix (try $ string "shr" >> return (BinOp "shr")) AssocNone
]
- , [ Infix (try $ string "and" >> return (BinOp "and")) AssocLeft
- , Infix (try $ string "or" >> return (BinOp "or")) AssocLeft
+ , [
+ Infix (try $ string "or" >> return (BinOp "or")) AssocLeft
, Infix (try $ string "xor" >> return (BinOp "xor")) AssocLeft
- ]
+ ]-}
, [
Infix (char '=' >> return (BinOp "=")) AssocNone
]
@@ -415,7 +425,7 @@
, switchCase
, withBlock
, forCycle
- , (try $ reference >>= \r -> string ":=" >> return r) >>= \r -> expression >>= return . Assignment r
+ , (try $ reference >>= \r -> string ":=" >> return r) >>= \r -> comments >> expression >>= return . Assignment r
, builtInFunction expression >>= \(n, e) -> return $ BuiltInFunctionCall e (SimpleReference (Identifier n BTUnknown))
, procCall
, char ';' >> comments >> return NOP
@@ -480,7 +490,12 @@
comments
e1 <- expression
comments
- choice [string "to", string "downto"]
+ up <- liftM (== Just "to") $
+ optionMaybe $ choice [
+ try $ string "to"
+ , try $ string "downto"
+ ]
+ --choice [string "to", string "downto"]
comments
e2 <- expression
comments
@@ -488,7 +503,7 @@
comments
p <- phrase
comments
- return $ ForCycle i e1 e2 p
+ return $ ForCycle i e1 e2 p up
switchCase = do
try $ string "case"
@@ -573,14 +588,20 @@
table = [
[
Prefix (char '-' >> return (InitPrefixOp "-"))
+ ,Prefix (try (string "not") >> return (InitPrefixOp "not"))
]
, [ Infix (char '*' >> return (InitBinOp "*")) AssocLeft
, Infix (char '/' >> return (InitBinOp "/")) AssocLeft
, Infix (try (string "div") >> return (InitBinOp "div")) AssocLeft
, Infix (try (string "mod") >> return (InitBinOp "mod")) AssocLeft
+ , Infix (try $ string "and" >> return (InitBinOp "and")) AssocLeft
+ , Infix (try $ string "shl" >> return (InitBinOp "shl")) AssocNone
+ , Infix (try $ string "shr" >> return (InitBinOp "shr")) AssocNone
]
, [ Infix (char '+' >> return (InitBinOp "+")) AssocLeft
, Infix (char '-' >> return (InitBinOp "-")) AssocLeft
+ , Infix (try $ string "or" >> return (InitBinOp "or")) AssocLeft
+ , Infix (try $ string "xor" >> return (InitBinOp "xor")) AssocLeft
]
, [ Infix (try (string "<>") >> return (InitBinOp "<>")) AssocNone
, Infix (try (string "<=") >> return (InitBinOp "<=")) AssocNone
@@ -589,14 +610,14 @@
, Infix (char '>' >> return (InitBinOp ">")) AssocNone
, Infix (char '=' >> return (InitBinOp "=")) AssocNone
]
- , [ Infix (try $ string "and" >> return (InitBinOp "and")) AssocLeft
+ {--, [ Infix (try $ string "and" >> return (InitBinOp "and")) AssocLeft
, Infix (try $ string "or" >> return (InitBinOp "or")) AssocLeft
, Infix (try $ string "xor" >> return (InitBinOp "xor")) AssocLeft
]
, [ Infix (try $ string "shl" >> return (InitBinOp "shl")) AssocNone
, Infix (try $ string "shr" >> return (InitBinOp "shr")) AssocNone
- ]
- , [Prefix (try (string "not") >> return (InitPrefixOp "not"))]
+ ]--}
+ --, [Prefix (try (string "not") >> return (InitPrefixOp "not"))]
]
itypeCast = do
@@ -621,3 +642,14 @@
string "var"
v <- varsDecl True
return $ System (t ++ v)
+
+redoUnit = do
+ string "redo;"
+ comments
+ string "type"
+ comments
+ t <- typesDecl
+ string "var"
+ v <- varsDecl True
+ return $ Redo (t ++ v)
+
--- a/tools/PascalPreprocessor.hs Wed Jul 25 16:31:34 2012 +0400
+++ b/tools/PascalPreprocessor.hs Wed Jul 25 22:46:03 2012 +0400
@@ -18,6 +18,8 @@
initDefines = Map.fromList [
("FPC", "")
, ("PAS2C", "")
+ , ("ENDIAN_LITTLE", "")
+ , ("S3D_DISABLED", "")
]
preprocess :: String -> IO String
--- a/tools/PascalUnitSyntaxTree.hs Wed Jul 25 16:31:34 2012 +0400
+++ b/tools/PascalUnitSyntaxTree.hs Wed Jul 25 22:46:03 2012 +0400
@@ -7,6 +7,7 @@
Program Identifier Implementation Phrase
| Unit Identifier Interface Implementation (Maybe Initialize) (Maybe Finalize)
| System [TypeVarDeclaration]
+ | Redo [TypeVarDeclaration]
deriving Show
data Interface = Interface Uses TypesAndVars
deriving Show
@@ -48,7 +49,7 @@
| IfThenElse Expression Phrase (Maybe Phrase)
| WhileCycle Expression Phrase
| RepeatCycle Expression [Phrase]
- | ForCycle Identifier Expression Expression Phrase
+ | ForCycle Identifier Expression Expression Phrase Bool -- The last Boolean indicates wether it's up or down counting
| WithBlock Reference Phrase
| Phrases [Phrase]
| SwitchCase Expression [([InitExpression], Phrase)] (Maybe [Phrase])
--- a/tools/pas2c.hs Wed Jul 25 16:31:34 2012 +0400
+++ b/tools/pas2c.hs Wed Jul 25 22:46:03 2012 +0400
@@ -71,13 +71,14 @@
escapeChar :: Char -> ShowS
escapeChar '"' s = "\\\"" ++ s
+escapeChar '\\' s = "\\\\" ++ s
escapeChar a s = a : s
strInit :: String -> Doc
strInit a = text "STRINIT" <> parens (doubleQuotes (text $ escapeStr a))
renderStringConsts :: State RenderState Doc
-renderStringConsts = liftM (vcat . map (\(a, b) -> text "const string255" <+> (text a) <+> text "=" <+> strInit b <> semi))
+renderStringConsts = liftM (vcat . map (\(a, b) -> text "static const string255" <+> (text a) <+> text "=" <+> strInit b <> semi))
$ gets stringConsts
docToLower :: Doc -> Doc
@@ -132,10 +133,16 @@
where
f = do
checkDuplicateFunDecls tvs
- mapM_ (tvar2C True) tvs
+ mapM_ (tvar2C True False True False) tvs
+ toNamespace nss (Redo tvs) = -- functions that are re-implemented, add prefix to all of them
+ currentScope $ execState f (emptyState nss){currentUnit = "fpcrtl_"}
+ where
+ f = do
+ checkDuplicateFunDecls tvs
+ mapM_ (tvar2C True False True False) tvs
toNamespace _ (Program {}) = Map.empty
toNamespace nss (Unit (Identifier i _) interface _ _ _) =
- currentScope $ execState (interface2C interface) (emptyState nss){currentUnit = map toLower i ++ "_"}
+ currentScope $ execState (interface2C interface True) (emptyState nss){currentUnit = map toLower i ++ "_"}
withState' :: (RenderState -> RenderState) -> State RenderState a -> State RenderState a
@@ -149,7 +156,6 @@
})
return a
-withLastIdNamespace :: State RenderState Doc -> State RenderState Doc
withLastIdNamespace f = do
li <- gets lastIdentifier
nss <- gets namespaces
@@ -165,49 +171,57 @@
toCFiles :: Map.Map String Records -> (String, PascalUnit) -> IO ()
toCFiles _ (_, System _) = return ()
+toCFiles _ (_, Redo _) = return ()
toCFiles ns p@(fn, pu) = do
hPutStrLn stdout $ "Rendering '" ++ fn ++ "'..."
toCFiles' p
where
- toCFiles' (fn, p@(Program {})) = writeFile (fn ++ ".c") $ (render2C initialState . pascal2C) p
+ toCFiles' (fn, p@(Program {})) = writeFile (fn ++ ".c") $ "#include \"fpcrtl.h\"\n" ++ (render2C initialState . pascal2C) p
toCFiles' (fn, (Unit unitId@(Identifier i _) interface implementation _ _)) = do
- let (a, s) = runState (id2C IOInsert (setBaseType BTUnit unitId) >> interface2C interface) initialState{currentUnit = map toLower i ++ "_"}
+ let (a, s) = runState (id2C IOInsert (setBaseType BTUnit unitId) >> interface2C interface True) initialState{currentUnit = map toLower i ++ "_"}
+ (a', s') = runState (id2C IOInsert (setBaseType BTUnit unitId) >> interface2C interface False) initialState{currentUnit = map toLower i ++ "_"}
writeFile (fn ++ ".h") $ "#pragma once\n\n#include \"pas2c.h\"\n\n" ++ (render (a $+$ text ""))
- writeFile (fn ++ ".c") $ "#include \"" ++ fn ++ ".h\"\n" ++ (render2C s . implementation2C) implementation
+ writeFile (fn ++ ".c") $ "#include \"fpcrtl.h\"\n\n#include \"" ++ fn ++ ".h\"\n" ++ render (a' $+$ text "") ++ (render2C s . implementation2C) implementation
initialState = emptyState ns
render2C :: RenderState -> State RenderState Doc -> String
render2C a = render . ($+$ empty) . flip evalState a
+
usesFiles :: PascalUnit -> [String]
-usesFiles (Program _ (Implementation uses _) _) = "pas2cSystem" : uses2List uses
-usesFiles (Unit _ (Interface uses1 _) (Implementation uses2 _) _ _) = "pas2cSystem" : uses2List uses1 ++ uses2List uses2
+usesFiles (Program _ (Implementation uses _) _) = ["pas2cSystem", "pas2cRedo"] ++ uses2List uses
+usesFiles (Unit _ (Interface uses1 _) (Implementation uses2 _) _ _) = ["pas2cSystem", "pas2cRedo"] ++ uses2List uses1 ++ uses2List uses2
usesFiles (System {}) = []
-
+usesFiles (Redo {}) = []
pascal2C :: PascalUnit -> State RenderState Doc
pascal2C (Unit _ interface implementation init fin) =
- liftM2 ($+$) (interface2C interface) (implementation2C implementation)
+ liftM2 ($+$) (interface2C interface True) (implementation2C implementation)
pascal2C (Program _ implementation mainFunction) = do
impl <- implementation2C implementation
- [main] <- tvar2C True
- (FunctionDeclaration (Identifier "main" BTInt) (SimpleType $ Identifier "int" BTInt) [] (Just (TypesAndVars [], mainFunction)))
+ [main] <- tvar2C True False True True (FunctionDeclaration (Identifier "main" BTInt) (SimpleType $ Identifier "int" BTInt) [VarDeclaration False False ([Identifier "argc" BTInt], SimpleType (Identifier "Integer" BTInt)) Nothing, VarDeclaration False False ([Identifier "argv" BTUnknown], SimpleType (Identifier "PPChar" BTUnknown)) Nothing] (Just (TypesAndVars [], mainFunction)))
return $ impl $+$ main
-
-interface2C :: Interface -> State RenderState Doc
-interface2C (Interface uses tvars) = do
+-- the second bool indicates whether do normal interface translation or generate variable declarations
+-- that will be inserted into implementation files
+interface2C :: Interface -> Bool -> State RenderState Doc
+interface2C (Interface uses tvars) True = do
u <- uses2C uses
- tv <- typesAndVars2C True tvars
+ tv <- typesAndVars2C True True True tvars
r <- renderStringConsts
return (u $+$ r $+$ tv)
+interface2C (Interface uses tvars) False = do
+ u <- uses2C uses
+ tv <- typesAndVars2C True False False tvars
+ r <- renderStringConsts
+ return tv
implementation2C :: Implementation -> State RenderState Doc
implementation2C (Implementation uses tvars) = do
u <- uses2C uses
- tv <- typesAndVars2C True tvars
+ tv <- typesAndVars2C True False True tvars
r <- renderStringConsts
return (u $+$ r $+$ tv)
@@ -220,17 +234,22 @@
ins (FunctionDeclaration (Identifier i _) _ _ _) m = Map.insertWith (+) (map toLower i) 1 m
ins _ m = m
-typesAndVars2C :: Bool -> TypesAndVars -> State RenderState Doc
-typesAndVars2C b (TypesAndVars ts) = do
+-- the second bool indicates whether declare variable as extern or not
+-- the third bool indicates whether include types or not
+
+typesAndVars2C :: Bool -> Bool -> Bool -> TypesAndVars -> State RenderState Doc
+typesAndVars2C b externVar includeType(TypesAndVars ts) = do
checkDuplicateFunDecls ts
- liftM (vcat . map (<> semi) . concat) $ mapM (tvar2C b) ts
+ liftM (vcat . map (<> semi) . concat) $ mapM (tvar2C b externVar includeType False) ts
setBaseType :: BaseType -> Identifier -> Identifier
setBaseType bt (Identifier i _) = Identifier i bt
uses2C :: Uses -> State RenderState Doc
uses2C uses@(Uses unitIds) = do
+
mapM_ injectNamespace (Identifier "pas2cSystem" undefined : unitIds)
+ mapM_ injectNamespace (Identifier "pas2cRedo" undefined : unitIds)
mapM_ (id2C IOInsert . setBaseType BTUnit) unitIds
return $ vcat . map (\i -> text $ "#include \"" ++ i ++ ".h\"") $ uses2List uses
where
@@ -256,6 +275,7 @@
return $ text i'
where
n = map toLower i
+
id2C IOLookup i = id2CLookup head i
id2C IOLookupLast i = id2CLookup last i
id2C (IOLookupFunction params) (Identifier i t) = do
@@ -279,7 +299,7 @@
let vv = head $ fromJust v in modify (\s -> s{lastType = snd vv, lastIdentifier = fst vv}) >> (return . text . fst $ vv)
id2CLookup :: ([Record] -> Record) -> Identifier -> State RenderState Doc
-id2CLookup f (Identifier i _) = do
+id2CLookup f (Identifier i t) = do
let i' = map toLower i
v <- gets $ Map.lookup i' . currentScope
lt <- gets lastType
@@ -363,7 +383,7 @@
error $ "Dereferencing from non-pointer type " ++ show t ++ "\n" ++ s
-functionParams2C params = liftM (hcat . punctuate comma . concat) $ mapM (tvar2C False) params
+functionParams2C params = liftM (hcat . punctuate comma . concat) $ mapM (tvar2C False False True True) params
numberOfDeclarations :: [TypeVarDeclaration] -> Int
numberOfDeclarations = sum . map cnt
@@ -421,12 +441,15 @@
(p, ph) <- withState' (\st -> st{currentScope = Map.insertWith un (map toLower rv) [(render res, t')] $ currentScope st
, currentFunctionResult = if isVoid then [] else render res}) $ do
p <- functionParams2C params
- ph <- liftM2 ($+$) (typesAndVars2C False tvars) (phrase2C' phrase)
+ ph <- liftM2 ($+$) (typesAndVars2C False False True tvars) (phrase2C' phrase)
return (p, ph)
let phrasesBlock = if isVoid then ph else t empty <+> res <> semi $+$ ph $+$ text "return" <+> res <> semi
-
- return [(if notDeclared && hasVars then funWithVarsToDefine n params else empty) $+$
+ let define = if hasVars then text "#ifndef" <+> text n $+$ funWithVarsToDefine n params $+$ text "#endif" else empty
+ return [
+ define
+ $+$
+ --(if notDeclared && hasVars then funWithVarsToDefine n params else empty) $+$
t empty <+> text (if hasVars then n ++ "__vars" else n) <> parens p
$+$
text "{"
@@ -443,37 +466,69 @@
fun2C False _ (FunctionDeclaration (Identifier name _) _ _ _) = error $ "nested functions not allowed: " ++ name
fun2C _ tv _ = error $ "fun2C: I don't render " ++ show tv
-tvar2C :: Bool -> TypeVarDeclaration -> State RenderState [Doc]
-tvar2C b f@(FunctionDeclaration (Identifier name _) _ _ _) =
- fun2C b name f
-tvar2C _ td@(TypeDeclaration i' t) = do
+-- the second bool indicates whether declare variable as extern or not
+-- the third bool indicates whether include types or not
+-- the fourth bool indicates whether ignore initialization or not (basically for dynamic arrays since we cannot do initialization in function params)
+tvar2C :: Bool -> Bool -> Bool -> Bool -> TypeVarDeclaration -> State RenderState [Doc]
+tvar2C b _ includeType _ f@(FunctionDeclaration (Identifier name _) _ _ _) = do
+ t <- fun2C b name f
+ if includeType then return t else return []
+tvar2C _ _ includeType _ td@(TypeDeclaration i' t) = do
i <- id2CTyped t i'
tp <- type2C t
- return [text "typedef" <+> tp i]
+ return $ if includeType then [text "typedef" <+> tp i] else []
-tvar2C _ (VarDeclaration True _ (ids, t) Nothing) = do
+tvar2C _ _ _ _ (VarDeclaration True _ (ids, t) Nothing) = do
t' <- liftM ((empty <+>) . ) $ type2C t
liftM (map(\i -> t' i)) $ mapM (id2CTyped (VarParamType t)) ids
-tvar2C _ (VarDeclaration _ isConst (ids, t) mInitExpr) = do
- t' <- liftM (((if isConst then text "const" else empty) <+>) . ) $ type2C t
+tvar2C _ externVar includeType ignoreInit (VarDeclaration _ isConst (ids, t) mInitExpr) = do
+ t' <- liftM (((if isConst then text "static const" else if externVar
+ then text "extern"
+ else empty)
+ <+>) . ) $ type2C t
ie <- initExpr mInitExpr
lt <- gets lastType
case (isConst, lt, ids, mInitExpr) of
(True, BTInt, [i], Just _) -> do
i' <- id2CTyped t i
- return [text "enum" <> braces (i' <+> ie)]
+ return $ if includeType then [text "enum" <> braces (i' <+> ie)] else []
(True, BTFloat, [i], Just e) -> do
i' <- id2CTyped t i
ie <- initExpr2C e
- return [text "#define" <+> i' <+> parens ie <> text "\n"]
+ return $ if includeType then [text "#define" <+> i' <+> parens ie <> text "\n"] else []
(_, BTFunction{}, _, Nothing) -> liftM (map(\i -> t' i)) $ mapM (id2CTyped t) ids
- _ -> liftM (map(\i -> t' i <+> ie)) $ mapM (id2CTyped t) ids
+ (_, BTArray r _ _, [i], _) -> do
+ i' <- id2CTyped t i
+ ie' <- return $ case (r, mInitExpr, ignoreInit) of
+ (RangeInfinite, Nothing, False) -> text "= NULL" -- force dynamic array to be initialized as NULL if not initialized at all
+ (_, _, _) -> ie
+ result <- liftM (map(\i -> varDeclDecision isConst includeType (t' i) ie')) $ mapM (id2CTyped t) ids
+ case (r, ignoreInit) of
+ (RangeInfinite, False) ->
+ -- if the array is dynamic, add dimension info to it
+ return $ [dimDecl] ++ result
+ where
+ arrayDimStr = show $ arrayDimension t
+ arrayDimInitExp = text ("={" ++ ".dim = " ++ arrayDimStr ++ ", .a = {0, 0, 0, 0}}")
+ dimDecl = varDeclDecision isConst includeType (text "fpcrtl_dimension_t" <+> i' <> text "_dimension_info") arrayDimInitExp
+
+ (_, _) -> return result
+
+ _ -> liftM (map(\i -> varDeclDecision isConst includeType (t' i) ie)) $ mapM (id2CTyped t) ids
where
initExpr Nothing = return $ empty
initExpr (Just e) = liftM (text "=" <+>) (initExpr2C e)
+ varDeclDecision True True varStr expStr = varStr <+> expStr
+ varDeclDecision False True varStr expStr = if externVar then varStr else varStr <+> expStr
+ varDeclDecision False False varStr expStr = varStr <+> expStr
+ varDeclDecision True False varStr expStr = empty
+ arrayDimension a = case a of
+ ArrayDecl Nothing t -> let a = arrayDimension t in if a > 3 then error "Dynamic array with dimension > 4 is not supported." else 1 + arrayDimension t
+ ArrayDecl _ _ -> error "Mixed dynamic array and static array are not supported."
+ _ -> 0
-tvar2C f (OperatorDeclaration op (Identifier i _) ret params body) = do
+tvar2C f _ _ _ (OperatorDeclaration op (Identifier i _) ret params body) = do
r <- op2CTyped op (extractTypes params)
fun2C f i (FunctionDeclaration r ret params body)
@@ -489,6 +544,7 @@
"-" -> "sub"
"*" -> "mul"
"/" -> "div"
+ "/(float)" -> "div"
"=" -> "eq"
"<" -> "lt"
">" -> "gt"
@@ -591,7 +647,7 @@
_ -> return $ \a -> i' <+> text "*" <+> a
type2C' (PointerTo t) = liftM (\t a -> t (parens $ text "*" <> a)) $ type2C t
type2C' (RecordType tvs union) = do
- t <- withState' f $ mapM (tvar2C False) tvs
+ t <- withState' f $ mapM (tvar2C False False True False) tvs
u <- unions
return $ \i -> text "struct __" <> i <+> lbrace $+$ nest 4 ((vcat . map (<> semi) . concat $ t) $$ u) $+$ rbrace <+> i
where
@@ -602,7 +658,7 @@
structs <- mapM struct2C a
return $ text "union" $+$ braces (nest 4 $ vcat structs) <> semi
struct2C tvs = do
- t <- withState' f $ mapM (tvar2C False) tvs
+ t <- withState' f $ mapM (tvar2C False False True False) tvs
return $ text "struct" $+$ braces (nest 4 (vcat . map (<> semi) . concat $ t)) <> semi
type2C' (RangeType r) = return (text "int" <+>)
type2C' (Sequence ids) = do
@@ -615,7 +671,7 @@
t' <- type2C t
lt <- gets lastType
ft <- case lt of
- BTFunction {} -> type2C (PointerTo t)
+ -- BTFunction {} -> type2C (PointerTo t)
_ -> return t'
r' <- initExpr2C (InitRange r)
return $ \i -> ft i <> brackets r'
@@ -675,15 +731,26 @@
e <- expr2C expr
return $ r <+> text "=" <+> e <> semi
_ -> error $ "Assignment to string from " ++ show lt
- (BTArray _ _ _, _) -> phrase2C $
- ProcCall (FunCall
- [
- Reference $ Address ref
- , Reference $ Address $ RefExpression expr
- , Reference $ FunCall [expr] (SimpleReference (Identifier "sizeof" BTUnknown))
- ]
- (SimpleReference (Identifier "memcpy" BTUnknown))
- ) []
+ (BTArray _ _ _, _) -> do
+ case expr of
+ Reference er -> do
+ exprRef <- ref2C er
+ exprT <- gets lastType
+ case exprT of
+ BTArray RangeInfinite _ _ ->
+ return $ text "FIXME: assign a dynamic array to an array"
+ BTArray _ _ _ -> phrase2C $
+ ProcCall (FunCall
+ [
+ Reference $ ref
+ , Reference $ RefExpression expr
+ , Reference $ FunCall [expr] (SimpleReference (Identifier "sizeof" BTUnknown))
+ ]
+ (SimpleReference (Identifier "memcpy" BTUnknown))
+ ) []
+ _ -> return $ text "FIXME: assign a non-specific value to an array"
+
+ _ -> return $ text "FIXME: dynamic array assignment 2"
_ -> do
e <- expr2C expr
return $ r <+> text "=" <+> e <> semi
@@ -704,7 +771,7 @@
ph <- phrase2C p
return $
vcat (map (\i -> text "case" <+> i <> colon) . concat $ ies) <> nest 4 (ph $+$ text "break;")
- dflt | isNothing mphrase = return []
+ dflt | isNothing mphrase = return [text "default: break;"] -- avoid compiler warning
| otherwise = do
ph <- mapM phrase2C $ fromJust mphrase
return [text "default:" <+> nest 4 (vcat ph)]
@@ -716,13 +783,15 @@
(BTRecord _ rs) -> withRecordNamespace (render r ++ ".") rs $ phrase2C $ wrapPhrase p
a -> do
error $ "'with' block referencing non-record type " ++ show a ++ "\n" ++ show wb
-phrase2C (ForCycle i' e1' e2' p) = do
+phrase2C (ForCycle i' e1' e2' p up) = do
i <- id2C IOLookup i'
e1 <- expr2C e1'
e2 <- expr2C e2'
ph <- phrase2C (wrapPhrase p)
+ cmp <- return $ if up == True then "<=" else ">="
+ inc <- return $ if up == True then "++" else "--"
return $
- text "for" <> (parens . hsep . punctuate (char ';') $ [i <+> text "=" <+> e1, i <+> text "<=" <+> e2, text "++" <> i])
+ text "for" <> (parens . hsep . punctuate (char ';') $ [i <+> text "=" <+> parens e1, i <+> text cmp <+> parens e2, text inc <> i])
$$
ph
phrase2C (RepeatCycle e' p') = do
@@ -777,12 +846,23 @@
case expr2 of
SetExpression set -> do
ids <- mapM (id2C IOLookup) set
+ modify(\s -> s{lastType = BTBool})
return . parens . hcat . punctuate (text " || ") . map (\i -> parens $ e1 <+> text "==" <+> i) $ ids
_ -> error "'in' against not set expression"
(o, _, _) | o `elem` boolOps -> do
modify(\s -> s{lastType = BTBool})
return $ parens e1 <+> text o <+> parens e2
- | otherwise -> return $ parens e1 <+> text o <+> parens e2
+ | otherwise -> do
+ o' <- return $ case o of
+ "/(float)" -> text "/(float)" -- pascal returns real value
+ _ -> text o
+ e1' <- return $ case (o, t1, t2) of
+ ("-", BTInt, BTInt) -> parens $ text "(int64_t)" <+> parens e1
+ _ -> parens e1
+ e2' <- return $ case (o, t1, t2) of
+ ("-", BTInt, BTInt) -> parens $ text "(int64_t)" <+> parens e2
+ _ -> parens e2
+ return $ e1' <+> o' <+> e2'
where
boolOps = ["==", "!=", "<", ">", "<=", ">="]
expr2C (NumberLiteral s) = do
@@ -806,7 +886,12 @@
BTRecord t _ -> do
i <- op2CTyped op [SimpleType (Identifier t undefined)]
ref2C $ FunCall [expr] (SimpleReference i)
- _ -> return $ text (op2C op) <> e
+ BTBool -> do
+ o <- return $ case op of
+ "not" -> text "!"
+ _ -> text (op2C op)
+ return $ o <> parens e
+ _ -> return $ text (op2C op) <> parens e
expr2C Null = return $ text "NULL"
expr2C (CharCode a) = do
modify(\s -> s{lastType = BTChar})
@@ -835,13 +920,13 @@
_ -> error $ "BuiltInFunCall 'high' from " ++ show e ++ "\ntype: " ++ show lt
expr2C (BuiltInFunCall [e] (SimpleReference (Identifier "ord" _))) = liftM parens $ expr2C e
expr2C (BuiltInFunCall [e] (SimpleReference (Identifier "succ" _))) = liftM (<> text " + 1") $ expr2C e
-expr2C (BuiltInFunCall [e] (SimpleReference (Identifier "pred" _))) = liftM (<> text " - 1") $ expr2C e
+expr2C (BuiltInFunCall [e] (SimpleReference (Identifier "pred" _))) = liftM (<> text " - (int64_t)1") $ expr2C e
expr2C (BuiltInFunCall [e] (SimpleReference (Identifier "length" _))) = do
e' <- expr2C e
lt <- gets lastType
modify (\s -> s{lastType = BTInt})
case lt of
- BTString -> return $ text "Length" <> parens e'
+ BTString -> return $ text "fpcrtl_Length" <> parens e'
BTArray RangeInfinite _ _ -> error $ "length() called on variable size array " ++ show e'
BTArray (RangeFromTo _ n) _ _ -> initExpr2C (BuiltInFunction "succ" [n])
_ -> error $ "length() called on " ++ show lt
@@ -864,7 +949,7 @@
case t of
BTFunction _ _ rt -> do
modify(\s -> s{lastType = rt})
- return $ i <> parens empty
+ return $ i <> parens empty --xymeng: removed parens
_ -> return $ i
ref2CF r@(RecordField (SimpleReference _) (SimpleReference _)) = do
i <- ref2C r
@@ -962,7 +1047,7 @@
op2C :: String -> String
op2C "or" = "|"
op2C "and" = "&"
-op2C "not" = "!"
+op2C "not" = "~"
op2C "xor" = "^"
op2C "div" = "/"
op2C "mod" = "%"
@@ -970,5 +1055,6 @@
op2C "shr" = ">>"
op2C "<>" = "!="
op2C "=" = "=="
+op2C "/" = "/(float)"
op2C a = a