Skip to content

Commit 1b1efd2

Browse files
authored
Merge pull request #30 from arnaud-m/addAnd
Add AND #22
2 parents b09bb04 + 2db2abd commit 1b1efd2

File tree

10 files changed

+1229
-883
lines changed

10 files changed

+1229
-883
lines changed

src/main/antlr4/Cryptator.g4

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,15 @@ import cryptator.tree.CryptaLeaf;
1212

1313
// Parser Rules
1414

15-
program : equation EOF{}; //additional token to simplify the passage in parameter
15+
program : equations EOF{}; //additional token to simplify the passage in parameter
1616

17-
equation returns [ICryptaNode node]: //create a node of the tree corresponding to an equation and return this node
18-
'(' equation ')' {$node=$equation.node;}
19-
| left=expression COMPARATOR right=expression {$node=new CryptaNode($COMPARATOR.getText(), $left.node, $right.node);};
17+
equations returns [ICryptaNode node] //create a node of conjuncts
18+
: equation (AND*) {$node=$equation.node;}
19+
| e1=equation (AND+) e2=equations (AND*) {$node=new CryptaNode($AND.getText(), $e1.node, $e2.node);};
20+
21+
equation returns [ICryptaNode node] //create a node of the tree corresponding to an equation and return this node
22+
: '(' equation ')' {$node=$equation.node;}
23+
| left=expression COMPARATOR right=expression {$node=new CryptaNode($COMPARATOR.getText(), $left.node, $right.node);};
2024

2125

2226
expression returns [ICryptaNode node]: //create recursively the tree of expressions with priority and return the root of the tree
@@ -46,3 +50,4 @@ SYMBOL : [a-zA-Z0-9\u0080-\uFFFF] {};
4650

4751
WHITESPACE : ( '\t' | ' ' | '\r' | '\n'| '\u000C' )+ -> skip ;
4852

53+
AND : ';';

src/main/java/cryptator/CryptaOperator.java

Lines changed: 63 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -8,81 +8,84 @@
88
*/
99
package cryptator;
1010

11-
import java.math.BigInteger;
12-
import java.util.function.BinaryOperator;
13-
1411
import org.chocosolver.solver.expression.discrete.arithmetic.ArExpression;
12+
import org.chocosolver.solver.expression.discrete.relational.ReExpression;
1513
import org.chocosolver.solver.variables.IntVar;
1614
import org.chocosolver.util.tools.VariableUtils;
1715

