diff --git a/.gitignore b/.gitignore
index 21cc758a806c9378f9087be9df7e86c57a6c1137..6fb050f33df6f21162c8152feb2c2b9d7e8bb16b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -147,3 +147,7 @@ tramp
 Session.vim
 .netrwhist
 *~
+
+### recolic
+*.gi
+
diff --git a/src/main/java/chocopy/pa2/DeclarationAnalyzer.java b/src/main/java/chocopy/pa2/DeclarationAnalyzer.java
index 24eebdc58a457f77ed8364d90457c5e2055eff5b..92f02035d7cb4fad52e77efeb6bf4c488ea2415c 100644
--- a/src/main/java/chocopy/pa2/DeclarationAnalyzer.java
+++ b/src/main/java/chocopy/pa2/DeclarationAnalyzer.java
@@ -4,11 +4,9 @@ import chocopy.common.analysis.AbstractNodeAnalyzer;
 import chocopy.common.analysis.SymbolTable;
 import chocopy.common.analysis.types.SymbolType;
 import chocopy.common.analysis.types.ValueType;
-import chocopy.common.astnodes.Declaration;
-import chocopy.common.astnodes.Errors;
-import chocopy.common.astnodes.Identifier;
-import chocopy.common.astnodes.Program;
-import chocopy.common.astnodes.VarDef;
+import chocopy.common.astnodes.*;
+
+import javax.management.RuntimeErrorException;
 
 /**
  * Analyzes declarations to create a top-level symbol table.
@@ -59,7 +57,78 @@ public class DeclarationAnalyzer extends AbstractNodeAnalyzer<SymbolType> {
 
     @Override
     public SymbolType analyze(VarDef varDef) {
-        return ValueType.annotationToValueType(varDef.var.type);
+        return analyze(varDef.var);
+    }
+
+    @Override
+    public SymbolType analyze(TypedVar node) {
+        return ValueType.annotationToValueType(node.type);
+    }
+
+    @Override
+    public SymbolType analyze(BinaryExpr node) {
+        String op = node.operator;
+
+        // Check operand type.
+        SymbolType left_type = node.left.getInferredType();
+        SymbolType right_type = node.left.getInferredType();
+        switch(op) {
+            case "-":
+            case "*":
+            case "//":
+            case "%":
+            case ">":
+            case "<":
+            case ">=":
+            case "<=":
+                if(left_type != ValueType.INT_TYPE || right_type != ValueType.INT_TYPE)
+                    throw new RuntimeException("Syntax Error: operand should be INT");
+                break;
+            case "and":
+            case "or":
+                if(left_type != ValueType.BOOL_TYPE || right_type != ValueType.BOOL_TYPE)
+                    throw new RuntimeException("Syntax Error: operand should be BOOL");
+                break;
+            case "+":
+                if(left_type != ValueType.INT_TYPE && left_type != ValueType.STR_TYPE && ! left_type.isListType())
+                    throw new RuntimeException("Syntax Error: operand of + should be INT or STR or LIST");
+                // fallthrough
+            case "==":
+            case "!=":
+            case "is":
+                if(node.left.getInferredType() != node.right.getInferredType())
+                    throw new RuntimeException("Syntax Error: binary operator operand type mismatch");
+                break;
+            default:
+                throw new RuntimeException("Syntax Error: binary operator operand type not supported.");
+        }
+
+        // Now set target type.
+        SymbolType result_type = ValueType.NONE_TYPE;
+        switch(op) {
+            case "-":
+            case "*":
+            case "//":
+            case "%":
+            case "and":
+            case "or":
+            case "+":
+                result_type = left_type;
+                break;
+            case ">":
+            case "<":
+            case ">=":
+            case "<=":
+            case "==":
+            case "!=":
+            case "is":
+                result_type = ValueType.BOOL_TYPE;
+                break;
+            default:
+                throw new RuntimeException("Logic error");
+        }
+
+        return result_type;
     }