diff --git a/src/CodeGen/Code.java b/src/CodeGen/Code.java
index a8137b5..fef9d86 100644
--- a/src/CodeGen/Code.java
+++ b/src/CodeGen/Code.java
@@ -69,7 +69,7 @@ public class Code {
 	bprint      = 53,
 	trap        = 54;
 
-    // compare operators
+    // Compare operators
     public static final int
 	eq = 0,
 	ne = 1,
@@ -82,16 +82,16 @@ public class Code {
 
     private static final int bufSize = 8192;
 
-    // code buffer
-    private static byte[] buf;
+    // Code buffer
+    private static byte[] buf = new byte[bufSize];
 
-    // next free byte in code buffer
-    public static int pc;
+    // Next free byte in code buffer
+    public static int pc = 0;
 
-    // pc of main function (set by parser)
-    public static int mainPc;
+    // PC of main function (set by parser)
+    public static int mainPc = -1;
 
-    // length of static data in words (set by parser)
+    // Length of static data in words (set by parser)
     public static int dataSize;
 
     //--------------- code buffer access ----------------------
@@ -184,12 +184,17 @@ public class Code {
 	x.kind = Item.Stack;
     }
 
-    // Generate an assignment x = y
-    public static void assign(Item x, Item y) {
+    /**
+     * Generate  an assignment  'x =  y' when  'y' is  already  in the
+     * estack
+     *
+     * @param x Variable to assign value from estack
+     */
+    public static void assign(Item x) {
 	switch(x.kind) {
 	case Item.Local:
 	    if(x.adr >= 0 && x.adr <= 3)
-		put(store + x.adr);
+		put(store0 + x.adr);
 	    else {
 		put(store);
 		put(x.adr);
@@ -199,12 +204,12 @@ public class Code {
 
 	case Item.Static:
 	    put(putstatic);
-	    put2(y.adr);
+	    put2(x.adr);
 	    break;
 
 	case Item.Fld:
 	    put(putfield);
-	    put2(y.adr);
+	    put2(x.adr);
 	    break;
 
 	case Item.Elem:
@@ -217,6 +222,20 @@ public class Code {
 	}
     }
 
+    /**
+     * Generate an  assignment 'x =  y' when 'y'  has to be  loaded in
+     * estack
+     *
+     * @param x Variable to assign value to
+     * @param y Value assigned to the variable
+     */
+    public static void assign(Item x, Item y) {
+	if(y != null)
+	    load(y);
+
+	assign(x);
+    }
+
     //------------- jumps ---------------
 
     // Unconditional jump
@@ -238,13 +257,6 @@ public class Code {
 
     //------------------------------------
 
-    // initialize code buffer
-    public static void init() {
-	buf = new byte[bufSize];
-	pc = 0;
-	mainPc = -1;
-    }
-
     // Write the code buffer to the output stream
     public static void write(OutputStream s) {
 	int codeSize;
diff --git a/src/CodeGen/Item.java b/src/CodeGen/Item.java
index a154b34..5290c8b 100644
--- a/src/CodeGen/Item.java
+++ b/src/CodeGen/Item.java
@@ -19,7 +19,7 @@ public class Item {
 	Meth   = 6;
 
     // Con, Local, Static, Stack, Fld, Elem, Meth
-    public int    kind;
+    public int kind;
 
     // item type
     public Struct type;
diff --git a/src/Compiler.java b/src/Compiler.java
index 8996df4..f68ee60 100644
--- a/src/Compiler.java
+++ b/src/Compiler.java
@@ -25,8 +25,7 @@ public class Compiler {
 
 	try {
 	    Scanner.init(new InputStreamReader(new FileInputStream(source)));
-	    Code.init();
-	    Parser.parse(0);
+	    Parser.parse(Log.Level.DEBUG);
 
 	    try {
 		Code.write(new FileOutputStream(output));
diff --git a/src/Log.java b/src/Log.java
index 8bc4994..8496433 100644
--- a/src/Log.java
+++ b/src/Log.java
@@ -1,33 +1,40 @@
+/**
+ * Log messages
+ */
 package Compilator;
 
+/**
+ * A  <code>Log</code> object  displays  a messages  depending on  the
+ * minimum message level we want
+ */
 public class Log {
+    /** Available log levels */
+    static public enum Level { DEBUG, INFO, ERR }
 
-	static int Level;
-	
-	public static final int
-	DEBUG=0,
-	LOW=1,
-	HIGH=2;
-	/*
-	 * 0 = debug
-	 * 1 = normal
-	 * 2 = critical
-	 */
-	
-	Log(int lvl){
-		Level=lvl;
-	}
-	
-	void print(int lvl, String msg){
-		if(lvl>=Level){
-			System.out.print(msg);
-		}
-	}
-	
-	void println(int lvl, String msg){
-		if(lvl>=Level){
-			System.out.println(msg);
-		}
-	}
-	
+    /** Restrict  messages  logging  to this  level,  <code>ERR</code>
+     * messages  will  be  displayed  whatever is  the  minimum  level
+     * value */
+    static private Level levelMin;
+
+    /**
+     * <code>Log</code> constructor
+     *
+     * @param levelMin: restrict messages logging to this level
+     */
+    Log(Level levelMin) {
+	this.levelMin = levelMin;
+    }
+
+    /**
+     * Display     the    message     <code>msg</code>     of    level
+     * </code>level</code> according to  the minimum level of messages
+     * we want to display
+     *
+     * @param level: message level
+     * @param msg: message string
+     */
+    void println(Level level, String msg_fmt, Object ... msg_vals) {
+	if(level.compareTo(levelMin) >= 0)
+	    System.err.printf(level + ": " + msg_fmt + "\n", msg_vals);
+    }
 }
diff --git a/src/Parser.java b/src/Parser.java
index d85382b..cb41cc0 100644
--- a/src/Parser.java
+++ b/src/Parser.java
@@ -13,7 +13,8 @@ import Compilator.SymTab.Struct;
 import Compilator.SymTab.Tab;
 
 /**
- * A  <code>Parser</code> object parse  a source  file and  write µJVM
+ * A <code>Parser</code> object parses a source file whose tokens have
+ * been extracted by <code>Scanner</code> and writes µJVM intermediate
  * code accordingly
  */
 public class Parser {
@@ -21,46 +22,6 @@ public class Parser {
     private static BitSet FirstStatement = new BitSet();
     private static Log log;
 
-    /** Token codes */
-    private static final int
-	none      = 0,
-	ident     = 1,
-	number    = 2,
-	charCon   = 3,
-	plus      = 4,
-	minus     = 5,
-	times     = 6,
-	slash     = 7,
-	rem       = 8,
-	eql       = 9,
-	neq       = 10,
-	lss       = 11,
-	leq       = 12,
-	gtr       = 13,
-	geq       = 14,
-	assign    = 15,
-	semicolon = 16,
-	comma     = 17,
-	period    = 18,
-	lpar      = 19,
-	rpar      = 20,
-	lbrack    = 21,
-	rbrack    = 22,
-	lbrace    = 23,
-	rbrace    = 24,
-	class_    = 25,
-	else_     = 26,
-	final_    = 27,
-	if_       = 28,
-	new_      = 29,
-	print_    = 30,
-	program_  = 31,
-	read_     = 32,
-	return_   = 33,
-	void_     = 34,
-	while_    = 35,
-	eof       = 36;
-
     /** Token names for error messages */
     private static final String[] name = {
 	"none", "identifier", "number", "char constant", "+", "-", "*", "/", "%",
@@ -76,18 +37,21 @@ public class Parser {
     private static Token la;
 
     /** Always contains la.kind */
-    private static int sym;
+    private static Token.Code sym;
 
     /** Error counter */
-    public static int errors;
+    public static int errors = 0;
 
-    /** No. of correctly recognized tokens since last error */
-    private static int errDist;
+    /** No. of correctly recognized  tokens since last error. As error
+     * messages are  displayed only  if there was  at least  3 scanned
+     * without error,  then initialise  it at <value>3</value>  at the
+     * beginning*/
+    private static int errDist = 3;
 
     /**
      * Store in <code>t</code>  the token which is going  to be parsed
      * and  call   the  scanner  to   get  the  next  one   stored  in
-     * <code>la</code>
+     * <code>la</code>, also stores its kind in <code>sym</code>
      */
     private static void scan()
     {
@@ -96,481 +60,708 @@ public class Parser {
 	try {
 	    la = Scanner.next();
 	    sym = la.kind;
+
+	    // Another token was recognized...
 	    errDist++;
 	}
 	catch(ScannerSyntaxError e) {
+	    // The scanner was not able to retrieve the token
 	    error(e.getMessage());
 	}
     }
 
-    private static void check(int expected) {
-	if (sym == expected)
+    /**
+     * Check whether the next token is  correct and if so get the next
+     * one
+     *
+     * @param token_expected: expected token
+     */
+    private static void check(Token.Code token_expected) {
+	if(sym == token_expected)
 	    scan();
 	else
-	    error(name[expected] + " expected"+ " found: "+sym);
+	    error("'" + name[token_expected.ordinal()] + "' expected, found: '" + sym + "'");
     }
 
-    public static void error(String msg) { // syntactic error at token la
+    /**
+     * Display an error message but not spurious ones
+     *
+     * @param msg: error message to display
+     */
+    public static void error(String msg) {
 	if (errDist >= 3) {
-	    System.out.println("-- line " + la.line + " col " + la.column + ": " + msg);
+	    log.println(Log.Level.ERR, "L: %d: C: %d: %s", la.line, la.column, msg);
 	    errors++;
 	}
+
 	errDist = 0;
     }
 
-    //-------------- parsing methods (in alphabetical order) -----------------
-
     /**
-     *  Program = "program" ident {ConstDecl | ClassDecl | VarDecl} '{' {MethodDecl} '}'.
+     * Parse <code>Program</code> instruction
+     *
+     * "program" ident {ConstDecl | ClassDecl | VarDecl} '{' {MethodDecl} '}'
      */
     private static void Program() {
-	log.println(Log.DEBUG, "Program(): " + sym + ": Begin:");
-	check(program_);
-	check(ident);
+	log.println(Log.Level.DEBUG, "> Program (sym=%d)", sym);
+
+	check(Token.Code.PROGRAM_);
+	check(Token.Code.IDENT);
+
+	// Create the global scope
 	Tab.openScope();
-	while(sym==final_ || sym==ident || sym==class_){
-	    switch(sym){
-	    case final_:
+
+	while(sym == Token.Code.FINAL_ || sym == Token.Code.IDENT || sym == Token.Code.CLASS_) {
+	    switch(sym) {
+	    case FINAL_:
 		ConstDecl();
 		break;
-	    case ident:
+		
+	    case IDENT:
 		VarDecl();
 		break;
-	    case class_:
+
+	    case CLASS_:
 		ClassDecl();
 		break;
 	    }
 	}
-	check(lbrace);
-	while(sym==ident || sym==void_){
+
+	check(Token.Code.LBRACE);
+
+	while(sym == Token.Code.IDENT || sym == Token.Code.VOID_)
 	    MethodDecl();
-	}
-	check(rbrace);
-	//Close the last scope
+
+	check(Token.Code.RBRACE);
+
+	// Close the global scope
 	Tab.closeScope();
-	log.println(Log.DEBUG, "Program(): End");
+
+	log.println(Log.Level.DEBUG, "< Program");
     }
 
     /**
-     *  ConstDecl = "final" Type ident "=" (number | charConst) ";".
-     * @throws SyntaxError
+     * Parse   declarations    of   global   constants    defined   at
+     * <code>Program</code> level.  We don't  need to add further code
+     * for code  generation here  because it will  be translated  to a
+     * 'const' instruction
+     *
+     * "final" Type ident "=" (number | charConst) ";"
      */
     private static void ConstDecl() {
-	log.println(Log.DEBUG, "ConstDecl(): " + sym + ": Begin:");
+	log.println(Log.Level.DEBUG, "> ConstDecl (sym=%d)", sym);
 
-	check(final_);
-	Struct ConstStruct = Type();
-	check(ident);
+	check(Token.Code.FINAL_);
+	Struct constType = Type();
+	check(Token.Code.IDENT);
 
 	// Insert  the  constant in  the  current  scope as  a
 	// constant
-	Tab.insert(Obj.Con, t.string, ConstStruct);
+ 	Tab.insert(Obj.Con, t.string, constType);
 
-	check(assign);
+	check(Token.Code.ASSIGN);
 
-	if(sym == number || sym == charCon)
+	// The type must  match the value, only number  and char types
+	// are accepted for constant declarations
+	if((sym == Token.Code.NUMBER && constType.kind == Struct.Int) ||
+	   (sym == Token.Code.CHARCON && constType.kind == Struct.Char))
+	    // Concerning code  generation, there is nothing  to do as
+	    // the value will be actually loaded as constant
 	    scan();
 	else
-	    error("Expected a number or a string");
-		
-	check(semicolon);
+	    error("Expected a number or a string, got sym=" + sym);
+
+	check(Token.Code.SEMICOLON);
 
-	log.println(Log.DEBUG, "ConstDecl(): End");
+	log.println(Log.Level.DEBUG, "< ConstDecl");
     }
 
     /**
-     *  VarDecl = Type ident {"," ident } ";".
-     * @throws SyntaxError
+     * Parse declaration of  variable defined at <code>Program</code>,
+     * <code>Class</code> and  <code>Method</code>.  We don't  need to
+     * add further  code for code  generation here because it  will be
+     * translated in 'putstatic/getstatic'  instructions for 'int' and
+     * 'char' and when instanciated  for class and array objects (with
+     * 'newarray' and 'new')
+     *
+     * Type ident {"," ident } ";"
      */
     private static void VarDecl() {
-	log.println(Log.DEBUG, "VarDecl(): " + sym + ": Begin:");
+	log.println(Log.Level.DEBUG, "> VarDecl (sym=%d)", sym);
 
-	Struct VarType=Type();
-	check(ident);
+	// Get the variable type
+	Struct VarType = Type();
 
-	// Insert  the  variable in  the  current  scope as  a
-	// variable
-	Tab.insert(Obj.Var, t.string, VarType);
+	check(Token.Code.IDENT);
 
-	while(sym==comma) {
+	// Insert the variable in the  current scope as a variable, an
+	// address will be automatically assigned so the space is kind
+	// of already allocated
+	Obj newVarObj = Tab.insert(Obj.Var, t.string, VarType);
+
+	// Insert all other variables in the current scope
+	while(sym == Token.Code.COMMA) {
 	    scan();
-	    check(ident);
+	    check(Token.Code.IDENT);
 
-	    // Insert every variable  in the current scope
-	    // as a variable
 	    Tab.insert(Obj.Var, t.string, VarType);
 	}
-	check(semicolon);
 
-	log.println(Log.DEBUG, "VarDecl(): End");
+	check(Token.Code.SEMICOLON);
+
+	log.println(Log.Level.DEBUG, "< VarDecl");
     }
 
     /**
-     *  ClassDecl = "class" ident "{" {VarDecl} "}".
-     * @throws SyntaxError
+     * Parse  declaration  of  class defined  at  <code>Program</code>
+     * level. We  don't need to  add further code for  code generation
+     * here because it will be allocated by a 'new'
+     *
+     * "class" ident "{" {VarDecl} "}"
      */
     private static void ClassDecl() {
-	log.println(Log.DEBUG, "ClassDecl(): " + sym + ": Begin:");
-	check(class_);
-	check(ident);
-	//Insert the new class in the scope
-	Struct currentClass=new Struct(Struct.Class);
+	log.println(Log.Level.DEBUG, "> ClassDecl (sym=%d)",sym);
+
+	check(Token.Code.CLASS_);
+	check(Token.Code.IDENT);
+
+	// Get the class type
+	Struct currentClass = new Struct(Struct.Class);
+
+	// Insert the new class in the scope
 	Tab.insert(Obj.Type, t.string, currentClass);
-	check(lbrace);
-	//Create a scope for this class
+
+	check(Token.Code.LBRACE);
+
+	// Create a new scope for this class
 	Tab.openScope();
-	while(sym==ident){
+
+	// Handle variable declarations within class scope
+	while(sym == Token.Code.IDENT)
 	    VarDecl();
-	}
-	//Set the attribute and number of attribute of the class
-	currentClass.fields=Tab.curScope.locals;
-	currentClass.nFields=Tab.curScope.nVars;
-	//Close the scope of this class
+
+	// Set the attribute and number of attributes of the class
+	currentClass.fields = Tab.curScope.locals;
+	currentClass.nFields = Tab.curScope.nVars;
+
+	// Close the scope of this class
 	Tab.closeScope();
-	check(rbrace);
-	log.println(Log.DEBUG, "ClassDecl(): End");
+
+	check(Token.Code.RBRACE);
+
+	log.println(Log.Level.DEBUG, "< ClassDecl");
     }
 
     /**
-     *  MethodDecl = (Type | "void") ident "(" [FormPars] ")" {VarDecl} Block.
-     * @throws SyntaxError
+     * Parse declaration of methods defined at <code>Program</code> or
+     * <code>Class</code> level
+     *
+     * (Type | "void") ident "(" [FormPars] ")" {VarDecl} Block
      */
     private static void MethodDecl() {
-	//TODO
-	log.println(Log.DEBUG, "MethodDecl(): " + sym + ": Begin:");
+	log.println(Log.Level.DEBUG, "> MethodDecl (sym=%d)", sym);
+
 	Struct type;
-	String name;
-	int n=0;
-	if(sym==ident){
-	    type=Type();
-	}else{
-	    check(void_);
-	    type=Tab.noType;
+	
+	if(sym == Token.Code.IDENT)
+	    type = Type();
+	else {
+	    check(Token.Code.VOID_);
+	    type = Tab.noType;
 	}
-	check(ident);
-	name=t.string;
-	//Create a scope for this method
-	Obj currentMethod=Tab.insert(Obj.Meth, name, type);
+
+	check(Token.Code.IDENT);
+
+	// Insert the method name in the symbol table and create a new
+	// scope for this method
+	Obj currentMethod = Tab.insert(Obj.Meth, t.string, type);
 	Tab.openScope();
-	check(lpar);
-	if(sym==ident){
-	    n=FormPars();
-	}
-	currentMethod.nPars=n;
-	if(name.equals("main")){
-	    Code.mainPc=Code.pc;
-	    if(currentMethod.type != Tab.noType){
+
+	check(Token.Code.LPAR);
+
+	// Add the parameters in the current scope
+	currentMethod.nPars = (sym == Token.Code.IDENT ? FormPars() : 0);
+
+	// In  case this  is the  main  function (entry  point of  the
+	// program), then set the PC accordingly
+	if(t.string.equals("main")) {
+	    Code.mainPc = Code.pc;
+
+	    if(currentMethod.type != Tab.noType)
 		error("Method main must be void");
-	    }
-	    if(currentMethod.nPars!= 0){
+
+	    if(currentMethod.nPars != 0)
 		error("Method main must no have parameters");
-	    }
 	}
-	check(rpar);
-	while(sym==ident){
+
+	check(Token.Code.RPAR);
+
+	while(sym == Token.Code.IDENT)
 	    VarDecl();
-	}
-	//TODO CHeck slide 66
-	currentMethod.adr=Code.pc;
+
+	// Now  the  parameters  have  been  added  on  the  'pstack',
+	// generate the code  for the method and set  the method entry
+	// address
+	currentMethod.adr = Code.pc;
 	Code.put(Code.enter);
 	Code.put(currentMethod.nPars);
 	Code.put(Tab.curScope.nVars);
-	Block();
-	if(currentMethod.type==Tab.noType){
-	    Code.put(Code.exit);
-	    Code.put(Code.return_);
-	}else{
-	    Code.put(Code.trap);
-	    Code.put(1);
-	}
-	//TODO Check, encore la?
-	currentMethod.locals=Tab.curScope.locals;
-	//currentMethod.type.nFields=Tab.curScope.nVars;
-	//Close the scope of this class
+
+	Block(currentMethod);
+
+	// Close the scope of this method
+	currentMethod.locals = Tab.curScope.locals;
 	Tab.closeScope();
-	log.println(Log.DEBUG, "MethodDecl(): End");
+
+	log.println(Log.Level.DEBUG, "< MethodDecl");
     }
 
     /**
-     *  FormPars = Type ident {"," Type ident}.
-     * @throws SyntaxError
+     * Parse  a <code>FormPars</code>  code, which  is  the parameters
+     * when declaring a method
+     *
+     * Type ident {"," Type ident}
+     *
+     * @return The number of method parameters
      */
     private static int FormPars() {
-	log.println(Log.DEBUG, "FormPars(): " + sym + ": Begin:");;
-	Struct FormArg=Type();
-	check(ident);
-	//insert the current Parameter as a variable
-	Tab.insert(Obj.Var, t.string, FormArg);
-	int n=1;
-	while(sym==comma){
+	log.println(Log.Level.DEBUG, "> FormPars (sym=%d)", sym);
+
+	int nParams = 0;
+	do {
+	    // Get the parameter type
+	    Struct FormType = Type();
+
+	    check(Token.Code.IDENT);
+
+	    // Insert the current parameter as a variable
+	    Tab.insert(Obj.Var, t.string, FormType);
+
+	    nParams++;
 	    scan();
-	    FormArg=Type();
-	    check(ident);
-	    //insert every parameter in the current scope as a variable
-	    Tab.insert(Obj.Var, t.string, FormArg);
-	    n++;
-	}
-	log.println(Log.DEBUG, "FormPars(): End");
-	return n;
+	} while(sym == Token.Code.COMMA);
+
+	log.println(Log.Level.DEBUG, "< FormPars");
+
+	return nParams;
     }
 
     /**
-     *  Type = ident ["[" "]"].
+     * Parse a <code>Type</code> which defined a variable type ('int',
+     * 'char' or 'array')
+     *
+     * ident ["[" "]"]
+     *
      * @return the structure of the current Type
-     * @throws SyntaxError
      */
     private static Struct Type() {
-	log.println(Log.DEBUG, "Type(): " + sym + ": Begin:");
-	check(ident);
-	Tab.find(t.string);
-	Struct result;
-	//Check if this Type exist
-	if(sym==lbrack){
-	    //Array
-	    result=new Struct(Struct.Arr, Tab.find(t.string).type);
+	log.println(Log.Level.DEBUG, "> Type (sym=%d)", sym);
+
+	check(Token.Code.IDENT);
+	Obj currentTypeObj = Tab.find(t.string);
+	
+	// In case this is an array
+	Struct currentType;
+	if(sym == Token.Code.LBRACK){
+	    currentType = new Struct(Struct.Arr, currentTypeObj.type);
 	    scan();
-	    check(rbrack);
-	}else{
-	    //Not an array => simple type
-	    result=Tab.find(t.string).type;
+	    check(Token.Code.RBRACK);
 	}
-	log.println(Log.DEBUG, "Type(): End");
-	return result;
+	// Not an array but just an 'int' or 'char'
+	else
+	    currentType = currentTypeObj.type;
+
+	log.println(Log.Level.DEBUG, "< Type");
+
+	return currentType;
     }
 
     /**
-     *  Block = "{" {Statement} "}".
-     * @throws SyntaxError
+     * Convenient  <code>Block</code> method  called for  a non-method
+     * block only
+     *
+     * @see Block
      */
     private static void Block() {
-	log.println(Log.DEBUG, "Block(): " + sym + ": Begin:");
-	check(lbrace);
-	while(FirstStatement.get(sym)){
-	    Statement();
+	Block(null);
+    }
+
+    /**
+     * Parse  a <code>Block</code>  which may  be actually  the method
+     * body (if  the first parameter equals  to <code>null</code>), if
+     * so then check the return type
+     *
+     * "{" {Statement} "}".
+     *
+     * @param currentMethod the method where this block is defined or null
+     */
+    private static void Block(Obj currentMethod) {
+	log.println(Log.Level.DEBUG, "> Block (sym=%d)", sym);
+
+	check(Token.Code.LBRACE);
+
+	boolean hasReturn = false;
+	while(FirstStatement.get(sym.ordinal())) {
+	    // A function must have a 'return' statement
+	    if(currentMethod != null && sym == Token.Code.RETURN_)
+		hasReturn = true;
+
+	    Statement(currentMethod);
+	}
+
+	check(Token.Code.RBRACE);
+
+	// Check for the return type, if any and generate the code
+	if(currentMethod != null) {
+	    // This a procedure or a valid function
+	    if(currentMethod.type == Tab.noType || hasReturn) {
+		Code.put(Code.exit);
+		Code.put(Code.return_);
+	    }
+	    // This function has no 'return' statement...
+	    else {
+		Code.put(Code.trap);
+		Code.put(1);
+	    }
 	}
-	check(rbrace);
-	log.println(Log.DEBUG, "Block(): End");
+
+	log.println(Log.Level.DEBUG, "< Block");
+    }
+
+    /**
+     * Convenient   <code>Statement</code>   method   called   for   a
+     * non-method statement
+     *
+     * @see Statement
+     */
+    private static void Statement() {
+	Statement(null);
     }
 
     /**
-     * Statement = Designator ("=" Expr | ActPars) ";"
+     * Parse statements as defined within <code>Block</code>
+     *
+     * Designator ("=" Expr | ActPars) ";"
      * | "if" "(" Condition ")" Statement
-     * ["else" Statement]
+     *   ["else" Statement]
      * | "while" "(" Condition ")" Statement
      * | "return" [Expr] ";"
      * | "read" "(" Designator ")" ";"
      * | "print" "(" Expr ["," number] ")" ";"
      * | Block
-     * | ";".
+     * | ";"
+     *
+     * @param currentMethod if within a method, otherwise null
      */
-    private static void Statement() {
-	log.println(Log.DEBUG, "Statement(): " + sym + ": Begin:");
-	int op;
-	int adr;
-	switch(sym){
-	case ident:
-	    Item x=Designator();
-	    if(sym==assign){
+    private static void Statement(Obj currentMethod) {
+	log.println(Log.Level.DEBUG, "> Statement (sym=%d)", sym);
+
+	switch(sym) {
+	case IDENT:
+	    Item x = Designator();
+
+	    // Assignment statement
+	    if(sym == Token.Code.ASSIGN) {
 		scan();
-		Item y=Expr();
-		if(x.type.assignableTo(y.type)){
+
+		Item y = Expr();
+		if(x.type.assignableTo(y.type))
 		    Code.assign(x, y);
-		}else{
-		    error("not assignable");
-		}
-	    }else{
+		else
+		    error("Not assignable to this variable");
+	    }
+	    // Function call statement
+	    else {
+		// First, load the parameters on the 'pstack'
 		ActPars(x);
+
+		// Then, call the function
 		Code.put(Code.call);
 		Code.put2(x.adr);
-		if(x.type!=Tab.noType){
+
+		if(x.type != Tab.noType)
 		    Code.put(Code.pop);
-		}
 	    }
-	    check(semicolon);
+
+	    check(Token.Code.SEMICOLON);
 	    break;
 
-	case if_:
-	    //TODO check but semble bon
+	case IF_:
 	    scan();
-	    check(lpar);
-	    op=Condition();
-	    Code.putFalseJump(op, 0);
-	    adr=Code.pc-2;
-	    check(rpar);
+	    check(Token.Code.LPAR);
+
+	    // Get  operator  of the  if  statement  and generate  the
+	    // associated code
+	    int opIf = Condition();
+
+	    // Insert a  jump according to  the condition and  set the
+	    // jump target  address to  0 as it  is not known  yet (it
+	    // will be set later to the value of PC at the end of this
+	    // statement)
+	    Code.putFalseJump(opIf, 0);
+
+	    // Save the address  of the current PC as  it will be used
+	    // to fix up the previously generated jump with the proper
+	    // target address
+	    int adrIf = Code.pc - 2;
+
+	    check(Token.Code.RPAR);
 	    Statement();
-	    if(sym==else_){
+
+	    if(sym == Token.Code.ELSE_) {
 		Code.putJump(0);
-		int adr2=Code.pc-2;
-		Code.fixup(adr);
+		int adrElse = Code.pc - 2;
+		Code.fixup(adrIf);
 		scan();
 		Statement();
-		Code.fixup(adr2);
-	    }else{
-		Code.fixup(adr);
+		Code.fixup(adrElse);
 	    }
+	    else
+		// Fix up the previously  generated jump as the target
+		// address  jump is the  current value  of PC  (end of
+		// statement)
+		Code.fixup(adrIf);
+
 	    break;
-	case while_:
-	    //TODO check but semble bon
+
+	case WHILE_:
 	    scan();
-	    int top=Code.pc;
-	    check(lpar);
-	    op= Condition();
-	    Code.putFalseJump(op, 0);
-	    adr=Code.pc-2;
-	    check(rpar);
+	    check(Token.Code.LPAR);
+
+	    // Save the top of the while statement
+	    int topPC = Code.pc;
+
+	    // Get operator of the condition
+	    int opWhile = Condition();
+
+	    // Insert a  jump according to  the condition and  set the
+	    // jump target address to 0 as it is not known yet
+	    Code.putFalseJump(opWhile, 0);
+
+	    // Save the address of  the jump instruction which will be
+	    // patched up at the end of the while statement
+	    int adrWhile = Code.pc - 2;
+
+	    check(Token.Code.RPAR);
 	    Statement();
-	    Code.putJump(top);
-	    Code.fixup(adr);
+
+	    // Inconditional jump to the beginning of the statement
+	    Code.putJump(topPC);
+
+	    // Now fix  the jump target  address for the  condition of
+	    // the loop
+	    Code.fixup(adrWhile);
+
 	    break;
-	case return_:
+
+	case RETURN_:
 	    scan();
-	    Expr();
-	    check(semicolon);
+	    Item expr = Expr();
+	    check(Token.Code.SEMICOLON);
+
+	    // Check if this is a function (not a procedure)
+	    if(currentMethod == null || currentMethod.type == Tab.noType)
+		error("Unexpected return outside a function");
+
+	    // Check that  the type  matches between the  return value
+	    // and the method return type
+	    else if(!expr.type.assignableTo(currentMethod.type))
+		error("Type of return value does not match method return type");
+
 	    break;
-	case read_:
+
+	case READ_:
 	    scan();
-	    check(lpar);
-	    Designator();
-	    check(rpar);
-	    check(semicolon);
+	    check(Token.Code.LPAR);
+
+	    // Get the variable where the read value will be written
+	    Item itemRead = Designator();
+
+	    check(Token.Code.RPAR);
+	    check(Token.Code.SEMICOLON);
+
+	    // Code generation for read which can be performed only on
+	    // int or char types
+	    if(itemRead.type.kind == Struct.Int) {
+		Code.put(Code.read);
+		Code.assign(itemRead);
+	    }
+	    else if(itemRead.type.kind == Struct.Char) {
+		Code.put(Code.bread);
+		Code.assign(itemRead);
+	    }
+	    else
+		error("read can only be performed on int or char types");
+
 	    break;
-	case print_:
+
+	case PRINT_:
 	    scan();
-	    check(lpar);
-	    Expr();
-	    if(sym==comma){
+	    check(Token.Code.LPAR);
+
+	    // Get 'print' expression
+	    Item itemPrint = Expr();
+
+	    // Get optional 'number' argument
+	    if(sym == Token.Code.COMMA) {
 		scan();
-		check(number);
+		check(Token.Code.NUMBER);
+
+		// Load it
+		Code.load(new Item(t.value));
 	    }
-	    check(rpar);
-	    check(semicolon);
+
+	    check(Token.Code.RPAR);
+	    check(Token.Code.SEMICOLON);
+
+	    // Load the value to print
+	    Code.load(itemPrint);
+
+	    // Generate   different   type   of  'print'   instruction
+	    // depending on the type
+	    if(itemPrint.type.kind == Struct.Int)
+		Code.put(Code.print);
+
+	    else if(itemPrint.type.kind == Struct.Char)
+		Code.put(Code.bprint);
+
+	    else
+		error("Unexpected value for print");
+
 	    break;
-	case lbrace:
+
+	case LBRACE:
 	    Block();
 	    break;
-	case semicolon:
+
+	case SEMICOLON:
 	    scan();
 	    break;
+
 	default:
-	    error("Unexpected beginning for the statement");
+	    error("Unexpected beginning of statement");
 	    break;
 	}
-	log.println(Log.DEBUG, "Statement(): End");
+
+	log.println(Log.Level.DEBUG, "< Statement");
     }
 
     /**
-     *  ActPars = "(" [ Expr {"," Expr} ] ")".
-     * @throws SyntaxError
-     */
-    /*TODO REMETTRE COMME AVANT CAR FOIREUX
-     * (exemple: aucun parametre, ca plante maintenant)
+     * Parse method  arguments if  any and check  that it  matches the
+     * method actual prototype
+     *
+     * "(" [ Expr {"," Expr} ] ")"
+     *
+     * @param method Method object
      */
-    private static void ActPars(Item m) {
-	log.println(Log.DEBUG, "ActPars(): " + sym + ": Begin:");
-	Item ap;
-	if(m.kind != Item.Meth) {
+    private static void ActPars(Item method) {
+	log.println(Log.Level.DEBUG, "> ActPars (sym=%d)", sym);
+
+	// Check whether it is actually a method
+	if(method.kind != Item.Meth) {
 	    error("Not a method");
-	    m.obj = Tab.noObj;
+	    method.obj = Tab.noObj;
 	}
-	int aPars = 0;
-	int fPars = m.obj.nPars;
-	Obj fp = m.obj.locals;
-	check(lpar);
-
-	if(sym!=rpar){
-	    ap = Expr();
-	    Code.load(ap);
-	    aPars++;
-	    if(fp != null){
-		if(!ap.type.assignableTo(fp.type)) {
-		    error("Parameter type mismatch");
-		    fp = fp.next;
-		}
-	    }
 
-	    while(sym==comma){
-		scan();
-		ap = Expr();
-		Code.load(ap);
-		aPars++;
-		if(fp != null){
-		    if(!ap.type.assignableTo(fp.type)) {
-			error("Parameter type mismatch");
-			fp = fp.next;
-		    }
-		}
+	check(Token.Code.LPAR);
 
-	    }
+	// Parse all the parameters if any
+	int foundParameters = 0;
+	if(sym != Token.Code.RPAR){
+	    do {
+		// Get the value of the parameter and load it
+		Item parameter = Expr();
+		Code.load(parameter);
+
+		foundParameters++;
+
+		// Check that type of this parameter matches
+		Obj locals = method.obj.locals;
+		if(locals != null) {
+		    if(!parameter.type.assignableTo(locals.type))
+			error("Parameter " + foundParameters + " type mismatch");
+
+		    locals = locals.next;
+		}
+	    } while(sym == Token.Code.COMMA);
 	}
 
-	check(rpar);
+	check(Token.Code.RPAR);
 
-	if(aPars > fPars)
+	// Check whether  the number of parameters  parsed matches the
+	// number of parameters expected for this method
+	int expectedParameters = method.obj.nPars;
+
+	if(foundParameters > expectedParameters)
 	    error("Too many actual arguments");
-	else if(aPars < fPars)
+	else if(foundParameters < expectedParameters)
 	    error("Too few actual parameters");
 
-	log.println(Log.DEBUG, "ActPars(): End");
+	log.println(Log.Level.DEBUG, "< ActPars");
     }
 
     /**
-     *  Condition = Expr Relop Expr.
-     * @throws SyntaxError
+     * Parse   a   <code>if</code>   and   <code>while</code>   within
+     * <code>Statement</code>.    Only  generate   code   for  loading
+     * right-side and left-side expressions.
+     *
+     * Expr Relop Expr
+     *
+     * @return Condition operator as defined in <code>Code</code>
      */
     private static int Condition() {
-	log.println(Log.DEBUG, "Condition(): " + sym + ": Begin:");
-	int op;
-	Item x, y;
-	x=Expr();
+	log.println(Log.Level.DEBUG, "> Condition (sym=%d)", sym);
+
+	// Parse  left-side expression  of the  condition and  load it
+	// onto the estack
+	Item x = Expr();
 	Code.load(x);
-	op=Relop();
-	y=Expr();
+
+	// Get operator (the jump code is generated in Statement)
+	int op = Relop();
+
+	// Parse right-side  expression of  the condition and  load it
+	// onto the estack
+	Item y = Expr();
 	Code.load(y);
+
+	// Type checking of the condition expressions
 	if(!x.type.compatibleWith(y.type))
 	    error("Type mismatch");
-	if(x.type.isRefType() && op!=Code.eq && op !=Code.ne){
+
+	// Only equality operator can be applied on array and classes
+	if(x.type.isRefType() && op != Code.eq && op != Code.ne)
 	    error("Invalid compare");
-	}
-	log.println(Log.DEBUG, "Condition(): End");
+
+	log.println(Log.Level.DEBUG, "< Condition");
+
 	return op;
     }
 
     /**
-     *  Relop = "==" | "!=" | ">" | ">=" | "<" | "<=".
-     * @throws SyntaxError
+     * Parse    a   condition   operator    as   defined    within   a
+     * <code>Condition</code>
+     *
+     * "==" | "!=" | ">" | ">=" | "<" | "<="
+     *
+     * @return Condition operator as defined in <code>Code</code>
      */
     private static int Relop() {
-	log.println(Log.DEBUG, "Relop(): " + sym + ": Begin:");
-	int op=0;
-	if(FirstReLop.get(sym)){
-	    //TODO verif des bons symbols Code.eq, etc.
-	    switch(sym){
-	    case eql:
-		op=Code.eq;
-		break;
-	    case neq:
-		op=Code.ne;
-		break;
-	    case lss:
-		op=Code.lt;
-		break;
-	    case leq:
-		op=Code.le;
-		break;
-	    case gtr:
-		op=Code.gt;
-		break;
-	    case geq:
-		op=Code.ge;
-		break;
-	    }
-	    scan();	
-	}
-	else{
+	log.println(Log.Level.DEBUG, "> Relop (sym=%d)", sym);
+
+	// The next symbol must be relation operator
+	if(!FirstReLop.get(sym.ordinal())) {
 	    error("Expected a comparator");
+	    return 0;
 	}
 
-	log.println(Log.DEBUG, "Relop(): End");
+	// Code and  Token operators are  ordered in the same  way, so
+	// just compute the operator of the Code to be generated
+	int op = Code.eq + (sym.ordinal() - Token.Code.EQL.ordinal());
+
+	scan();	
+
+	log.println(Log.Level.DEBUG, "< Relop");
 	return op;
     }
 
@@ -580,11 +771,11 @@ public class Parser {
      * @throws SyntaxError
      */
     private static Item Expr() {
-	log.println(Log.DEBUG, "Expr(): " + sym + ": Begin:");
+	log.println(Log.Level.DEBUG, "Expr(): " + sym + ": Begin:");
 	Item x, y;
 	int op;
 
-	if(sym == minus){
+	if(sym == Token.Code.MINUS){
 	    scan();
 	    x=Term();
 	    if(x.type!=Tab.intType){
@@ -600,7 +791,7 @@ public class Parser {
 	    x=Term();
 	}
 
-	while(sym==minus || sym==plus) {
+	while(sym==Token.Code.MINUS || sym==Token.Code.PLUS) {
 	    op=Addop();
 	    Code.load(x);
 	    y=Term();
@@ -611,7 +802,7 @@ public class Parser {
 	    Code.put(op);
 	}
 
-	log.println(Log.DEBUG, "Expr(): End");
+	log.println(Log.Level.DEBUG, "Expr(): End");
 	return x;
     }
 
@@ -621,19 +812,19 @@ public class Parser {
      * @throws SyntaxError
      */
     private static Item Term() {
-	log.println(Log.DEBUG, "Term(): " + sym + ": Begin:");
+	log.println(Log.Level.DEBUG, "Term(): " + sym + ": Begin:");
 	Item x, y;
 	int op;
 	x=Factor();
-	while(sym==times || sym==slash || sym==rem){
+	while(sym==Token.Code.TIMES || sym==Token.Code.SLASH || sym==Token.Code.REM){
 	    switch(sym){
-	    case times:
+	    case TIMES:
 		op=Code.mul;
 		break;
-	    case slash:
+	    case SLASH:
 		op=Code.div;
 		break;
-	    case rem:
+	    case REM:
 		op=Code.rem;
 		break;
 	    default:
@@ -649,7 +840,7 @@ public class Parser {
 	    }
 	    Code.put(op);
 	}
-	log.println(Log.DEBUG, "Term(): End");
+	log.println(Log.Level.DEBUG, "Term(): End");
 	return x;
     }
 
@@ -662,16 +853,16 @@ public class Parser {
      * @throws SyntaxError
      */
     private static Item Factor() {
-	log.println(Log.DEBUG, "Factor(): " + sym + ": Begin:");
+	log.println(Log.Level.DEBUG, "Factor(): " + sym + ": Begin:");
 
 	Item x;
 	int val;
 	String name;
 
 	switch(sym){
-	case ident:
+	case IDENT:
 	    x = Designator();
-	    if(sym == eql){
+	    if(sym == Token.Code.EQL){
 		ActPars(x);
 		if(x.type==Tab.noType){
 		    error("procedure called as a function");
@@ -687,26 +878,26 @@ public class Parser {
 		x.kind=Item.Stack;
 	    }
 	    break;
-	case number:
+	case NUMBER:
 	    scan();
 	    val=t.value;
 	    x = new Item(val);
 	    //Code.load(result);
 	    break;
-	case charCon:
+	case CHARCON:
 	    scan();
 	    val=t.value;
 	    x= new Item(val);
 	    x.type=Tab.charType;
 	    break;
-	case lpar:
+	case LPAR:
 	    scan();
 	    x=Expr();
-	    check(rpar);
+	    check(Token.Code.RPAR);
 	    break;
-	case new_:
+	case NEW_:
 	    scan();
-	    check(ident);
+	    check(Token.Code.IDENT);
 	    name=t.string;
 	    Obj obj=Tab.find(name);
 	    if(obj.kind!=Obj.Type){
@@ -714,7 +905,7 @@ public class Parser {
 	    }
 	    Struct type=obj.type;
 	    //If Array
-	    if(sym==lbrack){
+	    if(sym==Token.Code.LBRACK){
 		//It is an array of ident
 		//result=new Struct(Struct.Arr);
 		//result.elemType=Tab.find(t.string).type;
@@ -731,7 +922,7 @@ public class Parser {
 		    Code.put(1);
 		}
 		type=new Struct(Struct.Arr, type);
-		check(rbrack);
+		check(Token.Code.RBRACK);
 	    }else{
 		//Otherwise, simple Type
 		if(type.kind!=Struct.Class){
@@ -750,7 +941,7 @@ public class Parser {
 	    error("Unexpected first character in the factor");
 	    break;
 	}
-	log.println(Log.DEBUG, "Factor(): End");
+	log.println(Log.Level.DEBUG, "Factor(): End");
 	return x;
     }
 
@@ -760,17 +951,17 @@ public class Parser {
      * @throws SyntaxError
      */
     private static Item Designator() {
-	log.println(Log.DEBUG, "Designator(): " + sym + ": Begin:");
+	log.println(Log.Level.DEBUG, "Designator(): " + sym + ": Begin:");
 	Item x, y;
 	String name;
-	check(ident);
+	check(Token.Code.IDENT);
 	name=t.string;
 	Obj obj = Tab.find(t.string);
 	x=new Item(obj);
 	//Check if this variable exists
-	while(lbrack==sym || sym==period){
+	while(Token.Code.LBRACK==sym || sym==Token.Code.PERIOD){
 	    switch(sym){
-	    case lbrack:
+	    case LBRACK:
 		Code.load(x);
 		if(x.type.kind != Struct.Arr) {
 		    error(t.string + "is not an array");
@@ -779,7 +970,7 @@ public class Parser {
 
 		scan();
 		y = Expr();
-		check(rbrack);
+		check(Token.Code.RBRACK);
 
 		if(y.type.kind != Struct.Int){
 		    error("Index must be of type int");
@@ -789,13 +980,13 @@ public class Parser {
 		x.type = x.type.elemType;
 		break;
 
-	    case period:
+	    case PERIOD:
 		if(x.type.kind != Struct.Class) {
 		    error(t.string + "is not an object");
 		    break;
 		}
 		scan();
-		check(ident);
+		check(Token.Code.IDENT);
 		Code.load(x);
 		// Search for this ident in the class
 		obj = Tab.findField(t.string, x.type);
@@ -806,7 +997,7 @@ public class Parser {
 	    }
 	}
 
-	log.println(Log.DEBUG, "Designator(): End");
+	log.println(Log.Level.DEBUG, "Designator(): End");
 
 	// Return the type of the designator
 	return x;
@@ -818,13 +1009,13 @@ public class Parser {
      */
     private static int Addop() {
 	int op;
-	log.println(Log.DEBUG, "Addop(): " + sym + ": Begin:");
-	if(sym==plus || sym==minus){
+	log.println(Log.Level.DEBUG, "Addop(): " + sym + ": Begin:");
+	if(sym==Token.Code.PLUS || sym==Token.Code.MINUS){
 	    switch(sym){
-	    case minus:
+	    case MINUS:
 		op=Code.sub;
 		break;
-	    case plus:
+	    case PLUS:
 		op=Code.add;
 		break;
 	    default:
@@ -836,7 +1027,7 @@ public class Parser {
 	    error("Unexpected character: expected + or -");
 	    op=0;
 	}
-	log.println(Log.DEBUG, "Addop(): End");
+	log.println(Log.Level.DEBUG, "Addop(): End");
 	return op;
     }
 
@@ -845,44 +1036,45 @@ public class Parser {
      * @throws SyntaxError
      */
     private static void Mulop() {
-	log.println(Log.DEBUG, "Mulop(): " + sym + ": Begin:");
-	if(sym==times || sym==slash || sym==rem){
+	log.println(Log.Level.DEBUG, "Mulop(): " + sym + ": Begin:");
+	if(sym==Token.Code.TIMES || sym==Token.Code.SLASH || sym==Token.Code.REM){
 	    scan();
 	}else{
 	    error("Unexpected character: expected *, / or %");
 	}
-	log.println(Log.DEBUG, "Mulop(): End");
+	log.println(Log.Level.DEBUG, "Mulop(): End");
     }
 
-    public static void parse(int loglvl) {
+    public static void parse(Log.Level logLevelMin) {
 	// initialize symbol sets
-	FirstReLop.set(eql);
-	FirstReLop.set(neq);
-	FirstReLop.set(lss);
-	FirstReLop.set(leq);
-	FirstReLop.set(gtr);
-	FirstReLop.set(geq);
-
-	FirstStatement.set(ident);
-	FirstStatement.set(if_);
-	FirstStatement.set(else_);
-	FirstStatement.set(while_);
-	FirstStatement.set(return_);
-	FirstStatement.set(read_);
-	FirstStatement.set(print_);
-	FirstStatement.set(lbrace);
-	FirstStatement.set(semicolon);
-
-	log=new Log(loglvl);
+	FirstReLop.set(Token.Code.EQL.ordinal());
+	FirstReLop.set(Token.Code.NEQ.ordinal());
+	FirstReLop.set(Token.Code.LSS.ordinal());
+	FirstReLop.set(Token.Code.LEQ.ordinal());
+	FirstReLop.set(Token.Code.GTR.ordinal());
+	FirstReLop.set(Token.Code.GEQ.ordinal());
+
+	FirstStatement.set(Token.Code.IDENT.ordinal());
+	FirstStatement.set(Token.Code.IF_.ordinal());
+	FirstStatement.set(Token.Code.ELSE_.ordinal());
+	FirstStatement.set(Token.Code.WHILE_.ordinal());
+	FirstStatement.set(Token.Code.RETURN_.ordinal());
+	FirstStatement.set(Token.Code.READ_.ordinal());
+	FirstStatement.set(Token.Code.PRINT_.ordinal());
+	FirstStatement.set(Token.Code.LBRACE.ordinal());
+	FirstStatement.set(Token.Code.SEMICOLON.ordinal());
+
+	log = new Log(logLevelMin);
 
 	//Initialize Symbol Table
 	Tab.init();
 
 	// start parsing
-	errors = 0; errDist = 3;
 	scan();
 	Program();
-	if (sym != eof) error("end of file found before end of program");
+
+	if(sym != Token.Code.EOF)
+	    error("end of file found before end of program");
     }
 
 }
diff --git a/src/Scanner.java b/src/Scanner.java
index 3f89a0e..89b41ac 100644
--- a/src/Scanner.java
+++ b/src/Scanner.java
@@ -17,50 +17,10 @@ class Scanner {
     /** End of line character */
     private static final char eol = '\n';
     
-    /** Token identifier */
-    private static final int
-	none      = 0,
-	ident     = 1,
-	number    = 2,
-	charCon   = 3,
-	plus      = 4,
-	minus     = 5,
-	times     = 6,
-	slash     = 7,
-	rem       = 8,
-	eql       = 9,
-	neq       = 10,
-	lss       = 11,
-	leq       = 12,
-	gtr       = 13,
-	geq       = 14,
-	assign    = 15,
-	semicolon = 16,
-	comma     = 17,
-	period    = 18,
-	lpar      = 19,
-	rpar      = 20,
-	lbrack    = 21,
-	rbrack    = 22,
-	lbrace    = 23,
-	rbrace    = 24,
-	class_    = 25,
-	else_     = 26,
-	final_    = 27,
-	if_       = 28,
-	new_      = 29,
-	print_    = 30,
-	program_  = 31,
-	read_     = 32,
-	return_   = 33,
-	void_     = 34,
-	while_    = 35,
-	eof       = 36;
-    
     /**
      * Sorted list  of keywords as the keyword  identifiers are sorted
      * when  declared, that's  why there  is <code>firstKeyword</code>
-     * attribute which gives the first identifier 
+     * attribute which gives the first identifier
      */
     private static final String keywords[] = {
 	"class", "else", "final", "if", "new", "print",
@@ -68,7 +28,7 @@ class Scanner {
     };
 
     /** First identifier number related to <code>keywords</code> */
-    private static final int firstKeyword = class_;
+    private static final Token.Code firstKeyword = Token.Code.CLASS_;
 
     /** Lookahead character */
     private static char ch;
@@ -95,7 +55,7 @@ class Scanner {
      *
      *
      */
-    private static class HashMapSimpleToken extends HashMap<Character, Integer> {
+    private static class HashMapSimpleToken extends HashMap<Character, Token.Code> {
 	/**
 	 *
 	 *
@@ -105,7 +65,7 @@ class Scanner {
 	    super();
 
 	    for(int i = 0; i < attrs_values.length - 1; i=i+2){
-	    	this.put((Character) attrs_values[i], (Integer) attrs_values[i + 1]);
+	    	this.put((Character) attrs_values[i], (Token.Code) attrs_values[i + 1]);
 	    }
 	}
     }
@@ -154,11 +114,11 @@ class Scanner {
 	column = 0;
 	nextCh();
 
-	Object[] b={';', semicolon, '.', period, '+', plus, 
-		    '-', minus, '*', times, '(', lpar,
-		    ')', rpar, '[', lbrack, ']', rbrack,
-		    '{', lbrace, '}', rbrace, '%', rem,
-		    ',', comma};
+	Object[] b={';', Token.Code.SEMICOLON, '.', Token.Code.PERIOD, '+', Token.Code.PLUS, 
+		    '-', Token.Code.MINUS, '*', Token.Code.TIMES, '(', Token.Code.LPAR,
+		    ')', Token.Code.RPAR, '[', Token.Code.LBRACK, ']', Token.Code.RBRACK,
+		    '{', Token.Code.LBRACE, '}', Token.Code.RBRACE, '%', Token.Code.REM,
+		    ',', Token.Code.COMMA};
 	SimpleTokens = new HashMapSimpleToken(b);
     }
 
@@ -181,65 +141,65 @@ class Scanner {
 	switch(ch) {
 	case eofCh:
 	    // No nextCh() any more
-	    t.kind = eof;
+	    t.kind = Token.Code.EOF;
 	    break;
 
 	case '>':
-	    t.kind = gtr;
+	    t.kind = Token.Code.GTR;
 	    nextCh();
 	    if(ch == '=') {
 		nextCh();
-		t.kind = geq;
+		t.kind = Token.Code.GEQ;
 	    }
 
 	    break;
 
 	case '<':
-	    t.kind = lss;
+	    t.kind = Token.Code.LSS;
 	    nextCh();
 	    if(ch == '=') {
 		nextCh();
-		t.kind = leq;
+		t.kind = Token.Code.LEQ;
 	    }
 
 	    break;
 
 	case '!':
-	    t.kind = none;
+	    t.kind = Token.Code.NONE;
 	    nextCh();
 	    if(ch == '=') {
 		nextCh();
-		t.kind = neq;
+		t.kind = Token.Code.NEQ;
 	    }
 
 	    break;
 
 	case '=':
-	    t.kind = assign;
+	    t.kind = Token.Code.ASSIGN;
 	    nextCh();
 	    if(ch == '=') {
 		nextCh();
-		t.kind = eql;
+		t.kind = Token.Code.EQL;
 	    }
 
 	    break;
 
 	case '\'':
-	    t.kind = none;
+	    t.kind = Token.Code.NONE;
 
 	    nextCh();
 	    char val = ch;
 	    nextCh();
 		
 	    if(Character.isLetter(val) && ch == '\'') {
-		t.kind = charCon;
+		t.kind = Token.Code.CHARCON;
 		t.value = val;
 	    }
 
 	    break;
 
 	case '/':
-	    t.kind = slash;
+	    t.kind = Token.Code.SLASH;
 
 	    nextCh();
 	    if (ch == '/') {
@@ -262,7 +222,7 @@ class Scanner {
 		readNumber(t);
 	    else {
 		nextCh();
-		t.kind = none;
+		t.kind = Token.Code.NONE;
 	    }
 
 	    break;
@@ -279,7 +239,10 @@ class Scanner {
 	while(Character.isLetterOrDigit(ch));
 
 	int keywordIndex = Arrays.binarySearch(keywords, t.string);
-	t.kind = keywordIndex < 0 ? ident : (firstKeyword + keywordIndex);
+
+	t.kind = keywordIndex < 0 ?
+	    Token.Code.IDENT :
+	    Token.Code.values()[firstKeyword.ordinal() + keywordIndex];
     }
 
     private static void readNumber(Token t) throws ScannerSyntaxError {
@@ -291,7 +254,7 @@ class Scanner {
 
 	try {
 	    t.value = Integer.parseInt(t.string);
-	    t.kind = number;
+	    t.kind = Token.Code.NUMBER;
 	}
 	catch(NumberFormatException e) {
 	    throw new ScannerSyntaxError(t, e.getMessage());
diff --git a/src/SymTab/Obj.java b/src/SymTab/Obj.java
index 949d0b5..e875703 100644
--- a/src/SymTab/Obj.java
+++ b/src/SymTab/Obj.java
@@ -6,23 +6,44 @@ Every scope has a list of objects declared in this scope.
 package Compilator.SymTab;
 
 public class Obj {
-	public static final int // object kinds
-		Con  = 0,
-		Var  = 1,
-		Type = 2,
-		Meth = 3,
-		Prog = 4;
-	public int    kind;		// Con, Var, Type, Meth, Prog
-	public String name;		// object name
-	public Struct type;	 	// object type
-	public int    val;    // Con: value
-	public int    adr;    // Var, Math: address
-	public int    level;  // Var: declaration level
-	public int    nPars;  // Meth: number of parameters
-	public Obj    locals; // Meth: parameters and local objects
-	public Obj    next;		// next local object in this scope
-
-	public Obj(int kind, String name, Struct type) {
-		this.kind = kind; this.name = name; this.type = type;
-	}
+    // object kinds
+    public static final int
+	Con  = 0,
+	Var  = 1,
+	Type = 2,
+	Meth = 3,
+	Prog = 4;
+    
+    // Con, Var, Type, Meth, Prog
+    public int    kind;
+
+    // Object name
+    public String name;
+
+    // Object type
+    public Struct type;
+
+    // Con: value
+    public int val;
+
+    // Var, Math: address
+    public int adr;
+
+    // Var: declaration level
+    public int level;
+
+    // Meth: number of parameters
+    public int nPars;
+
+    // Meth: parameters and local objects
+    public Obj locals;
+
+    // Next local object in this scope
+    public Obj next;
+    
+    public Obj(int kind, String name, Struct type) {
+	this.kind = kind;
+	this.name = name;
+	this.type = type;
+    }
 }
\ No newline at end of file
diff --git a/src/TestParser.java b/src/TestParser.java
index 1d299b5..a1de96f 100644
--- a/src/TestParser.java
+++ b/src/TestParser.java
@@ -25,7 +25,7 @@ public class TestParser {
 	
 	    try {
 		Scanner.init(new InputStreamReader(new FileInputStream(args[0])));
-		Parser.parse(loglvl);
+		Parser.parse(Log.Level.DEBUG);
 		System.out.println(Parser.errors + " errors detected");
 	    } catch (IOException e) {
 		System.out.println("-- cannot open input file " + args[0]);
diff --git a/src/Token.java b/src/Token.java
index edfca83..841444b 100644
--- a/src/Token.java
+++ b/src/Token.java
@@ -6,8 +6,50 @@ package Compilator;
  * a integer (<code>kind</code>)
  */
 class Token {
+    /** Token identifier
+     * TODO: use an enum? */
+    static public enum Code {
+	    NONE,
+	    IDENT,
+	    NUMBER,
+	    CHARCON,
+	    PLUS,
+	    MINUS,
+	    TIMES,
+	    SLASH,
+	    REM,
+	    EQL,
+	    NEQ,
+	    LSS,
+	    LEQ,
+	    GTR,
+	    GEQ,
+	    ASSIGN,
+	    SEMICOLON,
+	    COMMA,
+	    PERIOD,
+	    LPAR,
+	    RPAR,
+	    LBRACK,
+	    RBRACK,
+	    LBRACE,
+	    RBRACE,
+	    CLASS_,
+	    ELSE_,
+	    FINAL_,
+	    IF_,
+	    NEW_,
+	    PRINT_,
+	    PROGRAM_,
+	    READ_,
+	    RETURN_,
+	    VOID_,
+	    WHILE_,
+	    EOF
+    }
+
     /** Token kind (unique identifier) */
-    int kind;
+    Code kind;
     
     /** Token line */
     int line;