16+
import java.math.BigInteger;
17+
import java.util.function.BinaryOperator;
18+
1819
/**
1920
* @see https://en.wikipedia.org/wiki/Relational_operator
2021
*/
2122
public enum CryptaOperator {
22-
ADD("+", (a, b) -> a.add(b), (a, b) -> a.add(b)),
23-
SUB("-", (a, b) -> a.subtract(b), (a, b) -> a.sub(b)),
24-
MUL("*", (a, b) -> a.multiply(b), (a, b) -> a.mul(b)),
25-
DIV("//", (a, b) -> a.divide(b), (a, b) -> a.div(b)),
26-
FDIV("/", (a, b) -> fdiv(a, b), (a, b) -> fdiv(a, b)),
27-
MOD("%", (a, b) -> a.mod(b), (a, b) -> a.mod(b)),
28-
POW("^", (a, b) -> a.pow(b.intValue()), (a, b) -> a.pow(b)),
29-
ID("", (a, b) -> BigInteger.ZERO, (a, b) -> null),
30-
EQ("=", (a, b) -> toBigInt(a.compareTo(b) == 0), (a, b) -> a.eq(b)),
31-
NE("!=", (a, b) -> toBigInt(a.compareTo(b) != 0), (a, b) -> a.ne(b)),
32-
LT("<", (a, b) -> toBigInt(a.compareTo(b) < 0), (a, b) -> a.lt(b)),
33-
GT(">", (a, b) -> toBigInt(a.compareTo(b) > 0), (a, b) -> a.gt(b)),
34-
LE("<=", (a, b) -> toBigInt(a.compareTo(b) <= 0), (a, b) -> a.le(b)),
35-
GE(">=", (a, b) -> toBigInt(a.compareTo(b) >= 0), (a, b) -> a.ge(b));
23+
ADD("+", (a, b) -> a.add(b), (a, b) -> a.add(b)),
24+
SUB("-", (a, b) -> a.subtract(b), (a, b) -> a.sub(b)),
25+
MUL("*", (a, b) -> a.multiply(b), (a, b) -> a.mul(b)),
26+
DIV("//", (a, b) -> a.divide(b), (a, b) -> a.div(b)),
27+
FDIV("/", (a, b) -> fdiv(a, b), (a, b) -> fdiv(a, b)),
28+
MOD("%", (a, b) -> a.mod(b), (a, b) -> a.mod(b)),
29+
POW("^", (a, b) -> a.pow(b.intValue()), (a, b) -> a.pow(b)),
30+
ID("", (a, b) -> BigInteger.ZERO, (a, b) -> null),
31+
EQ("=", (a, b) -> toBigInt(a.compareTo(b) == 0), (a, b) -> a.eq(b)),
32+
NE("!=", (a, b) -> toBigInt(a.compareTo(b) != 0), (a, b) -> a.ne(b)),
33+
LT("<", (a, b) -> toBigInt(a.compareTo(b) < 0), (a, b) -> a.lt(b)),
34+
GT(">", (a, b) -> toBigInt(a.compareTo(b) > 0), (a, b) -> a.gt(b)),
35+
LE("<=", (a, b) -> toBigInt(a.compareTo(b) <= 0), (a, b) -> a.le(b)),
36+
GE(">=", (a, b) -> toBigInt(a.compareTo(b) >= 0), (a, b) -> a.ge(b)),
37+
38+
AND(";", (a, b) -> toBigInt(!a.equals(BigInteger.ZERO) && !b.equals(BigInteger.ZERO)), (a, b) -> ((ReExpression) a).and((ReExpression) b));
39+
40+
public final String token;
41+
42+
public final BinaryOperator<BigInteger> function;
3643

37-
public final String token;
44+
public final BinaryOperator<ArExpression> expression;
3845

39-
public final BinaryOperator<BigInteger> function;
46+
CryptaOperator(String token, BinaryOperator<BigInteger> function, BinaryOperator<ArExpression> expression) {
47+
this.token = token;
48+
this.function = function;
49+
this.expression = expression;
50+
}
4051

41-
public final BinaryOperator<ArExpression> expression;
52+
public static CryptaOperator valueOfToken(String token) {
53+
if (token == null) return null;
54+
for (CryptaOperator operator : CryptaOperator.values()) {
55+
if (token.equals(operator.getToken())) return operator;
56+
}
57+
throw new IllegalArgumentException("Unknown token: " + token);
58+
}
4259

43-
private CryptaOperator(String token, BinaryOperator<BigInteger> function, BinaryOperator<ArExpression> expression) {
44-
this.token = token;
45-
this.function = function;
46-
this.expression = expression;
47-
}
60+
private static final BigInteger toBigInt(boolean b) {
61+
return b ? BigInteger.ONE : BigInteger.ZERO;
62+
}
4863

49-
public final String getToken() {
50-
return token;
51-
}
64+
private static final BigInteger fdiv(BigInteger a, BigInteger b) {
65+
final BigInteger[] r = a.divideAndRemainder(b);
66+
if (r[1].equals(BigInteger.ZERO)) return r[0];
67+
else throw new ArithmeticException("The remainder of the division is non-zero.");
68+
}
5269

53-
public final BinaryOperator<BigInteger> getFunction() {
54-
return function;
55-
}
70+
private static final ArExpression fdiv(ArExpression a, ArExpression b) {
71+
final IntVar va = a.intVar();
72+
final IntVar vb = b.intVar();
73+
final int[] bounds = VariableUtils.boundsForDivision(va, vb);
74+
final IntVar q = a.getModel().intVar(bounds[0], bounds[1]);
75+
// Post auxiliary constraint to emulate floor division.
76+
q.mul(b).eq(a).post();
77+
return q;
78+
}
5679

57-
public final BinaryOperator<ArExpression> getExpression() {
58-
return expression;
59-
}
80+
public final String getToken() {
81+
return token;
82+
}
6083

61-
public static CryptaOperator valueOfToken(String token) {
62-
if(token == null) return null;
63-
for(CryptaOperator operator : CryptaOperator.values()) {
64-
if(token.equals(operator.getToken())) return operator;
65-
}
66-
throw new IllegalArgumentException("Unknown token: " + token);
67-
}
68-
69-
private static final BigInteger toBigInt(boolean b) {
70-
return b ? BigInteger.ONE : BigInteger.ZERO;
71-
}
84+
public final BinaryOperator<BigInteger> getFunction() {
85+
return function;
86+
}
7287

73-
private static final BigInteger fdiv(BigInteger a, BigInteger b) {
74-
final BigInteger[] r = a.divideAndRemainder(b);
75-
if(r[1].equals(BigInteger.ZERO)) return r[0];
76-
else throw new ArithmeticException("The remainder of the division is non-zero.");
77-
}
78-
79-
private static final ArExpression fdiv(ArExpression a, ArExpression b) {
80-
final IntVar va = a.intVar();
81-
final IntVar vb = b.intVar();
82-
final int[] bounds = VariableUtils.boundsForDivision(va, vb);
83-
final IntVar q = a.getModel().intVar(bounds[0], bounds[1]);
84-
// Post auxiliary constraint to emulate floor division.
85-
q.mul(b).eq(a).post();
86-
return q;
87-
}
88+
public final BinaryOperator<ArExpression> getExpression() {
89+
return expression;
90+
}
8891
}

src/main/java/cryptator/parser/CryptaParserWrapper.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,16 @@
99
package cryptator.parser;
1010

1111

12+
import cryptator.specs.ICryptaNode;
13+
import cryptator.specs.ICryptaParser;
1214
import org.antlr.v4.runtime.CharStream;
1315
import org.antlr.v4.runtime.CharStreams;
1416
import org.antlr.v4.runtime.CommonTokenStream;
1517

16-
import cryptator.specs.ICryptaNode;
17-
import cryptator.specs.ICryptaParser;
18-
1918
public class CryptaParserWrapper implements ICryptaParser {
2019

21-
@Override
22-
public ICryptaNode parse(final String cryptarithm) throws CryptaParserException {
20+
@Override
21+
public ICryptaNode parse(final String cryptarithm) throws CryptaParserException {
2322
final CharStream input = CharStreams.fromString(cryptarithm);
2423
final CryptatorLexer lexer = new CryptatorLexer(input);
2524
lexer.removeErrorListeners();
@@ -30,7 +29,7 @@ public ICryptaNode parse(final String cryptarithm) throws CryptaParserException
3029
parser.removeErrorListeners();
3130
parser.addErrorListener(ThrowingErrorListener.INSTANCE);
3231
cryptator.parser.CryptatorParser.ProgramContext ctx = parser.program();
33-
return ctx.equation().node;
32+
return ctx.equations().node;
3433
}
3534

3635
}

src/main/java/cryptator/solver/CryptaBignumModeler.java

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@
99
package cryptator.solver;
1010

1111
import java.util.ArrayDeque;
12+
import java.util.Arrays;
1213
import java.util.Deque;
1314

1415
import org.chocosolver.solver.Model;
1516
import org.chocosolver.solver.expression.discrete.arithmetic.ArExpression;
17+
import org.chocosolver.solver.expression.discrete.relational.ReExpression;
1618
import org.chocosolver.solver.variables.IntVar;
1719

1820
import cryptator.CryptaOperator;
@@ -73,7 +75,7 @@ private final ArExpression[] applyADD(ArExpression[] a, ArExpression[] b) {
7375
c[i] = b[i];
7476
}
7577
return c;
76-
}
78+
}
7779

7880
class BignumArExpression {
7981

@@ -86,7 +88,6 @@ public BignumArExpression(ArExpression[] a, int n, String suffix) {
8688
digits = model.intVarArray("D" + suffix, n, 0, config.getArithmeticBase()-1);
8789
// TODO improve the bound ?
8890
carries = model.intVarArray("C"+ suffix, n, 0, IntVar.MAX_INT_BOUND / config.getArithmeticBase());
89-
// TODO Is it better to use scalar or an expression ?
9091
postScalar(
9192
new IntVar[] {carries[0], digits[0], a[0].intVar()},
9293
new int[] {config.getArithmeticBase(), 1, -1}
@@ -121,27 +122,32 @@ private final void applyEQ(ArExpression[] a, ArExpression[] b) {
121122
a1.digits[i].eq(b1.digits[i]).decompose().post();
122123
}
123124
a1.carries[n-1].eq(b1.carries[n-1]).decompose().post();
124-
}
125125

126+
}
126127

127128
@Override
128129
public void accept(ICryptaNode node, int numNode) {
129130
super.accept(node, numNode);
130-
if(node.isLeaf()) {
131+
if(node.isLeaf()) {
131132
stack.push(makeWordVars(node.getWord()));
132-
} else {
133+
} else if (!node.getOperator().equals(CryptaOperator.AND)) {
133134
final ArExpression[] b = stack.pop();
134135
final ArExpression[] a = stack.pop();
135136
switch (node.getOperator()) {
136137
case ADD:
137138
stack.push(applyADD(a, b));
138139
break;
139-
case EQ:
140+
case EQ:
140141
applyEQ(a, b);
142+
if(!stack.isEmpty()) throw new IllegalStateException("Stack is not empty after accepting a relational operator.");
141143
break;
142144
default:
143-
break;
144-
}
145+
// Should never be in the default case, this exception is
146+
// a program break in order to recall to modify the switch if
147+
// a new operator in BigNum is added.
148+
// Example case : we remove the MUL operator in computeUnsupportedBignumOperator
149+
throw new IllegalStateException("Bignum operator is not yet implemented");
150+
}
145151
}
146152
}
147153

0 commit comments

Comments
 (0)