Browse Source

Initialized repo with the original files of acse

Andrea Gussoni 9 years ago
commit
5410b7344f
86 changed files with 17107 additions and 0 deletions
  1. 74 0
      .gitignore
  2. 26 0
      Makefile
  3. 19 0
      README
  4. 1 0
      VERSION
  5. 6 0
      acse/.directory
  6. 109 0
      acse/Acse.lex
  7. 2134 0
      acse/Acse.output
  8. 666 0
      acse/Acse.y
  9. 25 0
      acse/Makefile
  10. 118 0
      acse/axe_array.c
  11. 51 0
      acse/axe_array.h
  12. 1290 0
      acse/axe_cflow_graph.c
  13. 86 0
      acse/axe_cflow_graph.h
  14. 155 0
      acse/axe_constants.h
  15. 354 0
      acse/axe_debug.c
  16. 31 0
      acse/axe_debug.h
  17. 904 0
      acse/axe_engine.c
  18. 74 0
      acse/axe_engine.h
  19. 145 0
      acse/axe_errors.c
  20. 21 0
      acse/axe_errors.h
  21. 298 0
      acse/axe_expressions.c
  22. 53 0
      acse/axe_expressions.h
  23. 682 0
      acse/axe_gencode.c
  24. 499 0
      acse/axe_gencode.h
  25. 126 0
      acse/axe_io_manager.c
  26. 35 0
      acse/axe_io_manager.h
  27. 182 0
      acse/axe_labels.c
  28. 46 0
      acse/axe_labels.h
  29. 690 0
      acse/axe_reg_alloc.c
  30. 49 0
      acse/axe_reg_alloc.h
  31. 217 0
      acse/axe_struct.c
  32. 155 0
      acse/axe_struct.h
  33. 1061 0
      acse/axe_transform.c
  34. 28 0
      acse/axe_transform.h
  35. 297 0
      acse/axe_utils.c
  36. 70 0
      acse/axe_utils.h
  37. 35 0
      acse/cflow_constants.h
  38. 548 0
      acse/collections.c
  39. 102 0
      acse/collections.h
  40. 28 0
      acse/reg_alloc_constants.h
  41. 24 0
      acse/sy_table_constants.h
  42. 368 0
      acse/symbol_table.c
  43. 67 0
      acse/symbol_table.h
  44. 25 0
      assembler/Makefile
  45. 118 0
      assembler/asm_constants.h
  46. 107 0
      assembler/asm_debug.c
  47. 19 0
      assembler/asm_debug.h
  48. 788 0
      assembler/asm_engine.c
  49. 49 0
      assembler/asm_engine.h
  50. 262 0
      assembler/asm_struct.c
  51. 106 0
      assembler/asm_struct.h
  52. 122 0
      assembler/assembler.lex
  53. 651 0
      assembler/assembler.output
  54. 625 0
      assembler/assembler.y
  55. 548 0
      assembler/collections.c
  56. 102 0
      assembler/collections.h
  57. 26 0
      mace/Makefile
  58. 15 0
      mace/Makefile.all
  59. 110 0
      mace/decode.c
  60. 144 0
      mace/decode.h
  61. 339 0
      mace/fetch.c
  62. 14 0
      mace/fetch.h
  63. 23 0
      mace/getbits.c
  64. 13 0
      mace/getbits.h
  65. 96 0
      mace/machine.c
  66. 56 0
      mace/machine.h
  67. 216 0
      mace/main.c
  68. 12 0
      tests/Makefile
  69. 19 0
      tests/Makefile.test
  70. 121 0
      tests/arrays/arrays.src
  71. 27 0
      tests/arrays2/arrays2.src
  72. 13 0
      tests/assign/assign.src
  73. 12 0
      tests/dowhile/dowhile.src
  74. 6 0
      tests/errors/error1.src
  75. 6 0
      tests/errors/error2.src
  76. 7 0
      tests/errors/errore.src
  77. 20 0
      tests/fact/fact.src
  78. 9 0
      tests/misc/while0.src
  79. 22 0
      tests/misc/while1.src
  80. 14 0
      tests/misc/while_id.src
  81. 12 0
      tests/mult_table/mult_table.src
  82. 36 0
      tests/power/power.src
  83. 13 0
      tests/semi/semi.src
  84. 18 0
      tests/spilltest/spilltest.src
  85. 8 0
      tests/sum/sum.src
  86. 209 0
      tests/sum/tests

+ 74 - 0
.gitignore

@@ -0,0 +1,74 @@
+
+# Created by https://www.gitignore.io/api/c
+
+### C ###
+# Prerequisites
+*.d
+
+# Object files
+*.o
+*.ko
+*.obj
+*.elf
+
+# Linker output
+*.ilk
+*.map
+*.exp
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Libraries
+*.lib
+*.a
+*.la
+*.lo
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+*.out
+*.app
+*.i*86
+*.x86_64
+*.hex
+
+# Debug files
+*.dSYM/
+*.su
+*.idb
+*.pdb
+
+# Kernel Module Compile Results
+*.mod*
+*.cmd
+.tmp_versions/
+modules.order
+Module.symvers
+Mkfile.old
+dkms.conf
+
+# End of https://www.gitignore.io/api/c
+
+# Created by https://www.gitignore.io/api/assembler
+#
+### Assembler ###
+*.[sS]
+*.bc
+
+# End of https://www.gitignore.io/api/assembler
+
+bin/
+
+*.asm
+*.cfg
+*.tab.c
+*.tab.h
+*.yy.c

+ 26 - 0
Makefile

@@ -0,0 +1,26 @@
+objects = executor asm compiler
+dirs:=mace assembler acse tests
+
+
+all : bin $(objects)
+
+bin :
+	mkdir -p bin
+
+tests : 
+	cd ./tests && $(MAKE)
+
+executor :
+	cd ./mace && $(MAKE)
+
+asm :
+	cd ./assembler && $(MAKE)
+
+compiler :
+	cd ./acse && $(MAKE)
+
+clean :
+	for i in $(dirs) ; do cd $$i && $(MAKE) clean; cd .. ; done
+	rm -rf bin
+
+.PHONY : all clean tests executor asm compiler

+ 19 - 0
README

@@ -0,0 +1,19 @@
+To install the ACSE compiler type in the console:
+ make
+
+To compile some examples (located in the directory ./tests) type:
+ make tests
+
+
+In order to use the compiler/assembler/executor at first you have
+to export the directory ./bin in your current PATH as follows:
+
+export PATH=`pwd`/bin:$PATH
+
+
+You can compile and run new Lance programs in this way (suppose you
+have saved a Lance program in 'myprog.src'):
+
+ acse myprog.src myprog.asm
+ asm myprog.asm myprog.o
+ mace myprog.o

+ 1 - 0
VERSION

@@ -0,0 +1 @@
+1.1.0

+ 6 - 0
acse/.directory

@@ -0,0 +1,6 @@
+[Dolphin]
+Timestamp=2016,2,2,22,5,43
+Version=3
+
+[Settings]
+HiddenFilesShown=true

+ 109 - 0
acse/Acse.lex

@@ -0,0 +1,109 @@
+/***************************************************************************
+
+                                    Scanner 
+
+***************************************************************************/
+%option noyywrap
+
+%{
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * Axe.lex
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#include <string.h>
+#include "axe_struct.h"
+#include "collections.h"
+#include "Acse.tab.h"
+#include "axe_constants.h"
+
+/* Variables declared in the lexer for error tracking */
+extern int line_num;
+extern int num_error;
+
+/* extern declaration of function yyerror */
+extern int yyerror(const char* errmsg);
+
+%}
+/*=========================================================================
+                          TOKEN DEFINITIONS
+=========================================================================*/
+DIGIT    [0-9]
+ID       [a-zA-Z_][a-zA-Z0-9_]*
+
+
+/*=========================================================================
+      TOKENS
+=========================================================================*/
+
+%option noyywrap
+
+%x comment
+
+%%
+
+"\r\n"            { ++line_num; }
+"\n"              { ++line_num; }
+
+[ \t\f\v]+        { /* Ignore whitespace. */ }
+
+"//"[^\n]*        { ++line_num; /* ignore comment lines */ }
+"/*"              BEGIN(comment);
+
+<comment>[^*\n]*
+<comment>[^*\n]*\n      { ++line_num; }
+<comment>"*"+[^*/\n]*   
+<comment>"*"+[^*/\n]*\n { ++line_num; }
+<comment>"*"+"/"        BEGIN(INITIAL);
+
+"{"               { return LBRACE; }
+"}"               { return RBRACE; }
+"["               { return LSQUARE; }
+"]"               { return RSQUARE; }
+"("               { return LPAR; }
+")"               { return RPAR; }
+";"               { return SEMI; }
+":"               { return COLON; }
+"+"               { return PLUS; }
+"-"               { return MINUS; }
+"*"               { return MUL_OP; }
+"/"               { return DIV_OP; }
+"%"               { return MOD_OP; }
+"&"               { return AND_OP; }
+"|"               { return OR_OP; }
+"!"               { return NOT_OP; }
+"="               { return ASSIGN; }
+"<"               { return LT; }
+">"               { return GT; }
+"<<"              { return SHL_OP; }
+">>"              { return SHR_OP; }
+"=="              { return EQ; }
+"!="              { return NOTEQ; }
+"<="              { return LTEQ; }
+">="              { return GTEQ; }
+"&&"              { return ANDAND; }
+"||"              { return OROR; }
+","               { return COMMA; }
+
+"do"              { return DO; }
+"else"            { return ELSE; }
+"for"             { return FOR; }
+"if"              { return IF; }
+"int"             { yylval.intval = INTEGER_TYPE; return TYPE; }
+"while"           { return WHILE; }
+"return"          { return RETURN; }
+"read"            { return READ; }
+"write"           { return WRITE; }
+
+{ID}              { yylval.svalue=strdup(yytext); return IDENTIFIER; }
+{DIGIT}+          { yylval.intval = atoi( yytext );
+                    return(NUMBER); }
+
+.                 { yyerror("Error: unexpected token");
+                    num_error++;
+                    return (-1); /* invalid token */
+                  }

+ 2134 - 0
acse/Acse.output

@@ -0,0 +1,2134 @@
+Terminals which are not used
+
+   COLON
+   MOD_OP
+   FOR
+   NOT
+
+
+State 25 conflicts: 1 shift/reduce
+
+
+Grammar
+
+    0 $accept: program $end
+
+    1 program: var_declarations statements
+
+    2 var_declarations: var_declarations var_declaration
+    3                 | /* empty */
+
+    4 var_declaration: TYPE declaration_list SEMI
+
+    5 declaration_list: declaration_list COMMA declaration
+    6                 | declaration
+
+    7 declaration: IDENTIFIER ASSIGN NUMBER
+    8            | IDENTIFIER LSQUARE NUMBER RSQUARE
+    9            | IDENTIFIER
+
+   10 code_block: statement
+   11           | LBRACE statements RBRACE
+
+   12 statements: statements statement
+   13           | statement
+
+   14 statement: assign_statement SEMI
+   15          | control_statement
+   16          | read_write_statement SEMI
+   17          | SEMI
+
+   18 control_statement: if_statement
+   19                  | do_while_statement SEMI
+   20                  | while_statement
+   21                  | return_statement SEMI
+
+   22 read_write_statement: read_statement
+   23                     | write_statement
+
+   24 assign_statement: IDENTIFIER LSQUARE exp RSQUARE ASSIGN exp
+   25                 | IDENTIFIER ASSIGN exp
+
+   26 if_statement: if_stmt
+
+   27 @1: /* empty */
+
+   28 if_statement: if_stmt ELSE @1 code_block
+
+   29 return_statement: RETURN
+
+   30 read_statement: READ LPAR IDENTIFIER RPAR
+
+   31 write_statement: WRITE LPAR exp RPAR
+
+   32 @2: /* empty */
+
+   33 @3: /* empty */
+
+   34 while_statement: WHILE @2 LPAR exp RPAR @3 code_block
+
+   35 @4: /* empty */
+
+   36 do_while_statement: DO @4 code_block WHILE LPAR exp RPAR
+
+   37 @5: /* empty */
+
+   38 @6: /* empty */
+
+   39 if_stmt: IF @5 LPAR exp RPAR @6 code_block
+
+   40 exp: NUMBER
+   41    | IDENTIFIER
+   42    | IDENTIFIER LSQUARE exp RSQUARE
+   43    | NOT_OP NUMBER
+   44    | NOT_OP IDENTIFIER
+   45    | exp AND_OP exp
+   46    | exp OR_OP exp
+   47    | exp PLUS exp
+   48    | exp MINUS exp
+   49    | exp MUL_OP exp
+   50    | exp DIV_OP exp
+   51    | exp LT exp
+   52    | exp GT exp
+   53    | exp EQ exp
+   54    | exp NOTEQ exp
+   55    | exp LTEQ exp
+   56    | exp GTEQ exp
+   57    | exp SHL_OP exp
+   58    | exp SHR_OP exp
+   59    | exp ANDAND exp
+   60    | exp OROR exp
+   61    | LPAR exp RPAR
+   62    | MINUS exp
+
+
+Terminals, with rules where they appear
+
+$end (0) 0
+error (256)
+LBRACE (258) 11
+RBRACE (259) 11
+LPAR (260) 30 31 34 36 39 61
+RPAR (261) 30 31 34 36 39 61
+LSQUARE (262) 8 24 42
+RSQUARE (263) 8 24 42
+SEMI (264) 4 14 16 17 19 21
+COLON (265)
+PLUS (266) 47
+MINUS (267) 48 62
+MUL_OP (268) 49
+DIV_OP (269) 50
+MOD_OP (270)
+AND_OP (271) 45
+OR_OP (272) 46
+NOT_OP (273) 43 44
+ASSIGN (274) 7 24 25
+LT (275) 51
+GT (276) 52
+SHL_OP (277) 57
+SHR_OP (278) 58
+EQ (279) 53
+NOTEQ (280) 54
+LTEQ (281) 55
+GTEQ (282) 56
+ANDAND (283) 59
+OROR (284) 60
+COMMA (285) 5
+ELSE (286) 28
+FOR (287)
+RETURN (288) 29
+READ (289) 30
+WRITE (290) 31
+DO (291) 36
+WHILE (292) 34 36
+IF (293) 39
+TYPE (294) 4
+IDENTIFIER (295) 7 8 9 24 25 30 41 42 44
+NUMBER (296) 7 8 40 43
+NOT (297)
+
+
+Nonterminals, with rules where they appear
+
+$accept (43)
+    on left: 0
+program (44)
+    on left: 1, on right: 0
+var_declarations (45)
+    on left: 2 3, on right: 1 2
+var_declaration (46)
+    on left: 4, on right: 2
+declaration_list (47)
+    on left: 5 6, on right: 4 5
+declaration (48)
+    on left: 7 8 9, on right: 5 6
+code_block (49)
+    on left: 10 11, on right: 28 34 36 39
+statements (50)
+    on left: 12 13, on right: 1 11 12
+statement (51)
+    on left: 14 15 16 17, on right: 10 12 13
+control_statement (52)
+    on left: 18 19 20 21, on right: 15
+read_write_statement (53)
+    on left: 22 23, on right: 16
+assign_statement (54)
+    on left: 24 25, on right: 14
+if_statement (55)
+    on left: 26 28, on right: 18
+@1 (56)
+    on left: 27, on right: 28
+return_statement (57)
+    on left: 29, on right: 21
+read_statement (58)
+    on left: 30, on right: 22
+write_statement (59)
+    on left: 31, on right: 23
+while_statement (60)
+    on left: 34, on right: 20
+@2 (61)
+    on left: 32, on right: 34
+@3 (62)
+    on left: 33, on right: 34
+do_while_statement (63)
+    on left: 36, on right: 19
+@4 (64)
+    on left: 35, on right: 36
+if_stmt (65)
+    on left: 39, on right: 26 28
+@5 (66)
+    on left: 37, on right: 39
+@6 (67)
+    on left: 38, on right: 39
+exp (68)
+    on left: 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
+    58 59 60 61 62, on right: 24 25 31 34 36 39 42 45 46 47 48 49 50
+    51 52 53 54 55 56 57 58 59 60 61 62
+
+
+state 0
+
+    0 $accept: . program $end
+
+    $default  reduce using rule 3 (var_declarations)
+
+    program           go to state 1
+    var_declarations  go to state 2
+
+
+state 1
+
+    0 $accept: program . $end
+
+    $end  shift, and go to state 3
+
+
+state 2
+
+    1 program: var_declarations . statements
+    2 var_declarations: var_declarations . var_declaration
+
+    SEMI        shift, and go to state 4
+    RETURN      shift, and go to state 5
+    READ        shift, and go to state 6
+    WRITE       shift, and go to state 7
+    DO          shift, and go to state 8
+    WHILE       shift, and go to state 9
+    IF          shift, and go to state 10
+    TYPE        shift, and go to state 11
+    IDENTIFIER  shift, and go to state 12
+
+    var_declaration       go to state 13
+    statements            go to state 14
+    statement             go to state 15
+    control_statement     go to state 16
+    read_write_statement  go to state 17
+    assign_statement      go to state 18
+    if_statement          go to state 19
+    return_statement      go to state 20
+    read_statement        go to state 21
+    write_statement       go to state 22
+    while_statement       go to state 23
+    do_while_statement    go to state 24
+    if_stmt               go to state 25
+
+
+state 3
+
+    0 $accept: program $end .
+
+    $default  accept
+
+
+state 4
+
+   17 statement: SEMI .
+
+    $default  reduce using rule 17 (statement)
+
+
+state 5
+
+   29 return_statement: RETURN .
+
+    $default  reduce using rule 29 (return_statement)
+
+
+state 6
+
+   30 read_statement: READ . LPAR IDENTIFIER RPAR
+
+    LPAR  shift, and go to state 26
+
+
+state 7
+
+   31 write_statement: WRITE . LPAR exp RPAR
+
+    LPAR  shift, and go to state 27
+
+
+state 8
+
+   36 do_while_statement: DO . @4 code_block WHILE LPAR exp RPAR
+
+    $default  reduce using rule 35 (@4)
+
+    @4  go to state 28
+
+
+state 9
+
+   34 while_statement: WHILE . @2 LPAR exp RPAR @3 code_block
+
+    $default  reduce using rule 32 (@2)
+
+    @2  go to state 29
+
+
+state 10
+
+   39 if_stmt: IF . @5 LPAR exp RPAR @6 code_block
+
+    $default  reduce using rule 37 (@5)
+
+    @5  go to state 30
+
+
+state 11
+
+    4 var_declaration: TYPE . declaration_list SEMI
+
+    IDENTIFIER  shift, and go to state 31
+
+    declaration_list  go to state 32
+    declaration       go to state 33
+
+
+state 12
+
+   24 assign_statement: IDENTIFIER . LSQUARE exp RSQUARE ASSIGN exp
+   25                 | IDENTIFIER . ASSIGN exp
+
+    LSQUARE  shift, and go to state 34
+    ASSIGN   shift, and go to state 35
+
+
+state 13
+
+    2 var_declarations: var_declarations var_declaration .
+
+    $default  reduce using rule 2 (var_declarations)
+
+
+state 14
+
+    1 program: var_declarations statements .
+   12 statements: statements . statement
+
+    SEMI        shift, and go to state 4
+    RETURN      shift, and go to state 5
+    READ        shift, and go to state 6
+    WRITE       shift, and go to state 7
+    DO          shift, and go to state 8
+    WHILE       shift, and go to state 9
+    IF          shift, and go to state 10
+    IDENTIFIER  shift, and go to state 12
+
+    $default  reduce using rule 1 (program)
+
+    statement             go to state 36
+    control_statement     go to state 16
+    read_write_statement  go to state 17
+    assign_statement      go to state 18
+    if_statement          go to state 19
+    return_statement      go to state 20
+    read_statement        go to state 21
+    write_statement       go to state 22
+    while_statement       go to state 23
+    do_while_statement    go to state 24
+    if_stmt               go to state 25
+
+
+state 15
+
+   13 statements: statement .
+
+    $default  reduce using rule 13 (statements)
+
+
+state 16
+
+   15 statement: control_statement .
+
+    $default  reduce using rule 15 (statement)
+
+
+state 17
+
+   16 statement: read_write_statement . SEMI
+
+    SEMI  shift, and go to state 37
+
+
+state 18
+
+   14 statement: assign_statement . SEMI
+
+    SEMI  shift, and go to state 38
+
+
+state 19
+
+   18 control_statement: if_statement .
+
+    $default  reduce using rule 18 (control_statement)
+
+
+state 20
+
+   21 control_statement: return_statement . SEMI
+
+    SEMI  shift, and go to state 39
+
+
+state 21
+
+   22 read_write_statement: read_statement .
+
+    $default  reduce using rule 22 (read_write_statement)
+
+
+state 22
+
+   23 read_write_statement: write_statement .
+
+    $default  reduce using rule 23 (read_write_statement)
+
+
+state 23
+
+   20 control_statement: while_statement .
+
+    $default  reduce using rule 20 (control_statement)
+
+
+state 24
+
+   19 control_statement: do_while_statement . SEMI
+
+    SEMI  shift, and go to state 40
+
+
+state 25
+
+   26 if_statement: if_stmt .
+   28             | if_stmt . ELSE @1 code_block
+
+    ELSE  shift, and go to state 41
+
+    ELSE      [reduce using rule 26 (if_statement)]
+    $default  reduce using rule 26 (if_statement)
+
+
+state 26
+
+   30 read_statement: READ LPAR . IDENTIFIER RPAR
+
+    IDENTIFIER  shift, and go to state 42
+
+
+state 27
+
+   31 write_statement: WRITE LPAR . exp RPAR
+
+    LPAR        shift, and go to state 43
+    MINUS       shift, and go to state 44
+    NOT_OP      shift, and go to state 45
+    IDENTIFIER  shift, and go to state 46
+    NUMBER      shift, and go to state 47
+
+    exp  go to state 48
+
+
+state 28
+
+   36 do_while_statement: DO @4 . code_block WHILE LPAR exp RPAR
+
+    LBRACE      shift, and go to state 49
+    SEMI        shift, and go to state 4
+    RETURN      shift, and go to state 5
+    READ        shift, and go to state 6
+    WRITE       shift, and go to state 7
+    DO          shift, and go to state 8
+    WHILE       shift, and go to state 9
+    IF          shift, and go to state 10
+    IDENTIFIER  shift, and go to state 12
+
+    code_block            go to state 50
+    statement             go to state 51
+    control_statement     go to state 16
+    read_write_statement  go to state 17
+    assign_statement      go to state 18
+    if_statement          go to state 19
+    return_statement      go to state 20
+    read_statement        go to state 21
+    write_statement       go to state 22
+    while_statement       go to state 23
+    do_while_statement    go to state 24
+    if_stmt               go to state 25
+
+
+state 29
+
+   34 while_statement: WHILE @2 . LPAR exp RPAR @3 code_block
+
+    LPAR  shift, and go to state 52
+
+
+state 30
+
+   39 if_stmt: IF @5 . LPAR exp RPAR @6 code_block
+
+    LPAR  shift, and go to state 53
+
+
+state 31
+
+    7 declaration: IDENTIFIER . ASSIGN NUMBER
+    8            | IDENTIFIER . LSQUARE NUMBER RSQUARE
+    9            | IDENTIFIER .
+
+    LSQUARE  shift, and go to state 54
+    ASSIGN   shift, and go to state 55
+
+    $default  reduce using rule 9 (declaration)
+
+
+state 32
+
+    4 var_declaration: TYPE declaration_list . SEMI
+    5 declaration_list: declaration_list . COMMA declaration
+
+    SEMI   shift, and go to state 56
+    COMMA  shift, and go to state 57
+
+
+state 33
+
+    6 declaration_list: declaration .
+
+    $default  reduce using rule 6 (declaration_list)
+
+
+state 34
+
+   24 assign_statement: IDENTIFIER LSQUARE . exp RSQUARE ASSIGN exp
+
+    LPAR        shift, and go to state 43
+    MINUS       shift, and go to state 44
+    NOT_OP      shift, and go to state 45
+    IDENTIFIER  shift, and go to state 46
+    NUMBER      shift, and go to state 47
+
+    exp  go to state 58
+
+
+state 35
+
+   25 assign_statement: IDENTIFIER ASSIGN . exp
+
+    LPAR        shift, and go to state 43
+    MINUS       shift, and go to state 44
+    NOT_OP      shift, and go to state 45
+    IDENTIFIER  shift, and go to state 46
+    NUMBER      shift, and go to state 47
+
+    exp  go to state 59
+
+
+state 36
+
+   12 statements: statements statement .
+
+    $default  reduce using rule 12 (statements)
+
+
+state 37
+
+   16 statement: read_write_statement SEMI .
+
+    $default  reduce using rule 16 (statement)
+
+
+state 38
+
+   14 statement: assign_statement SEMI .
+
+    $default  reduce using rule 14 (statement)
+
+
+state 39
+
+   21 control_statement: return_statement SEMI .
+
+    $default  reduce using rule 21 (control_statement)
+
+
+state 40
+
+   19 control_statement: do_while_statement SEMI .
+
+    $default  reduce using rule 19 (control_statement)
+
+
+state 41
+
+   28 if_statement: if_stmt ELSE . @1 code_block
+
+    $default  reduce using rule 27 (@1)
+
+    @1  go to state 60
+
+
+state 42
+
+   30 read_statement: READ LPAR IDENTIFIER . RPAR
+
+    RPAR  shift, and go to state 61
+
+
+state 43
+
+   61 exp: LPAR . exp RPAR
+
+    LPAR        shift, and go to state 43
+    MINUS       shift, and go to state 44
+    NOT_OP      shift, and go to state 45
+    IDENTIFIER  shift, and go to state 46
+    NUMBER      shift, and go to state 47
+
+    exp  go to state 62
+
+
+state 44
+
+   62 exp: MINUS . exp
+
+    LPAR        shift, and go to state 43
+    MINUS       shift, and go to state 44
+    NOT_OP      shift, and go to state 45
+    IDENTIFIER  shift, and go to state 46
+    NUMBER      shift, and go to state 47
+
+    exp  go to state 63
+
+
+state 45
+
+   43 exp: NOT_OP . NUMBER
+   44    | NOT_OP . IDENTIFIER
+
+    IDENTIFIER  shift, and go to state 64
+    NUMBER      shift, and go to state 65
+
+
+state 46
+
+   41 exp: IDENTIFIER .
+   42    | IDENTIFIER . LSQUARE exp RSQUARE
+
+    LSQUARE  shift, and go to state 66
+
+    $default  reduce using rule 41 (exp)
+
+
+state 47
+
+   40 exp: NUMBER .
+
+    $default  reduce using rule 40 (exp)
+
+
+state 48
+
+   31 write_statement: WRITE LPAR exp . RPAR
+   45 exp: exp . AND_OP exp
+   46    | exp . OR_OP exp
+   47    | exp . PLUS exp
+   48    | exp . MINUS exp
+   49    | exp . MUL_OP exp
+   50    | exp . DIV_OP exp
+   51    | exp . LT exp
+   52    | exp . GT exp
+   53    | exp . EQ exp
+   54    | exp . NOTEQ exp
+   55    | exp . LTEQ exp
+   56    | exp . GTEQ exp
+   57    | exp . SHL_OP exp
+   58    | exp . SHR_OP exp
+   59    | exp . ANDAND exp
+   60    | exp . OROR exp
+
+    RPAR    shift, and go to state 67
+    PLUS    shift, and go to state 68
+    MINUS   shift, and go to state 69
+    MUL_OP  shift, and go to state 70
+    DIV_OP  shift, and go to state 71
+    AND_OP  shift, and go to state 72
+    OR_OP   shift, and go to state 73
+    LT      shift, and go to state 74
+    GT      shift, and go to state 75
+    SHL_OP  shift, and go to state 76
+    SHR_OP  shift, and go to state 77
+    EQ      shift, and go to state 78
+    NOTEQ   shift, and go to state 79
+    LTEQ    shift, and go to state 80
+    GTEQ    shift, and go to state 81
+    ANDAND  shift, and go to state 82
+    OROR    shift, and go to state 83
+
+
+state 49
+
+   11 code_block: LBRACE . statements RBRACE
+
+    SEMI        shift, and go to state 4
+    RETURN      shift, and go to state 5
+    READ        shift, and go to state 6
+    WRITE       shift, and go to state 7
+    DO          shift, and go to state 8
+    WHILE       shift, and go to state 9
+    IF          shift, and go to state 10
+    IDENTIFIER  shift, and go to state 12
+
+    statements            go to state 84
+    statement             go to state 15
+    control_statement     go to state 16
+    read_write_statement  go to state 17
+    assign_statement      go to state 18
+    if_statement          go to state 19
+    return_statement      go to state 20
+    read_statement        go to state 21
+    write_statement       go to state 22
+    while_statement       go to state 23
+    do_while_statement    go to state 24
+    if_stmt               go to state 25
+
+
+state 50
+
+   36 do_while_statement: DO @4 code_block . WHILE LPAR exp RPAR
+
+    WHILE  shift, and go to state 85
+
+
+state 51
+
+   10 code_block: statement .
+
+    $default  reduce using rule 10 (code_block)
+
+
+state 52
+
+   34 while_statement: WHILE @2 LPAR . exp RPAR @3 code_block
+
+    LPAR        shift, and go to state 43
+    MINUS       shift, and go to state 44
+    NOT_OP      shift, and go to state 45
+    IDENTIFIER  shift, and go to state 46
+    NUMBER      shift, and go to state 47
+
+    exp  go to state 86
+
+
+state 53
+
+   39 if_stmt: IF @5 LPAR . exp RPAR @6 code_block
+
+    LPAR        shift, and go to state 43
+    MINUS       shift, and go to state 44
+    NOT_OP      shift, and go to state 45
+    IDENTIFIER  shift, and go to state 46
+    NUMBER      shift, and go to state 47
+
+    exp  go to state 87
+
+
+state 54
+
+    8 declaration: IDENTIFIER LSQUARE . NUMBER RSQUARE
+
+    NUMBER  shift, and go to state 88
+
+
+state 55
+
+    7 declaration: IDENTIFIER ASSIGN . NUMBER
+
+    NUMBER  shift, and go to state 89
+
+
+state 56
+
+    4 var_declaration: TYPE declaration_list SEMI .
+
+    $default  reduce using rule 4 (var_declaration)
+
+
+state 57
+
+    5 declaration_list: declaration_list COMMA . declaration
+
+    IDENTIFIER  shift, and go to state 31
+
+    declaration  go to state 90
+
+
+state 58
+
+   24 assign_statement: IDENTIFIER LSQUARE exp . RSQUARE ASSIGN exp
+   45 exp: exp . AND_OP exp
+   46    | exp . OR_OP exp
+   47    | exp . PLUS exp
+   48    | exp . MINUS exp
+   49    | exp . MUL_OP exp
+   50    | exp . DIV_OP exp
+   51    | exp . LT exp
+   52    | exp . GT exp
+   53    | exp . EQ exp
+   54    | exp . NOTEQ exp
+   55    | exp . LTEQ exp
+   56    | exp . GTEQ exp
+   57    | exp . SHL_OP exp
+   58    | exp . SHR_OP exp
+   59    | exp . ANDAND exp
+   60    | exp . OROR exp
+
+    RSQUARE  shift, and go to state 91
+    PLUS     shift, and go to state 68
+    MINUS    shift, and go to state 69
+    MUL_OP   shift, and go to state 70
+    DIV_OP   shift, and go to state 71
+    AND_OP   shift, and go to state 72
+    OR_OP    shift, and go to state 73
+    LT       shift, and go to state 74
+    GT       shift, and go to state 75
+    SHL_OP   shift, and go to state 76
+    SHR_OP   shift, and go to state 77
+    EQ       shift, and go to state 78
+    NOTEQ    shift, and go to state 79
+    LTEQ     shift, and go to state 80
+    GTEQ     shift, and go to state 81
+    ANDAND   shift, and go to state 82
+    OROR     shift, and go to state 83
+
+
+state 59
+
+   25 assign_statement: IDENTIFIER ASSIGN exp .
+   45 exp: exp . AND_OP exp
+   46    | exp . OR_OP exp
+   47    | exp . PLUS exp
+   48    | exp . MINUS exp
+   49    | exp . MUL_OP exp
+   50    | exp . DIV_OP exp
+   51    | exp . LT exp
+   52    | exp . GT exp
+   53    | exp . EQ exp
+   54    | exp . NOTEQ exp
+   55    | exp . LTEQ exp
+   56    | exp . GTEQ exp
+   57    | exp . SHL_OP exp
+   58    | exp . SHR_OP exp
+   59    | exp . ANDAND exp
+   60    | exp . OROR exp
+
+    PLUS    shift, and go to state 68
+    MINUS   shift, and go to state 69
+    MUL_OP  shift, and go to state 70
+    DIV_OP  shift, and go to state 71
+    AND_OP  shift, and go to state 72
+    OR_OP   shift, and go to state 73
+    LT      shift, and go to state 74
+    GT      shift, and go to state 75
+    SHL_OP  shift, and go to state 76
+    SHR_OP  shift, and go to state 77
+    EQ      shift, and go to state 78
+    NOTEQ   shift, and go to state 79
+    LTEQ    shift, and go to state 80
+    GTEQ    shift, and go to state 81
+    ANDAND  shift, and go to state 82
+    OROR    shift, and go to state 83
+
+    $default  reduce using rule 25 (assign_statement)
+
+
+state 60
+
+   28 if_statement: if_stmt ELSE @1 . code_block
+
+    LBRACE      shift, and go to state 49
+    SEMI        shift, and go to state 4
+    RETURN      shift, and go to state 5
+    READ        shift, and go to state 6
+    WRITE       shift, and go to state 7
+    DO          shift, and go to state 8
+    WHILE       shift, and go to state 9
+    IF          shift, and go to state 10
+    IDENTIFIER  shift, and go to state 12
+
+    code_block            go to state 92
+    statement             go to state 51
+    control_statement     go to state 16
+    read_write_statement  go to state 17
+    assign_statement      go to state 18
+    if_statement          go to state 19
+    return_statement      go to state 20
+    read_statement        go to state 21
+    write_statement       go to state 22
+    while_statement       go to state 23
+    do_while_statement    go to state 24
+    if_stmt               go to state 25
+
+
+state 61
+
+   30 read_statement: READ LPAR IDENTIFIER RPAR .
+
+    $default  reduce using rule 30 (read_statement)
+
+
+state 62
+
+   45 exp: exp . AND_OP exp
+   46    | exp . OR_OP exp
+   47    | exp . PLUS exp
+   48    | exp . MINUS exp
+   49    | exp . MUL_OP exp
+   50    | exp . DIV_OP exp
+   51    | exp . LT exp
+   52    | exp . GT exp
+   53    | exp . EQ exp
+   54    | exp . NOTEQ exp
+   55    | exp . LTEQ exp
+   56    | exp . GTEQ exp
+   57    | exp . SHL_OP exp
+   58    | exp . SHR_OP exp
+   59    | exp . ANDAND exp
+   60    | exp . OROR exp
+   61    | LPAR exp . RPAR
+
+    RPAR    shift, and go to state 93
+    PLUS    shift, and go to state 68
+    MINUS   shift, and go to state 69
+    MUL_OP  shift, and go to state 70
+    DIV_OP  shift, and go to state 71
+    AND_OP  shift, and go to state 72
+    OR_OP   shift, and go to state 73
+    LT      shift, and go to state 74
+    GT      shift, and go to state 75
+    SHL_OP  shift, and go to state 76
+    SHR_OP  shift, and go to state 77
+    EQ      shift, and go to state 78
+    NOTEQ   shift, and go to state 79
+    LTEQ    shift, and go to state 80
+    GTEQ    shift, and go to state 81
+    ANDAND  shift, and go to state 82
+    OROR    shift, and go to state 83
+
+
+state 63
+
+   45 exp: exp . AND_OP exp
+   46    | exp . OR_OP exp
+   47    | exp . PLUS exp
+   48    | exp . MINUS exp
+   49    | exp . MUL_OP exp
+   50    | exp . DIV_OP exp
+   51    | exp . LT exp
+   52    | exp . GT exp
+   53    | exp . EQ exp
+   54    | exp . NOTEQ exp
+   55    | exp . LTEQ exp
+   56    | exp . GTEQ exp
+   57    | exp . SHL_OP exp
+   58    | exp . SHR_OP exp
+   59    | exp . ANDAND exp
+   60    | exp . OROR exp
+   62    | MINUS exp .
+
+    MUL_OP  shift, and go to state 70
+    DIV_OP  shift, and go to state 71
+
+    $default  reduce using rule 62 (exp)
+
+
+state 64
+
+   44 exp: NOT_OP IDENTIFIER .
+
+    $default  reduce using rule 44 (exp)
+
+
+state 65
+
+   43 exp: NOT_OP NUMBER .
+
+    $default  reduce using rule 43 (exp)
+
+
+state 66
+
+   42 exp: IDENTIFIER LSQUARE . exp RSQUARE
+
+    LPAR        shift, and go to state 43
+    MINUS       shift, and go to state 44
+    NOT_OP      shift, and go to state 45
+    IDENTIFIER  shift, and go to state 46
+    NUMBER      shift, and go to state 47
+
+    exp  go to state 94
+
+
+state 67
+
+   31 write_statement: WRITE LPAR exp RPAR .
+
+    $default  reduce using rule 31 (write_statement)
+
+
+state 68
+
+   47 exp: exp PLUS . exp
+
+    LPAR        shift, and go to state 43
+    MINUS       shift, and go to state 44
+    NOT_OP      shift, and go to state 45
+    IDENTIFIER  shift, and go to state 46
+    NUMBER      shift, and go to state 47
+
+    exp  go to state 95
+
+
+state 69
+
+   48 exp: exp MINUS . exp
+
+    LPAR        shift, and go to state 43
+    MINUS       shift, and go to state 44
+    NOT_OP      shift, and go to state 45
+    IDENTIFIER  shift, and go to state 46
+    NUMBER      shift, and go to state 47
+
+    exp  go to state 96
+
+
+state 70
+
+   49 exp: exp MUL_OP . exp
+
+    LPAR        shift, and go to state 43
+    MINUS       shift, and go to state 44
+    NOT_OP      shift, and go to state 45
+    IDENTIFIER  shift, and go to state 46
+    NUMBER      shift, and go to state 47
+
+    exp  go to state 97
+
+
+state 71
+
+   50 exp: exp DIV_OP . exp
+
+    LPAR        shift, and go to state 43
+    MINUS       shift, and go to state 44
+    NOT_OP      shift, and go to state 45
+    IDENTIFIER  shift, and go to state 46
+    NUMBER      shift, and go to state 47
+
+    exp  go to state 98
+
+
+state 72
+
+   45 exp: exp AND_OP . exp
+
+    LPAR        shift, and go to state 43
+    MINUS       shift, and go to state 44
+    NOT_OP      shift, and go to state 45
+    IDENTIFIER  shift, and go to state 46
+    NUMBER      shift, and go to state 47
+
+    exp  go to state 99
+
+
+state 73
+
+   46 exp: exp OR_OP . exp
+
+    LPAR        shift, and go to state 43
+    MINUS       shift, and go to state 44
+    NOT_OP      shift, and go to state 45
+    IDENTIFIER  shift, and go to state 46
+    NUMBER      shift, and go to state 47
+
+    exp  go to state 100
+
+
+state 74
+
+   51 exp: exp LT . exp
+
+    LPAR        shift, and go to state 43
+    MINUS       shift, and go to state 44
+    NOT_OP      shift, and go to state 45
+    IDENTIFIER  shift, and go to state 46
+    NUMBER      shift, and go to state 47
+
+    exp  go to state 101
+
+
+state 75
+
+   52 exp: exp GT . exp
+
+    LPAR        shift, and go to state 43
+    MINUS       shift, and go to state 44
+    NOT_OP      shift, and go to state 45
+    IDENTIFIER  shift, and go to state 46
+    NUMBER      shift, and go to state 47
+
+    exp  go to state 102
+
+
+state 76
+
+   57 exp: exp SHL_OP . exp
+
+    LPAR        shift, and go to state 43
+    MINUS       shift, and go to state 44
+    NOT_OP      shift, and go to state 45
+    IDENTIFIER  shift, and go to state 46
+    NUMBER      shift, and go to state 47
+
+    exp  go to state 103
+
+
+state 77
+
+   58 exp: exp SHR_OP . exp
+
+    LPAR        shift, and go to state 43
+    MINUS       shift, and go to state 44
+    NOT_OP      shift, and go to state 45
+    IDENTIFIER  shift, and go to state 46
+    NUMBER      shift, and go to state 47
+
+    exp  go to state 104
+
+
+state 78
+
+   53 exp: exp EQ . exp
+
+    LPAR        shift, and go to state 43
+    MINUS       shift, and go to state 44
+    NOT_OP      shift, and go to state 45
+    IDENTIFIER  shift, and go to state 46
+    NUMBER      shift, and go to state 47
+
+    exp  go to state 105
+
+
+state 79
+
+   54 exp: exp NOTEQ . exp
+
+    LPAR        shift, and go to state 43
+    MINUS       shift, and go to state 44
+    NOT_OP      shift, and go to state 45
+    IDENTIFIER  shift, and go to state 46
+    NUMBER      shift, and go to state 47
+
+    exp  go to state 106
+
+
+state 80
+
+   55 exp: exp LTEQ . exp
+
+    LPAR        shift, and go to state 43
+    MINUS       shift, and go to state 44
+    NOT_OP      shift, and go to state 45
+    IDENTIFIER  shift, and go to state 46
+    NUMBER      shift, and go to state 47
+
+    exp  go to state 107
+
+
+state 81
+
+   56 exp: exp GTEQ . exp
+
+    LPAR        shift, and go to state 43
+    MINUS       shift, and go to state 44
+    NOT_OP      shift, and go to state 45
+    IDENTIFIER  shift, and go to state 46
+    NUMBER      shift, and go to state 47
+
+    exp  go to state 108
+
+
+state 82
+
+   59 exp: exp ANDAND . exp
+
+    LPAR        shift, and go to state 43
+    MINUS       shift, and go to state 44
+    NOT_OP      shift, and go to state 45
+    IDENTIFIER  shift, and go to state 46
+    NUMBER      shift, and go to state 47
+
+    exp  go to state 109
+
+
+state 83
+
+   60 exp: exp OROR . exp
+
+    LPAR        shift, and go to state 43
+    MINUS       shift, and go to state 44
+    NOT_OP      shift, and go to state 45
+    IDENTIFIER  shift, and go to state 46
+    NUMBER      shift, and go to state 47
+
+    exp  go to state 110
+
+
+state 84
+
+   11 code_block: LBRACE statements . RBRACE
+   12 statements: statements . statement
+
+    RBRACE      shift, and go to state 111
+    SEMI        shift, and go to state 4
+    RETURN      shift, and go to state 5
+    READ        shift, and go to state 6
+    WRITE       shift, and go to state 7
+    DO          shift, and go to state 8
+    WHILE       shift, and go to state 9
+    IF          shift, and go to state 10
+    IDENTIFIER  shift, and go to state 12
+
+    statement             go to state 36
+    control_statement     go to state 16
+    read_write_statement  go to state 17
+    assign_statement      go to state 18
+    if_statement          go to state 19
+    return_statement      go to state 20
+    read_statement        go to state 21
+    write_statement       go to state 22
+    while_statement       go to state 23
+    do_while_statement    go to state 24
+    if_stmt               go to state 25
+
+
+state 85
+
+   36 do_while_statement: DO @4 code_block WHILE . LPAR exp RPAR
+
+    LPAR  shift, and go to state 112
+
+
+state 86
+
+   34 while_statement: WHILE @2 LPAR exp . RPAR @3 code_block
+   45 exp: exp . AND_OP exp
+   46    | exp . OR_OP exp
+   47    | exp . PLUS exp
+   48    | exp . MINUS exp
+   49    | exp . MUL_OP exp
+   50    | exp . DIV_OP exp
+   51    | exp . LT exp
+   52    | exp . GT exp
+   53    | exp . EQ exp
+   54    | exp . NOTEQ exp
+   55    | exp . LTEQ exp
+   56    | exp . GTEQ exp
+   57    | exp . SHL_OP exp
+   58    | exp . SHR_OP exp
+   59    | exp . ANDAND exp
+   60    | exp . OROR exp
+
+    RPAR    shift, and go to state 113
+    PLUS    shift, and go to state 68
+    MINUS   shift, and go to state 69
+    MUL_OP  shift, and go to state 70
+    DIV_OP  shift, and go to state 71
+    AND_OP  shift, and go to state 72
+    OR_OP   shift, and go to state 73
+    LT      shift, and go to state 74
+    GT      shift, and go to state 75
+    SHL_OP  shift, and go to state 76
+    SHR_OP  shift, and go to state 77
+    EQ      shift, and go to state 78
+    NOTEQ   shift, and go to state 79
+    LTEQ    shift, and go to state 80
+    GTEQ    shift, and go to state 81
+    ANDAND  shift, and go to state 82
+    OROR    shift, and go to state 83
+
+
+state 87
+
+   39 if_stmt: IF @5 LPAR exp . RPAR @6 code_block
+   45 exp: exp . AND_OP exp
+   46    | exp . OR_OP exp
+   47    | exp . PLUS exp
+   48    | exp . MINUS exp
+   49    | exp . MUL_OP exp
+   50    | exp . DIV_OP exp
+   51    | exp . LT exp
+   52    | exp . GT exp
+   53    | exp . EQ exp
+   54    | exp . NOTEQ exp
+   55    | exp . LTEQ exp
+   56    | exp . GTEQ exp
+   57    | exp . SHL_OP exp
+   58    | exp . SHR_OP exp
+   59    | exp . ANDAND exp
+   60    | exp . OROR exp
+
+    RPAR    shift, and go to state 114
+    PLUS    shift, and go to state 68
+    MINUS   shift, and go to state 69
+    MUL_OP  shift, and go to state 70
+    DIV_OP  shift, and go to state 71
+    AND_OP  shift, and go to state 72
+    OR_OP   shift, and go to state 73
+    LT      shift, and go to state 74
+    GT      shift, and go to state 75
+    SHL_OP  shift, and go to state 76
+    SHR_OP  shift, and go to state 77
+    EQ      shift, and go to state 78
+    NOTEQ   shift, and go to state 79
+    LTEQ    shift, and go to state 80
+    GTEQ    shift, and go to state 81
+    ANDAND  shift, and go to state 82
+    OROR    shift, and go to state 83
+
+
+state 88
+
+    8 declaration: IDENTIFIER LSQUARE NUMBER . RSQUARE
+
+    RSQUARE  shift, and go to state 115
+
+
+state 89
+
+    7 declaration: IDENTIFIER ASSIGN NUMBER .
+
+    $default  reduce using rule 7 (declaration)
+
+
+state 90
+
+    5 declaration_list: declaration_list COMMA declaration .
+
+    $default  reduce using rule 5 (declaration_list)
+
+
+state 91
+
+   24 assign_statement: IDENTIFIER LSQUARE exp RSQUARE . ASSIGN exp
+
+    ASSIGN  shift, and go to state 116
+
+
+state 92
+
+   28 if_statement: if_stmt ELSE @1 code_block .
+
+    $default  reduce using rule 28 (if_statement)
+
+
+state 93
+
+   61 exp: LPAR exp RPAR .
+
+    $default  reduce using rule 61 (exp)
+
+
+state 94
+
+   42 exp: IDENTIFIER LSQUARE exp . RSQUARE
+   45    | exp . AND_OP exp
+   46    | exp . OR_OP exp
+   47    | exp . PLUS exp
+   48    | exp . MINUS exp
+   49    | exp . MUL_OP exp
+   50    | exp . DIV_OP exp
+   51    | exp . LT exp
+   52    | exp . GT exp
+   53    | exp . EQ exp
+   54    | exp . NOTEQ exp
+   55    | exp . LTEQ exp
+   56    | exp . GTEQ exp
+   57    | exp . SHL_OP exp
+   58    | exp . SHR_OP exp
+   59    | exp . ANDAND exp
+   60    | exp . OROR exp
+
+    RSQUARE  shift, and go to state 117
+    PLUS     shift, and go to state 68
+    MINUS    shift, and go to state 69
+    MUL_OP   shift, and go to state 70
+    DIV_OP   shift, and go to state 71
+    AND_OP   shift, and go to state 72
+    OR_OP    shift, and go to state 73
+    LT       shift, and go to state 74
+    GT       shift, and go to state 75
+    SHL_OP   shift, and go to state 76
+    SHR_OP   shift, and go to state 77
+    EQ       shift, and go to state 78
+    NOTEQ    shift, and go to state 79
+    LTEQ     shift, and go to state 80
+    GTEQ     shift, and go to state 81
+    ANDAND   shift, and go to state 82
+    OROR     shift, and go to state 83
+
+
+state 95
+
+   45 exp: exp . AND_OP exp
+   46    | exp . OR_OP exp
+   47    | exp . PLUS exp
+   47    | exp PLUS exp .
+   48    | exp . MINUS exp
+   49    | exp . MUL_OP exp
+   50    | exp . DIV_OP exp
+   51    | exp . LT exp
+   52    | exp . GT exp
+   53    | exp . EQ exp
+   54    | exp . NOTEQ exp
+   55    | exp . LTEQ exp
+   56    | exp . GTEQ exp
+   57    | exp . SHL_OP exp
+   58    | exp . SHR_OP exp
+   59    | exp . ANDAND exp
+   60    | exp . OROR exp
+
+    MUL_OP  shift, and go to state 70
+    DIV_OP  shift, and go to state 71
+
+    $default  reduce using rule 47 (exp)
+
+
+state 96
+
+   45 exp: exp . AND_OP exp
+   46    | exp . OR_OP exp
+   47    | exp . PLUS exp
+   48    | exp . MINUS exp
+   48    | exp MINUS exp .
+   49    | exp . MUL_OP exp
+   50    | exp . DIV_OP exp
+   51    | exp . LT exp
+   52    | exp . GT exp
+   53    | exp . EQ exp
+   54    | exp . NOTEQ exp
+   55    | exp . LTEQ exp
+   56    | exp . GTEQ exp
+   57    | exp . SHL_OP exp
+   58    | exp . SHR_OP exp
+   59    | exp . ANDAND exp
+   60    | exp . OROR exp
+
+    MUL_OP  shift, and go to state 70
+    DIV_OP  shift, and go to state 71
+
+    $default  reduce using rule 48 (exp)
+
+
+state 97
+
+   45 exp: exp . AND_OP exp
+   46    | exp . OR_OP exp
+   47    | exp . PLUS exp
+   48    | exp . MINUS exp
+   49    | exp . MUL_OP exp
+   49    | exp MUL_OP exp .
+   50    | exp . DIV_OP exp
+   51    | exp . LT exp
+   52    | exp . GT exp
+   53    | exp . EQ exp
+   54    | exp . NOTEQ exp
+   55    | exp . LTEQ exp
+   56    | exp . GTEQ exp
+   57    | exp . SHL_OP exp
+   58    | exp . SHR_OP exp
+   59    | exp . ANDAND exp
+   60    | exp . OROR exp
+
+    $default  reduce using rule 49 (exp)
+
+
+state 98
+
+   45 exp: exp . AND_OP exp
+   46    | exp . OR_OP exp
+   47    | exp . PLUS exp
+   48    | exp . MINUS exp
+   49    | exp . MUL_OP exp
+   50    | exp . DIV_OP exp
+   50    | exp DIV_OP exp .
+   51    | exp . LT exp
+   52    | exp . GT exp
+   53    | exp . EQ exp
+   54    | exp . NOTEQ exp
+   55    | exp . LTEQ exp
+   56    | exp . GTEQ exp
+   57    | exp . SHL_OP exp
+   58    | exp . SHR_OP exp
+   59    | exp . ANDAND exp
+   60    | exp . OROR exp
+
+    $default  reduce using rule 50 (exp)
+
+
+state 99
+
+   45 exp: exp . AND_OP exp
+   45    | exp AND_OP exp .
+   46    | exp . OR_OP exp
+   47    | exp . PLUS exp
+   48    | exp . MINUS exp
+   49    | exp . MUL_OP exp
+   50    | exp . DIV_OP exp
+   51    | exp . LT exp
+   52    | exp . GT exp
+   53    | exp . EQ exp
+   54    | exp . NOTEQ exp
+   55    | exp . LTEQ exp
+   56    | exp . GTEQ exp
+   57    | exp . SHL_OP exp
+   58    | exp . SHR_OP exp
+   59    | exp . ANDAND exp
+   60    | exp . OROR exp
+
+    PLUS    shift, and go to state 68
+    MINUS   shift, and go to state 69
+    MUL_OP  shift, and go to state 70
+    DIV_OP  shift, and go to state 71
+    LT      shift, and go to state 74
+    GT      shift, and go to state 75
+    SHL_OP  shift, and go to state 76
+    SHR_OP  shift, and go to state 77
+    EQ      shift, and go to state 78
+    NOTEQ   shift, and go to state 79
+    LTEQ    shift, and go to state 80
+    GTEQ    shift, and go to state 81
+
+    $default  reduce using rule 45 (exp)
+
+
+state 100
+
+   45 exp: exp . AND_OP exp
+   46    | exp . OR_OP exp
+   46    | exp OR_OP exp .
+   47    | exp . PLUS exp
+   48    | exp . MINUS exp
+   49    | exp . MUL_OP exp
+   50    | exp . DIV_OP exp
+   51    | exp . LT exp
+   52    | exp . GT exp
+   53    | exp . EQ exp
+   54    | exp . NOTEQ exp
+   55    | exp . LTEQ exp
+   56    | exp . GTEQ exp
+   57    | exp . SHL_OP exp
+   58    | exp . SHR_OP exp
+   59    | exp . ANDAND exp
+   60    | exp . OROR exp
+
+    PLUS    shift, and go to state 68
+    MINUS   shift, and go to state 69
+    MUL_OP  shift, and go to state 70
+    DIV_OP  shift, and go to state 71
+    AND_OP  shift, and go to state 72
+    LT      shift, and go to state 74
+    GT      shift, and go to state 75
+    SHL_OP  shift, and go to state 76
+    SHR_OP  shift, and go to state 77
+    EQ      shift, and go to state 78
+    NOTEQ   shift, and go to state 79
+    LTEQ    shift, and go to state 80
+    GTEQ    shift, and go to state 81
+
+    $default  reduce using rule 46 (exp)
+
+
+state 101
+
+   45 exp: exp . AND_OP exp
+   46    | exp . OR_OP exp
+   47    | exp . PLUS exp
+   48    | exp . MINUS exp
+   49    | exp . MUL_OP exp
+   50    | exp . DIV_OP exp
+   51    | exp . LT exp
+   51    | exp LT exp .
+   52    | exp . GT exp
+   53    | exp . EQ exp
+   54    | exp . NOTEQ exp
+   55    | exp . LTEQ exp
+   56    | exp . GTEQ exp
+   57    | exp . SHL_OP exp
+   58    | exp . SHR_OP exp
+   59    | exp . ANDAND exp
+   60    | exp . OROR exp
+
+    PLUS    shift, and go to state 68
+    MINUS   shift, and go to state 69
+    MUL_OP  shift, and go to state 70
+    DIV_OP  shift, and go to state 71
+    SHL_OP  shift, and go to state 76
+    SHR_OP  shift, and go to state 77
+
+    $default  reduce using rule 51 (exp)
+
+
+state 102
+
+   45 exp: exp . AND_OP exp
+   46    | exp . OR_OP exp
+   47    | exp . PLUS exp
+   48    | exp . MINUS exp
+   49    | exp . MUL_OP exp
+   50    | exp . DIV_OP exp
+   51    | exp . LT exp
+   52    | exp . GT exp
+   52    | exp GT exp .
+   53    | exp . EQ exp
+   54    | exp . NOTEQ exp
+   55    | exp . LTEQ exp
+   56    | exp . GTEQ exp
+   57    | exp . SHL_OP exp
+   58    | exp . SHR_OP exp
+   59    | exp . ANDAND exp
+   60    | exp . OROR exp
+
+    PLUS    shift, and go to state 68
+    MINUS   shift, and go to state 69
+    MUL_OP  shift, and go to state 70
+    DIV_OP  shift, and go to state 71
+    SHL_OP  shift, and go to state 76
+    SHR_OP  shift, and go to state 77
+
+    $default  reduce using rule 52 (exp)
+
+
+state 103
+
+   45 exp: exp . AND_OP exp
+   46    | exp . OR_OP exp
+   47    | exp . PLUS exp
+   48    | exp . MINUS exp
+   49    | exp . MUL_OP exp
+   50    | exp . DIV_OP exp
+   51    | exp . LT exp
+   52    | exp . GT exp
+   53    | exp . EQ exp
+   54    | exp . NOTEQ exp
+   55    | exp . LTEQ exp
+   56    | exp . GTEQ exp
+   57    | exp . SHL_OP exp
+   57    | exp SHL_OP exp .
+   58    | exp . SHR_OP exp
+   59    | exp . ANDAND exp
+   60    | exp . OROR exp
+
+    PLUS    shift, and go to state 68
+    MINUS   shift, and go to state 69
+    MUL_OP  shift, and go to state 70
+    DIV_OP  shift, and go to state 71
+
+    $default  reduce using rule 57 (exp)
+
+
+state 104
+
+   45 exp: exp . AND_OP exp
+   46    | exp . OR_OP exp
+   47    | exp . PLUS exp
+   48    | exp . MINUS exp
+   49    | exp . MUL_OP exp
+   50    | exp . DIV_OP exp
+   51    | exp . LT exp
+   52    | exp . GT exp
+   53    | exp . EQ exp
+   54    | exp . NOTEQ exp
+   55    | exp . LTEQ exp
+   56    | exp . GTEQ exp
+   57    | exp . SHL_OP exp
+   58    | exp . SHR_OP exp
+   58    | exp SHR_OP exp .
+   59    | exp . ANDAND exp
+   60    | exp . OROR exp
+
+    PLUS    shift, and go to state 68
+    MINUS   shift, and go to state 69
+    MUL_OP  shift, and go to state 70
+    DIV_OP  shift, and go to state 71
+
+    $default  reduce using rule 58 (exp)
+
+
+state 105
+
+   45 exp: exp . AND_OP exp
+   46    | exp . OR_OP exp
+   47    | exp . PLUS exp
+   48    | exp . MINUS exp
+   49    | exp . MUL_OP exp
+   50    | exp . DIV_OP exp
+   51    | exp . LT exp
+   52    | exp . GT exp
+   53    | exp . EQ exp
+   53    | exp EQ exp .
+   54    | exp . NOTEQ exp
+   55    | exp . LTEQ exp
+   56    | exp . GTEQ exp
+   57    | exp . SHL_OP exp
+   58    | exp . SHR_OP exp
+   59    | exp . ANDAND exp
+   60    | exp . OROR exp
+
+    PLUS    shift, and go to state 68
+    MINUS   shift, and go to state 69
+    MUL_OP  shift, and go to state 70
+    DIV_OP  shift, and go to state 71
+    LT      shift, and go to state 74
+    GT      shift, and go to state 75
+    SHL_OP  shift, and go to state 76
+    SHR_OP  shift, and go to state 77
+    LTEQ    shift, and go to state 80
+    GTEQ    shift, and go to state 81
+
+    $default  reduce using rule 53 (exp)
+
+
+state 106
+
+   45 exp: exp . AND_OP exp
+   46    | exp . OR_OP exp
+   47    | exp . PLUS exp
+   48    | exp . MINUS exp
+   49    | exp . MUL_OP exp
+   50    | exp . DIV_OP exp
+   51    | exp . LT exp
+   52    | exp . GT exp
+   53    | exp . EQ exp
+   54    | exp . NOTEQ exp
+   54    | exp NOTEQ exp .
+   55    | exp . LTEQ exp
+   56    | exp . GTEQ exp
+   57    | exp . SHL_OP exp
+   58    | exp . SHR_OP exp
+   59    | exp . ANDAND exp
+   60    | exp . OROR exp
+
+    PLUS    shift, and go to state 68
+    MINUS   shift, and go to state 69
+    MUL_OP  shift, and go to state 70
+    DIV_OP  shift, and go to state 71
+    LT      shift, and go to state 74
+    GT      shift, and go to state 75
+    SHL_OP  shift, and go to state 76
+    SHR_OP  shift, and go to state 77
+    LTEQ    shift, and go to state 80
+    GTEQ    shift, and go to state 81
+
+    $default  reduce using rule 54 (exp)
+
+
+state 107
+
+   45 exp: exp . AND_OP exp
+   46    | exp . OR_OP exp
+   47    | exp . PLUS exp
+   48    | exp . MINUS exp
+   49    | exp . MUL_OP exp
+   50    | exp . DIV_OP exp
+   51    | exp . LT exp
+   52    | exp . GT exp
+   53    | exp . EQ exp
+   54    | exp . NOTEQ exp
+   55    | exp . LTEQ exp
+   55    | exp LTEQ exp .
+   56    | exp . GTEQ exp
+   57    | exp . SHL_OP exp
+   58    | exp . SHR_OP exp
+   59    | exp . ANDAND exp
+   60    | exp . OROR exp
+
+    PLUS    shift, and go to state 68
+    MINUS   shift, and go to state 69
+    MUL_OP  shift, and go to state 70
+    DIV_OP  shift, and go to state 71
+    SHL_OP  shift, and go to state 76
+    SHR_OP  shift, and go to state 77
+
+    $default  reduce using rule 55 (exp)
+
+
+state 108
+
+   45 exp: exp . AND_OP exp
+   46    | exp . OR_OP exp
+   47    | exp . PLUS exp
+   48    | exp . MINUS exp
+   49    | exp . MUL_OP exp
+   50    | exp . DIV_OP exp
+   51    | exp . LT exp
+   52    | exp . GT exp
+   53    | exp . EQ exp
+   54    | exp . NOTEQ exp
+   55    | exp . LTEQ exp
+   56    | exp . GTEQ exp
+   56    | exp GTEQ exp .
+   57    | exp . SHL_OP exp
+   58    | exp . SHR_OP exp
+   59    | exp . ANDAND exp
+   60    | exp . OROR exp
+
+    PLUS    shift, and go to state 68
+    MINUS   shift, and go to state 69
+    MUL_OP  shift, and go to state 70
+    DIV_OP  shift, and go to state 71
+    SHL_OP  shift, and go to state 76
+    SHR_OP  shift, and go to state 77
+
+    $default  reduce using rule 56 (exp)
+
+
+state 109
+
+   45 exp: exp . AND_OP exp
+   46    | exp . OR_OP exp
+   47    | exp . PLUS exp
+   48    | exp . MINUS exp
+   49    | exp . MUL_OP exp
+   50    | exp . DIV_OP exp
+   51    | exp . LT exp
+   52    | exp . GT exp
+   53    | exp . EQ exp
+   54    | exp . NOTEQ exp
+   55    | exp . LTEQ exp
+   56    | exp . GTEQ exp
+   57    | exp . SHL_OP exp
+   58    | exp . SHR_OP exp
+   59    | exp . ANDAND exp
+   59    | exp ANDAND exp .
+   60    | exp . OROR exp
+
+    PLUS    shift, and go to state 68
+    MINUS   shift, and go to state 69
+    MUL_OP  shift, and go to state 70
+    DIV_OP  shift, and go to state 71
+    AND_OP  shift, and go to state 72
+    OR_OP   shift, and go to state 73
+    LT      shift, and go to state 74
+    GT      shift, and go to state 75
+    SHL_OP  shift, and go to state 76
+    SHR_OP  shift, and go to state 77
+    EQ      shift, and go to state 78
+    NOTEQ   shift, and go to state 79
+    LTEQ    shift, and go to state 80
+    GTEQ    shift, and go to state 81
+
+    $default  reduce using rule 59 (exp)
+
+
+state 110
+
+   45 exp: exp . AND_OP exp
+   46    | exp . OR_OP exp
+   47    | exp . PLUS exp
+   48    | exp . MINUS exp
+   49    | exp . MUL_OP exp
+   50    | exp . DIV_OP exp
+   51    | exp . LT exp
+   52    | exp . GT exp
+   53    | exp . EQ exp
+   54    | exp . NOTEQ exp
+   55    | exp . LTEQ exp
+   56    | exp . GTEQ exp
+   57    | exp . SHL_OP exp
+   58    | exp . SHR_OP exp
+   59    | exp . ANDAND exp
+   60    | exp . OROR exp
+   60    | exp OROR exp .
+
+    PLUS    shift, and go to state 68
+    MINUS   shift, and go to state 69
+    MUL_OP  shift, and go to state 70
+    DIV_OP  shift, and go to state 71
+    AND_OP  shift, and go to state 72
+    OR_OP   shift, and go to state 73
+    LT      shift, and go to state 74
+    GT      shift, and go to state 75
+    SHL_OP  shift, and go to state 76
+    SHR_OP  shift, and go to state 77
+    EQ      shift, and go to state 78
+    NOTEQ   shift, and go to state 79
+    LTEQ    shift, and go to state 80
+    GTEQ    shift, and go to state 81
+    ANDAND  shift, and go to state 82
+
+    $default  reduce using rule 60 (exp)
+
+
+state 111
+
+   11 code_block: LBRACE statements RBRACE .
+
+    $default  reduce using rule 11 (code_block)
+
+
+state 112
+
+   36 do_while_statement: DO @4 code_block WHILE LPAR . exp RPAR
+
+    LPAR        shift, and go to state 43
+    MINUS       shift, and go to state 44
+    NOT_OP      shift, and go to state 45
+    IDENTIFIER  shift, and go to state 46
+    NUMBER      shift, and go to state 47
+
+    exp  go to state 118
+
+
+state 113
+
+   34 while_statement: WHILE @2 LPAR exp RPAR . @3 code_block
+
+    $default  reduce using rule 33 (@3)
+
+    @3  go to state 119
+
+
+state 114
+
+   39 if_stmt: IF @5 LPAR exp RPAR . @6 code_block
+
+    $default  reduce using rule 38 (@6)
+
+    @6  go to state 120
+
+
+state 115
+
+    8 declaration: IDENTIFIER LSQUARE NUMBER RSQUARE .
+
+    $default  reduce using rule 8 (declaration)
+
+
+state 116
+
+   24 assign_statement: IDENTIFIER LSQUARE exp RSQUARE ASSIGN . exp
+
+    LPAR        shift, and go to state 43
+    MINUS       shift, and go to state 44
+    NOT_OP      shift, and go to state 45
+    IDENTIFIER  shift, and go to state 46
+    NUMBER      shift, and go to state 47
+
+    exp  go to state 121
+
+
+state 117
+
+   42 exp: IDENTIFIER LSQUARE exp RSQUARE .
+
+    $default  reduce using rule 42 (exp)
+
+
+state 118
+
+   36 do_while_statement: DO @4 code_block WHILE LPAR exp . RPAR
+   45 exp: exp . AND_OP exp
+   46    | exp . OR_OP exp
+   47    | exp . PLUS exp
+   48    | exp . MINUS exp
+   49    | exp . MUL_OP exp
+   50    | exp . DIV_OP exp
+   51    | exp . LT exp
+   52    | exp . GT exp
+   53    | exp . EQ exp
+   54    | exp . NOTEQ exp
+   55    | exp . LTEQ exp
+   56    | exp . GTEQ exp
+   57    | exp . SHL_OP exp
+   58    | exp . SHR_OP exp
+   59    | exp . ANDAND exp
+   60    | exp . OROR exp
+
+    RPAR    shift, and go to state 122
+    PLUS    shift, and go to state 68
+    MINUS   shift, and go to state 69
+    MUL_OP  shift, and go to state 70
+    DIV_OP  shift, and go to state 71
+    AND_OP  shift, and go to state 72
+    OR_OP   shift, and go to state 73
+    LT      shift, and go to state 74
+    GT      shift, and go to state 75
+    SHL_OP  shift, and go to state 76
+    SHR_OP  shift, and go to state 77
+    EQ      shift, and go to state 78
+    NOTEQ   shift, and go to state 79
+    LTEQ    shift, and go to state 80
+    GTEQ    shift, and go to state 81
+    ANDAND  shift, and go to state 82
+    OROR    shift, and go to state 83
+
+
+state 119
+
+   34 while_statement: WHILE @2 LPAR exp RPAR @3 . code_block
+
+    LBRACE      shift, and go to state 49
+    SEMI        shift, and go to state 4
+    RETURN      shift, and go to state 5
+    READ        shift, and go to state 6
+    WRITE       shift, and go to state 7
+    DO          shift, and go to state 8
+    WHILE       shift, and go to state 9
+    IF          shift, and go to state 10
+    IDENTIFIER  shift, and go to state 12
+
+    code_block            go to state 123
+    statement             go to state 51
+    control_statement     go to state 16
+    read_write_statement  go to state 17
+    assign_statement      go to state 18
+    if_statement          go to state 19
+    return_statement      go to state 20
+    read_statement        go to state 21
+    write_statement       go to state 22
+    while_statement       go to state 23
+    do_while_statement    go to state 24
+    if_stmt               go to state 25
+
+
+state 120
+
+   39 if_stmt: IF @5 LPAR exp RPAR @6 . code_block
+
+    LBRACE      shift, and go to state 49
+    SEMI        shift, and go to state 4
+    RETURN      shift, and go to state 5
+    READ        shift, and go to state 6
+    WRITE       shift, and go to state 7
+    DO          shift, and go to state 8
+    WHILE       shift, and go to state 9
+    IF          shift, and go to state 10
+    IDENTIFIER  shift, and go to state 12
+
+    code_block            go to state 124
+    statement             go to state 51
+    control_statement     go to state 16
+    read_write_statement  go to state 17
+    assign_statement      go to state 18
+    if_statement          go to state 19
+    return_statement      go to state 20
+    read_statement        go to state 21
+    write_statement       go to state 22
+    while_statement       go to state 23
+    do_while_statement    go to state 24
+    if_stmt               go to state 25
+
+
+state 121
+
+   24 assign_statement: IDENTIFIER LSQUARE exp RSQUARE ASSIGN exp .
+   45 exp: exp . AND_OP exp
+   46    | exp . OR_OP exp
+   47    | exp . PLUS exp
+   48    | exp . MINUS exp
+   49    | exp . MUL_OP exp
+   50    | exp . DIV_OP exp
+   51    | exp . LT exp
+   52    | exp . GT exp
+   53    | exp . EQ exp
+   54    | exp . NOTEQ exp
+   55    | exp . LTEQ exp
+   56    | exp . GTEQ exp
+   57    | exp . SHL_OP exp
+   58    | exp . SHR_OP exp
+   59    | exp . ANDAND exp
+   60    | exp . OROR exp
+
+    PLUS    shift, and go to state 68
+    MINUS   shift, and go to state 69
+    MUL_OP  shift, and go to state 70
+    DIV_OP  shift, and go to state 71
+    AND_OP  shift, and go to state 72
+    OR_OP   shift, and go to state 73
+    LT      shift, and go to state 74
+    GT      shift, and go to state 75
+    SHL_OP  shift, and go to state 76
+    SHR_OP  shift, and go to state 77
+    EQ      shift, and go to state 78
+    NOTEQ   shift, and go to state 79
+    LTEQ    shift, and go to state 80
+    GTEQ    shift, and go to state 81
+    ANDAND  shift, and go to state 82
+    OROR    shift, and go to state 83
+
+    $default  reduce using rule 24 (assign_statement)
+
+
+state 122
+
+   36 do_while_statement: DO @4 code_block WHILE LPAR exp RPAR .
+
+    $default  reduce using rule 36 (do_while_statement)
+
+
+state 123
+
+   34 while_statement: WHILE @2 LPAR exp RPAR @3 code_block .
+
+    $default  reduce using rule 34 (while_statement)
+
+
+state 124
+
+   39 if_stmt: IF @5 LPAR exp RPAR @6 code_block .
+
+    $default  reduce using rule 39 (if_stmt)

+ 666 - 0
acse/Acse.y

@@ -0,0 +1,666 @@
+%{
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * Acse.y
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+/*************************************************************************
+
+                   Compiler for the language LANCE
+
+***************************************************************************/
+
+#include <stdio.h>       
+#include <stdlib.h>
+#include <assert.h>
+#include "axe_struct.h"
+#include "axe_engine.h"
+#include "symbol_table.h"
+#include "axe_errors.h"
+#include "collections.h"
+#include "axe_expressions.h"
+#include "axe_gencode.h"
+#include "axe_utils.h"
+#include "axe_array.h"
+#include "axe_cflow_graph.h"
+#include "cflow_constants.h"
+#include "axe_transform.h"
+#include "axe_reg_alloc.h"
+#include "reg_alloc_constants.h"
+#include "axe_io_manager.h"
+#ifndef NDEBUG
+#  include "axe_debug.h"
+#endif
+
+
+
+/* global variables */
+int line_num;        /* this variable will keep track of the
+                      * source code line number. Every time that a newline
+                      * is encountered while parsing the input file, this
+                      * value is increased by 1. This value is then used
+                      * for error tracking: if the parser returns an error
+                      * or a warning, this value is used in order to notify
+                      * in which line of code the error has been found */
+int num_error;       /* the number of errors found in the code. This value
+                      * is increased by 1 every time a new error is found
+                      * in the code. */
+int num_warning;     /* As for the `num_error' global variable, this one
+                      * keeps track of all the warning messages displayed */
+
+/* errorcode is defined inside "axe_engine.c" */
+extern int errorcode;   /* this variable is used to test if an error is found
+                         * while parsing the input file. It also is set
+                         * to notify if the compiler internal state is invalid.
+                         * When the parsing process is started, the value
+                         * of `errorcode' is set to the value of the macro
+                         * `AXE_OK' defined in "axe_constants.h".
+                         * As long as everything (the parsed source code and
+                         * the internal state of the compiler) is correct,
+                         * the value of `errorcode' is set to `AXE_OK'.
+                         * When an error occurs (because the input file contains
+                         * one or more syntax errors or because something went
+                         * wrong in the machine internal state), the errorcode
+                         * is set to a value that is different from `AXE_OK'. */
+                         
+
+extern int cflow_errorcode;   /* As for `errorcode' this value is used to
+                        * test if an error occurs during the creation process of
+                        * a control flow graph. More informations can be found
+                        * analyzing the file `axe_cflow_graph.h'. */
+                     
+/* program informations */
+t_program_infos *program;  /* The singleton instance of `program'.
+                            * An instance of `t_program_infos' holds in its
+                            * internal structure, all the useful informations
+                            * about a program. For example: the assembly
+                            * (code and directives); the symbol table;
+                            * the label manager (see axe_labels.h) etc. */
+t_cflow_Graph *graph;      /* An instance of a control flow graph. This instance
+                            * will be generated starting from `program' and will
+                            * be used during the register allocation process */
+
+t_reg_allocator *RA;       /* Register allocator. It implements the "Linear scan"
+                            * algorythm */
+
+t_io_infos *file_infos;    /* input and output files used by the compiler */
+
+%}
+
+%expect 1
+
+/*=========================================================================
+                          SEMANTIC RECORDS
+=========================================================================*/
+
+%union {            
+   int intval;
+   char *svalue;
+   t_axe_expression expr;
+   t_axe_declaration *decl;
+   t_list *list;
+   t_axe_label *label;
+   t_while_statement while_stmt;
+} 
+/*=========================================================================
+                               TOKENS 
+=========================================================================*/
+%start program
+
+%token LBRACE RBRACE LPAR RPAR LSQUARE RSQUARE
+%token SEMI COLON PLUS MINUS MUL_OP DIV_OP MOD_OP
+%token AND_OP OR_OP NOT_OP
+%token ASSIGN LT GT SHL_OP SHR_OP EQ NOTEQ LTEQ GTEQ
+%token ANDAND OROR
+%token COMMA
+%token FOR
+%token RETURN
+%token READ
+%token WRITE
+
+%token <label> DO
+%token <while_stmt> WHILE
+%token <label> IF
+%token <label> ELSE
+%token <intval> TYPE
+%token <svalue> IDENTIFIER
+%token <intval> NUMBER
+
+%type <expr> exp
+%type <decl> declaration
+%type <list> declaration_list
+%type <label> if_stmt
+
+/*=========================================================================
+                          OPERATOR PRECEDENCES
+ =========================================================================*/
+
+%left COMMA
+%left ASSIGN
+%left OROR
+%left ANDAND
+%left OR_OP
+%left AND_OP
+%left EQ NOTEQ
+%left LT GT LTEQ GTEQ
+%left SHL_OP SHR_OP
+%left MINUS PLUS
+%left MUL_OP DIV_OP
+%right NOT
+
+/*=========================================================================
+                         BISON GRAMMAR
+=========================================================================*/
+%% 
+
+/* `program' is the starting non-terminal of the grammar.
+ * A program is composed by:
+      1. declarations (zero or more);
+      2. A list of instructions. (at least one instruction!).
+ * When the rule associated with the non-terminal `program' is executed,
+ * the parser notify it to the `program' singleton instance. */
+program  : var_declarations statements
+         {
+            /* Notify the end of the program. Once called
+             * the function `set_end_Program' - if necessary -
+             * introduces a `HALT' instruction into the
+             * list of instructions. */
+            set_end_Program(program);
+
+            /* return from yyparse() */
+            YYACCEPT;
+         }
+;
+
+var_declarations : var_declarations var_declaration   { /* does nothing */ }
+                 | /* empty */                        { /* does nothing */ }
+;
+
+var_declaration   : TYPE declaration_list SEMI
+                  {
+                     /* update the program infos by adding new variables */
+                     set_new_variables(program, $1, $2);
+                  }
+;
+
+declaration_list  : declaration_list COMMA declaration
+                  {  /* add the new declaration to the list of declarations */
+                     $$ = addElement($1, $3, -1);
+                  }
+                  | declaration
+                  {
+                     /* add the new declaration to the list of declarations */
+                     $$ = addElement(NULL, $1, -1);
+                  }
+;
+
+declaration : IDENTIFIER ASSIGN NUMBER
+            {
+               /* create a new instance of t_axe_declaration */
+               $$ = alloc_declaration($1, 0, 0, $3);
+
+               /* test if an `out of memory' occurred */
+               if ($$ == NULL)
+                  notifyError(AXE_OUT_OF_MEMORY);
+            }
+            | IDENTIFIER LSQUARE NUMBER RSQUARE
+            {
+               /* create a new instance of t_axe_declaration */
+               $$ = alloc_declaration($1, 1, $3, 0);
+
+                  /* test if an `out of memory' occurred */
+               if ($$ == NULL)
+                  notifyError(AXE_OUT_OF_MEMORY);
+            }
+            | IDENTIFIER
+            {
+               /* create a new instance of t_axe_declaration */
+               $$ = alloc_declaration($1, 0, 0, 0);
+               
+               /* test if an `out of memory' occurred */
+               if ($$ == NULL)
+                  notifyError(AXE_OUT_OF_MEMORY);
+            }
+;
+
+/* A block of code can be either a single statement or
+ * a set of statements enclosed between braces */
+code_block  : statement                  { /* does nothing */ }
+            | LBRACE statements RBRACE   { /* does nothing */ }
+;
+
+/* One or more code statements */
+statements  : statements statement       { /* does nothing */ }
+            | statement                  { /* does nothing */ }
+;
+
+/* A statement can be either an assignment statement or a control statement
+ * or a read/write statement or a semicolon */
+statement   : assign_statement SEMI      { /* does nothing */ }
+            | control_statement          { /* does nothing */ }
+            | read_write_statement SEMI  { /* does nothing */ }
+            | SEMI            { gen_nop_instruction(program); }
+;
+
+control_statement : if_statement         { /* does nothing */ }
+            | while_statement            { /* does nothing */ }
+            | do_while_statement SEMI    { /* does nothing */ }
+            | return_statement SEMI      { /* does nothing */ }
+;
+
+read_write_statement : read_statement  { /* does nothing */ }
+                     | write_statement { /* does nothing */ }
+;
+
+assign_statement : IDENTIFIER LSQUARE exp RSQUARE ASSIGN exp
+            {
+               /* Notify to `program' that the value $6
+                * have to be assigned to the location
+                * addressed by $1[$3]. Where $1 is obviously
+                * the array/pointer identifier, $3 is an expression
+                * that holds an integer value. That value will be
+                * used as an index for the array $1 */
+               storeArrayElement(program, $1, $3, $6);
+
+               /* free the memory associated with the IDENTIFIER.
+                * The use of the free instruction is required
+                * because of the value associated with IDENTIFIER.
+                * The value of IDENTIFIER is a string created
+                * by a call to the function `strdup' (see Acse.lex) */
+               free($1);
+            }
+            | IDENTIFIER ASSIGN exp
+            {
+               int location;
+               t_axe_instruction *instr;
+
+               /* in order to assign a value to a variable, we have to
+                * know where the variable is located (i.e. in which register).
+                * the function `get_symbol_location' is used in order
+                * to retrieve the register location assigned to
+                * a given identifier.
+                * A symbol table keeps track of the location of every
+                * declared variable.
+                * `get_symbol_location' perform a query on the symbol table
+                * in order to discover the correct location of
+                * the variable with $1 as identifier */
+               
+               /* get the location of the symbol with the given ID. */
+               location = get_symbol_location(program, $1, 0);
+
+               /* update the value of location */
+               if ($3.expression_type == IMMEDIATE)
+                  gen_move_immediate(program, location, $3.value);
+               else
+                  instr = gen_add_instruction
+                        (program, location, REG_0, $3.value, CG_DIRECT_ALL);
+
+               /* free the memory associated with the IDENTIFIER */
+               free($1);
+            }
+;
+            
+if_statement   : if_stmt
+               {
+                  /* fix the `label_else' */
+                  assignLabel(program, $1);
+               }
+               | if_stmt ELSE
+               {
+                  /* reserve a new label that points to the address where to jump if
+                   * `exp' is verified */
+                  $2 = newLabel(program);
+   
+                  /* exit from the if-else */
+                  gen_bt_instruction (program, $2, 0);
+   
+                  /* fix the `label_else' */
+                  assignLabel(program, $1);
+               }
+               code_block
+               {
+                  /* fix the `label_else' */
+                  assignLabel(program, $2);
+               }
+;
+            
+if_stmt  :  IF
+               {
+                  /* the label that points to the address where to jump if
+                   * `exp' is not verified */
+                  $1 = newLabel(program);
+               }
+               LPAR exp RPAR
+               {
+                     if ($4.expression_type == IMMEDIATE)
+                         gen_load_immediate(program, $4.value);
+                     else
+                         gen_andb_instruction(program, $4.value,
+                             $4.value, $4.value, CG_DIRECT_ALL);
+
+                     /* if `exp' returns FALSE, jump to the label $1 */
+                     gen_beq_instruction (program, $1, 0);
+               }
+               code_block { $$ = $1; }
+;
+
+while_statement  : WHILE
+                  {
+                     /* initialize the value of the non-terminal */
+                     $1 = create_while_statement();
+
+                     /* reserve and fix a new label */
+                     $1.label_condition
+                           = assignNewLabel(program);
+                  }
+                  LPAR exp RPAR
+                  {
+                     if ($4.expression_type == IMMEDIATE)
+                        gen_load_immediate(program, $4.value);
+                     else
+                         gen_andb_instruction(program, $4.value,
+                             $4.value, $4.value, CG_DIRECT_ALL);
+
+                     /* reserve a new label. This new label will point
+                      * to the first instruction after the while code
+                      * block */
+                     $1.label_end = newLabel(program);
+
+                     /* if `exp' returns FALSE, jump to the label $1.label_end */
+                     gen_beq_instruction (program, $1.label_end, 0);
+                  }
+                  code_block
+                  {
+                     /* jump to the beginning of the loop */
+                     gen_bt_instruction
+                           (program, $1.label_condition, 0);
+
+                     /* fix the label `label_end' */
+                     assignLabel(program, $1.label_end);
+                  }
+;
+                  
+do_while_statement  : DO
+                     {
+                        /* the label that points to the address where to jump if
+                         * `exp' is not verified */
+                        $1 = newLabel(program);
+                        
+                        /* fix the label */
+                        assignLabel(program, $1);
+                     }
+                     code_block WHILE LPAR exp RPAR
+                     {
+                           if ($6.expression_type == IMMEDIATE)
+                               gen_load_immediate(program, $6.value);
+                           else
+                               gen_andb_instruction(program, $6.value,
+                                   $6.value, $6.value, CG_DIRECT_ALL);
+
+                           /* if `exp' returns TRUE, jump to the label $1 */
+                           gen_bne_instruction (program, $1, 0);
+                     }
+;
+
+return_statement : RETURN
+            {
+               /* insert an HALT instruction */
+               gen_halt_instruction(program);
+            }
+;
+
+read_statement : READ LPAR IDENTIFIER RPAR 
+            {
+               int location;
+               
+               /* read from standard input an integer value and assign
+                * it to a variable associated with the given identifier */
+               /* get the location of the symbol with the given ID */
+               
+               /* lookup the symbol table and fetch the register location
+                * associated with the IDENTIFIER $3. */
+               location = get_symbol_location(program, $3, 0);
+
+               /* insert a read instruction */
+               gen_read_instruction (program, location);
+
+               /* free the memory associated with the IDENTIFIER */
+               free($3);
+            }
+;
+            
+write_statement : WRITE LPAR exp RPAR 
+            {
+   
+               int location;
+
+               if ($3.expression_type == IMMEDIATE)
+               {
+                  /* load `immediate' into a new register. Returns the new register
+                   * identifier or REG_INVALID if an error occurs */
+                  location = gen_load_immediate(program, $3.value);
+               }
+               else
+                  location = $3.value;
+
+               /* write to standard output an integer value */
+               gen_write_instruction (program, location);
+            }
+;
+
+exp: NUMBER      { $$ = create_expression ($1, IMMEDIATE); }
+   | IDENTIFIER  {
+                     int location;
+   
+                     /* get the location of the symbol with the given ID */
+                     location = get_symbol_location(program, $1, 0);
+                     
+                     /* return the register location of IDENTIFIER as
+                      * a value for `exp' */
+                     $$ = create_expression (location, REGISTER);
+
+                     /* free the memory associated with the IDENTIFIER */
+                     free($1);
+   }
+   | IDENTIFIER LSQUARE exp RSQUARE {
+                     int reg;
+                     
+                     /* load the value IDENTIFIER[exp]
+                      * into `arrayElement' */
+                     reg = loadArrayElement(program, $1, $3);
+
+                     /* create a new expression */
+                     $$ = create_expression (reg, REGISTER);
+
+                     /* free the memory associated with the IDENTIFIER */
+                     free($1);
+   }
+   | NOT_OP NUMBER   {  if ($2 == 0)
+                           $$ = create_expression (1, IMMEDIATE);
+                        else
+                           $$ = create_expression (0, IMMEDIATE);
+   }
+   | NOT_OP IDENTIFIER  {
+                           int identifier_location;
+                           int output_register;
+   
+                           /* get the location of the symbol with the given ID */
+                           identifier_location =
+                                 get_symbol_location(program, $2, 0);
+
+                           /* generate a NOT instruction. In order to do this,
+                            * at first we have to ask for a free register where
+                            * to store the result of the NOT instruction. */
+                           output_register = getNewRegister(program);
+
+                           /* Now we are able to generate a NOT instruction */
+                           gen_notl_instruction (program, output_register
+                                 , identifier_location);
+
+                           $$ = create_expression (output_register, REGISTER);
+
+                           /* free the memory associated with the IDENTIFIER */
+                           free($2);
+   }
+   | exp AND_OP exp     {
+                           $$ = handle_bin_numeric_op(program, $1, $3, ANDB);
+   }
+   | exp OR_OP exp      {
+                           $$ = handle_bin_numeric_op(program, $1, $3, ORB);
+   }
+   | exp PLUS exp       {
+                           $$ = handle_bin_numeric_op(program, $1, $3, ADD);
+   }
+   | exp MINUS exp      {
+                           $$ = handle_bin_numeric_op(program, $1, $3, SUB);
+   }
+   | exp MUL_OP exp     {
+                           $$ = handle_bin_numeric_op(program, $1, $3, MUL);
+   }
+   | exp DIV_OP exp     {
+                           $$ = handle_bin_numeric_op(program, $1, $3, DIV);
+   }
+   | exp LT exp      {
+                        $$ = handle_binary_comparison (program, $1, $3, _LT_);
+   }
+   | exp GT exp      {
+                        $$ = handle_binary_comparison (program, $1, $3, _GT_);
+   }
+   | exp EQ exp      {
+                        $$ = handle_binary_comparison (program, $1, $3, _EQ_);
+   }
+   | exp NOTEQ exp   {
+                        $$ = handle_binary_comparison (program, $1, $3, _NOTEQ_);
+   }
+   | exp LTEQ exp    {
+                        $$ = handle_binary_comparison (program, $1, $3, _LTEQ_);
+   }
+   | exp GTEQ exp    {
+                        $$ = handle_binary_comparison (program, $1, $3, _GTEQ_);
+   }
+   | exp SHL_OP exp  {  $$ = handle_bin_numeric_op(program, $1, $3, SHL); }
+   | exp SHR_OP exp  {  $$ = handle_bin_numeric_op(program, $1, $3, SHR); }
+   | exp ANDAND exp  {  $$ = handle_bin_numeric_op(program, $1, $3, ANDL); }
+   | exp OROR exp    {  $$ = handle_bin_numeric_op(program, $1, $3, ORL); }
+   | LPAR exp RPAR   { $$ = $2; }
+   | MINUS exp       {
+                        if ($2.expression_type == IMMEDIATE)
+                        {
+                           $$ = $2;
+                           $$.value = - ($$.value);
+                        }
+                        else
+                        {
+                           t_axe_expression exp_r0;
+
+                           /* create an expression for regisrer REG_0 */
+                           exp_r0.value = REG_0;
+                           exp_r0.expression_type = REGISTER;
+                           
+                           $$ = handle_bin_numeric_op
+                                 (program, exp_r0, $2, SUB);
+                        }
+                     }
+;
+
+%%
+/*=========================================================================
+                                  MAIN
+=========================================================================*/
+int main (int argc, char **argv)
+{
+   /* initialize all the compiler data structures and global variables */
+   init_compiler(argc, argv);
+   
+   /* start the parsing procedure */
+   yyparse();
+   
+#ifndef NDEBUG
+   fprintf(stdout, "Parsing process completed. \n");
+#endif
+
+   /* test if the parsing process completed succesfully */
+   checkConsistency();
+   
+#ifndef NDEBUG
+   fprintf(stdout, "Creating a control flow graph. \n");
+#endif
+
+   /* create the control flow graph */
+   graph = createFlowGraph(program->instructions);
+   checkConsistency();
+
+#ifndef NDEBUG
+   assert(program != NULL);
+   assert(program->sy_table != NULL);
+   assert(file_infos != NULL);
+   assert(file_infos->syTable_output != NULL);
+   printSymbolTable(program->sy_table, file_infos->syTable_output);
+   printGraphInfos(graph, file_infos->cfg_1, 0);
+      
+   fprintf(stdout, "Updating the basic blocks. \n");
+#endif
+      
+   /* update the control flow graph by inserting load and stores inside
+   * every basic block */
+   graph = insertLoadAndStoreInstr(program, graph);
+
+#ifndef NDEBUG
+   fprintf(stdout, "Executing a liveness analysis on the intermediate code \n");
+#endif
+   performLivenessAnalysis(graph);
+   checkConsistency();
+
+#ifndef NDEBUG
+   printGraphInfos(graph, file_infos->cfg_2, 1);
+#endif
+      
+#ifndef NDEBUG
+   fprintf(stdout, "Starting the register allocation process. \n");
+#endif
+   /* initialize the register allocator by using the control flow
+    * informations stored into the control flow graph */
+   RA = initializeRegAlloc(graph);
+      
+   /* execute the linear scan algorythm */
+   execute_linear_scan(RA);
+      
+#ifndef NDEBUG
+   printRegAllocInfos(RA, file_infos->reg_alloc_output);
+#endif
+
+#ifndef NDEBUG
+   fprintf(stdout, "Updating the control flow informations. \n");
+#endif
+   /* apply changes to the program informations by using the informations
+   * of the register allocation process */
+   updateProgramInfos(program, graph, RA);
+
+#ifndef NDEBUG
+   fprintf(stdout, "Writing the assembly file... \n");
+#endif
+   writeAssembly(program, file_infos->output_file_name);
+      
+#ifndef NDEBUG
+   fprintf(stdout, "Assembly written on file \"%s\".\n", file_infos->output_file_name);
+#endif
+   
+   /* shutdown the compiler */
+   shutdownCompiler(0);
+
+   return 0;
+}
+
+/*=========================================================================
+                                 YYERROR
+=========================================================================*/
+int yyerror(const char* errmsg)
+{
+   errorcode = AXE_SYNTAX_ERROR;
+   
+   return 0;
+}

+ 25 - 0
acse/Makefile

@@ -0,0 +1,25 @@
+project = ../bin/acse
+objects = Acse.tab.c lex.yy.c
+hfiles = $(wildcard *.h)
+cfiles = $(filter-out $(objects), $(wildcard *.c))
+
+.PHONY: all clean
+
+all: $(project)
+
+$(project) : $(objects) $(cfiles) $(hfiles)
+	gcc -o $@ $(objects) $(cfiles)
+
+Acse.tab.c : Acse.y
+	bison -d $<
+
+lex.yy.c : Acse.lex Acse.tab.h
+	flex $<
+
+clean :
+	rm -f Acse.tab.c Acse.tab.h lex.yy.c $(project) $(project:=.exe)
+
+# This rule keeps Make happy, while the %.tab.h file is generated by
+#  the bison rule above
+%.tab.h: %.tab.c
+	if [ -a $@ ]; then touch $@; else false; fi

+ 118 - 0
acse/axe_array.c

@@ -0,0 +1,118 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * axe_array.c
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#include "axe_array.h"
+#include "axe_gencode.h"
+#include "symbol_table.h"
+#include "axe_utils.h"
+#include "axe_errors.h"
+
+void storeArrayElement(t_program_infos *program, char *ID
+            , t_axe_expression index, t_axe_expression data)
+{
+   int address;
+   
+   address =  loadArrayAddress(program, ID, index);
+
+   if (data.expression_type == REGISTER)
+   {
+      /* load the value indirectly into `mova_register' */
+      gen_add_instruction(program, address, REG_0
+               , data.value, CG_INDIRECT_DEST);
+   }
+   else
+   {
+      int imm_register;
+
+      imm_register = gen_load_immediate(program, data.value);
+
+      /* load the value indirectly into `load_register' */
+      gen_add_instruction(program, address, REG_0
+               ,imm_register, CG_INDIRECT_DEST);
+   }
+}
+
+int loadArrayElement(t_program_infos *program
+               , char *ID, t_axe_expression index)
+{
+   int load_register;
+   int address;
+
+   /* retrieve the address of the array slot */
+   address = loadArrayAddress(program, ID, index);
+
+   /* get a new register */
+   load_register = getNewRegister(program);
+
+   /* load the value into `load_register' */
+   gen_add_instruction(program, load_register, REG_0
+            , address, CG_INDIRECT_SOURCE);
+
+   /* return the register ID that holds the required data */
+   return load_register;
+}
+
+int loadArrayAddress(t_program_infos *program
+            , char *ID, t_axe_expression index)
+{
+   int mova_register;
+   t_axe_label *label;
+
+   /* preconditions */
+   if (program == NULL)
+      notifyError(AXE_PROGRAM_NOT_INITIALIZED);
+
+   if (ID == NULL)
+      notifyError(AXE_VARIABLE_ID_UNSPECIFIED);
+   
+   /* retrieve the label associated with the given
+   * identifier */
+   label = getLabelFromVariableID(program, ID);
+                     
+   /* test if an error occurred */
+   if (label == NULL)
+      return REG_INVALID;
+
+   /* get a new register */
+   mova_register = getNewRegister(program);
+
+   /* generate the MOVA instruction */
+   gen_mova_instruction(program, mova_register, label, 0);
+
+   if (index.expression_type == IMMEDIATE)
+   {
+      if (index.value != 0)
+      {
+         if (is_int16(index.value))
+         {
+            gen_addi_instruction (program, mova_register
+                     , mova_register, index.value);
+         }
+         else
+         {
+            int tmp_reg = gen_load_immediate (program, index.value);
+            gen_add_instruction (program, mova_register
+                     , mova_register, tmp_reg, CG_DIRECT_ALL);
+         }
+      }
+   }
+   else
+   {
+      assert(index.expression_type == REGISTER);
+
+      /* We are making the following assumption:
+      * the type can only be an INTEGER_TYPE */
+      gen_add_instruction(program, mova_register, mova_register
+               , index.value, CG_DIRECT_ALL);
+   }
+
+   /* return the identifier of the register that contains
+    * the value of the array slot */
+   return mova_register;
+}

+ 51 - 0
acse/axe_array.h

@@ -0,0 +1,51 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * axe_array.h
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#ifndef _AXE_ARRAY_H
+#define _AXE_ARRAY_H
+
+#include "axe_engine.h"
+#include "axe_struct.h"
+
+/* This function generates instructions that load the content of
+ * an element of an array in a register.  This function takes as
+ * input: a variable identifier (ID) that refers to an array
+ * value; an index value that refers to a specific element of
+ * the array.  It returns the location identifier for the
+ * register that will contain the value of the array element at
+ * position `index'.  `index' is an expression: its value can be
+ * either a register location (i.e., the value of `index' is
+ * stored inside a register) or an immediate value. */
+extern int loadArrayElement(t_program_infos *program
+               , char *ID, t_axe_expression index);
+
+/* This function generates instructions that load the address of
+ * an element of an array in a regester.  This function takes as
+ * input: a variable identifier (ID) that refers to an array
+ * value; an index value that refers to a specific element of
+ * the array.  It returns the location identifier for the
+ * register that will contain the address of the array element
+ * at position `index'.  `index' is an expression: its value can
+ * be either a register location (i.e., the value of `index' is
+ * stored inside a register) or an immediate value. */
+extern int loadArrayAddress(t_program_infos *program
+               , char *ID, t_axe_expression index);
+
+/* This function generates instructions that store a value
+ * specified by `data' into the element at position `index' of
+ * the array `ID'.  This function takes as input: a variable
+ * identifier (ID) that refers to an array value; an index value
+ * that refers to a specific element of the array; a value to be
+ * stored (data).  `data' and `index' are expressions: their
+ * value can be either register locations (i.e. their values are
+ * stored inside a register) or immediate values. */
+extern void storeArrayElement(t_program_infos *program, char *ID
+            , t_axe_expression index, t_axe_expression data);
+
+#endif

+ 1290 - 0
acse/axe_cflow_graph.c

@@ -0,0 +1,1290 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * axe_cflow_graph.c
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#include <assert.h>
+#include "axe_labels.h"
+#include "axe_cflow_graph.h"
+#include "cflow_constants.h"
+#include "collections.h"
+#include "axe_debug.h"
+
+int cflow_errorcode;
+
+
+static t_cflow_var * allocVariable (t_cflow_Graph *graph, int identifier);
+static int isEndingNode(t_axe_instruction *instr);
+static int isStartingNode(t_axe_instruction *instr);
+static int isJumpInstruction(t_axe_instruction *instr);
+static int isUnconditionalJump(t_axe_instruction *instr);
+static int isHaltInstruction(t_axe_instruction *instr);
+static int isLoadInstruction(t_axe_instruction *instr);
+static void updateFlowGraph(t_cflow_Graph *graph);
+static t_basic_block * searchLabel(t_cflow_Graph *graph, t_axe_label *label);
+static void setDefUses(t_cflow_Graph *graph, t_cflow_Node *node);
+static int performLivenessIteration(t_cflow_Graph *graph);
+static int performLivenessOnBlock(t_basic_block *current_block, t_list *out);
+static t_list * addVariableToSet(t_list *set
+               , t_cflow_var *element, int *modified);
+static int compare_CFLOW_Variables (void *a, void *b);
+static t_list * computeLiveOutVars(t_cflow_Graph *graph,t_basic_block *block);
+
+
+void performLivenessAnalysis(t_cflow_Graph *graph)
+{
+   int modified;
+
+   do
+   {
+      modified = performLivenessIteration(graph);
+   }while(modified);
+}
+
+t_list * computeLiveOutVars(t_cflow_Graph *graph, t_basic_block *block)
+{
+   t_list *current_elem;
+   t_basic_block *current_succ;
+   t_list *result;
+   t_list *liveINVars;
+
+   /* preconditions */
+   if (block == NULL)
+      return NULL;
+
+   if (graph == NULL) {
+      cflow_errorcode = CFLOW_GRAPH_UNDEFINED;
+      return NULL;
+   }
+   
+   /* initialize `current_elem' */
+   current_elem = block->succ;
+
+   /* initialize `result' */
+   result = NULL;
+   while(current_elem != NULL)
+   {
+      current_succ = (t_basic_block *) LDATA(current_elem);
+      assert(current_succ != NULL);
+
+      if (current_succ != graph->endingBlock)
+      {
+         liveINVars = getLiveINVars(current_succ);
+         
+         /* update the value of `result' */
+         result = addListToSet(result
+               , liveINVars, NULL, NULL);
+
+         /* free the temporary list of live intervals */
+         freeList(liveINVars);
+      }
+      
+      current_elem = LNEXT(current_elem);
+   }
+
+   /* postconditions */
+   return result;
+}
+
+t_list * getLiveOUTVars(t_basic_block *bblock)
+{
+   t_list *last_Element;
+   t_cflow_Node *lastNode;
+   
+   if (bblock == NULL)
+      return NULL;
+
+   if (bblock->nodes == NULL)
+      return NULL;
+
+   
+   last_Element = getLastElement(bblock->nodes);
+   lastNode = (t_cflow_Node *) LDATA(last_Element);
+   assert(lastNode != NULL);
+
+   /* return a copy of the list of variables live in
+    * input to the current basic block */
+   return cloneList(lastNode->out);
+}
+
+t_list * getLiveINVars(t_basic_block *bblock)
+{
+   t_cflow_Node *firstNode;
+   
+   if (bblock == NULL)
+      return NULL;
+
+   if (bblock->nodes == NULL)
+      return NULL;
+
+   firstNode = (t_cflow_Node *) LDATA(bblock->nodes);
+   assert(firstNode != NULL);
+
+   /* return a copy of the list of variables live in
+    * input to the current basic block */
+   return cloneList(firstNode->in);
+}
+
+t_list * addVariableToSet(t_list *set
+               , t_cflow_var *element, int *modified)
+{
+   /* test the preconditions */
+   if (element == NULL)
+      return set;
+
+   if (CustomfindElement(set, element
+            , compare_CFLOW_Variables) == NULL)
+   {
+      set = addElement(set, element, -1);
+      if (modified != NULL)
+         (* modified) = 1;
+   }
+
+   /* postconditions */
+   return set;
+}
+
+t_list * addVariables(t_list *set, t_list *elements, int *modified)
+{
+   /* test the preconditions */
+   if (set == NULL || elements == NULL)
+      return set;
+
+   /* update the set of variables */
+   set = addListToSet(set, elements
+         , compare_CFLOW_Variables, modified);
+   
+   /* postconditions: return the new list of variables */
+   return set;
+}
+
+int compare_CFLOW_Variables (void *a, void *b)
+{
+   t_cflow_var *varA;
+   t_cflow_var *varB;
+
+   if (a == NULL)
+   {
+      if (b == NULL)
+         return 1;
+      return 0;
+   }
+
+   if (b == NULL)
+      return 0;
+
+   varA = (t_cflow_var *) a;
+   varB = (t_cflow_var *) b;
+
+   return (varA->ID == varB->ID);
+}
+
+int performLivenessOnBlock(t_basic_block *bblock, t_list *out)
+{
+   t_list *current_element;
+   t_list *cloned_list;
+   t_cflow_Node *next_node;
+   t_cflow_Node *current_node;
+   int modified;
+
+   /* initialize the local variables */
+   modified = 0;
+
+   if (bblock == NULL || bblock->nodes == NULL) {
+      cflow_errorcode = CFLOW_INVALID_BBLOCK;
+      return modified;
+   }
+
+   current_element = getLastElement(bblock->nodes);
+   current_node = (t_cflow_Node *) LDATA(current_element);
+   assert(current_node != NULL);
+
+   /* update the out set */
+   current_node->out = addListToSet
+         (current_node->out, out, NULL, &modified);
+
+   /* update the in list */
+   cloned_list = cloneList(current_node->out);
+   
+#if CFLOW_ALWAYS_LIVEIN_R0 == (1)
+   if ((current_node->uses)[0] != NULL && (current_node->uses)[0]->ID != REG_0)
+      cloned_list = addVariableToSet
+            (cloned_list, (current_node->uses)[0], NULL);
+   if ((current_node->uses)[1] != NULL && (current_node->uses)[1]->ID != REG_0)
+      cloned_list = addVariableToSet
+            (cloned_list, (current_node->uses)[1], NULL);
+   if ((current_node->uses)[2] != NULL && (current_node->uses)[2]->ID != REG_0)
+      cloned_list = addVariableToSet
+            (cloned_list, (current_node->uses)[2], NULL);
+#else
+   if ((current_node->uses)[0] != NULL)
+      cloned_list = addVariableToSet
+            (cloned_list, (current_node->uses)[0], NULL);
+   if ((current_node->uses)[1] != NULL)
+      cloned_list = addVariableToSet
+            (cloned_list, (current_node->uses)[1], NULL);
+   
+   if ((current_node->uses)[2] != NULL)
+      cloned_list = addVariableToSet
+            (cloned_list, (current_node->uses)[2], NULL);
+#endif
+
+
+
+#if CFLOW_ALWAYS_LIVEIN_R0 == (1)
+   if (current_node->def != NULL && (current_node->def)->ID != REG_0)
+#else
+   if (current_node->def != NULL)
+#endif
+   {
+      int found = 0;
+      int current_use_idx = 0;
+      
+      do
+      {
+         if ((current_node->uses)[current_use_idx] != NULL)
+         {
+            if ((current_node->uses)[current_use_idx]->ID == current_node->def->ID)
+               found = 1;
+         }
+         
+         current_use_idx++;
+         
+      } while((found == 0) && (current_use_idx < 3));
+      
+      if (!found)
+         cloned_list = removeElement(cloned_list, current_node->def);
+   }
+   
+   current_node->in = addListToSet
+         (current_node->in, cloned_list, NULL, &modified);
+
+   /* remove the cloned list */
+   freeList(cloned_list);
+   
+   /* set the new value of next_node */
+   next_node = current_node;
+   current_element = LPREV(current_element);
+   while (current_element != NULL)
+   {
+      /* take a new node */
+      current_node = (t_cflow_Node *) LDATA(current_element);
+      assert(current_node != NULL);
+
+      /* clone the `in' list of the next_node */
+      cloned_list = cloneList(next_node->in);
+      
+      /* update the out list */
+      current_node->out = addListToSet
+            (current_node->out, cloned_list, NULL, &modified);
+      
+      /* remove the cloned list */
+      freeList(cloned_list);
+
+      /* clone the `in' list of the next_node */
+      cloned_list = cloneList(current_node->out);
+      
+      /* update the in list */
+#if CFLOW_ALWAYS_LIVEIN_R0 == (1)
+      if ((current_node->uses)[0] != NULL && (current_node->uses)[0]->ID != REG_0)
+         cloned_list = addVariableToSet
+               (cloned_list, (current_node->uses)[0], NULL);
+      if ((current_node->uses)[1] != NULL && (current_node->uses)[1]->ID != REG_0)
+         cloned_list = addVariableToSet
+               (cloned_list, (current_node->uses)[1], NULL);
+      if ((current_node->uses)[2] != NULL && (current_node->uses)[2]->ID != REG_0)
+         cloned_list = addVariableToSet
+               (cloned_list, (current_node->uses)[2], NULL);
+#else
+      if ((current_node->uses)[0] != NULL)
+         cloned_list = addVariableToSet
+               (cloned_list, (current_node->uses)[0], NULL);
+      if ((current_node->uses)[1] != NULL)
+         cloned_list = addVariableToSet
+               (cloned_list, (current_node->uses)[1], NULL);
+      if ((current_node->uses)[2] != NULL)
+         cloned_list = addVariableToSet
+               (cloned_list, (current_node->uses)[2], NULL);
+#endif
+      
+#if CFLOW_ALWAYS_LIVEIN_R0 == (1)
+      if (current_node->def != NULL && (current_node->def)->ID != REG_0)
+#else
+      if (current_node->def != NULL)
+#endif
+      {
+         int found = 0;
+         int current_use_idx = 0;
+      
+         do
+         {
+            if ((current_node->uses)[current_use_idx] != NULL)
+            {
+               if ((current_node->uses)[current_use_idx]->ID
+                        == current_node->def->ID)
+               {
+                  found = 1;
+               }
+            }
+            current_use_idx++;
+         
+         } while((found == 0) && (current_use_idx < 3));
+      
+         if (!found)
+            cloned_list = removeElement(cloned_list, current_node->def);
+      }
+
+      current_node->in = addListToSet
+            (current_node->in, cloned_list, NULL, &modified);
+
+      /* remove the cloned list */
+      freeList(cloned_list);
+      
+      /* update the loop control informations */
+      current_element = LPREV(current_element);
+      next_node = current_node;
+   }
+
+   /* return the `modified' value */
+   return modified;
+}
+
+static int isLoadInstruction(t_axe_instruction *instr)
+{
+   if (instr == NULL) {
+      cflow_errorcode = CFLOW_INVALID_INSTRUCTION;
+      return 0;
+   }
+
+   return (instr->opcode == LOAD) ? 1 : 0;
+}
+
+int isHaltInstruction(t_axe_instruction *instr)
+{
+   if (instr == NULL) {
+      cflow_errorcode = CFLOW_INVALID_INSTRUCTION;
+      return 0;
+   }
+
+   return (instr->opcode == HALT) ? 1 : 0;
+}
+
+int performLivenessIteration(t_cflow_Graph *graph)
+{
+   int modified;
+   t_list *current_element;
+   t_basic_block *current_bblock;
+
+   /* initialize the value of the local variable `modified' */
+   modified = 0;
+
+   /* test the preconditions */
+   if (graph == NULL) {
+      cflow_errorcode = CFLOW_GRAPH_UNDEFINED;
+      return modified;
+   }
+
+   /* test if `graph->endingBlock' is valid */
+   if (graph->endingBlock == NULL) {
+      cflow_errorcode = CFLOW_INVALID_BBLOCK;
+      return modified;
+   }
+
+   /* retrieve the last basic block in the list */
+   current_element = getLastElement(graph->blocks);
+   
+   while(current_element != NULL)
+   {
+      t_list *live_out_vars;
+      
+      current_bblock = (t_basic_block *) LDATA(current_element);
+      assert(current_bblock != NULL);
+
+      /* retrieve the variables that will be live out from this block */
+      live_out_vars = computeLiveOutVars(graph, current_bblock);
+
+      /* test if an error occurred */
+      if (cflow_errorcode != CFLOW_OK)
+         return modified;
+
+      /* retrieve the liveness informations for the current bblock */
+      if (performLivenessOnBlock(current_bblock, live_out_vars))
+         modified = 1;
+
+      /* remove the list `out' */
+      freeList(live_out_vars);
+
+      /* test if an error occurred */
+      if (cflow_errorcode != CFLOW_OK) {
+         return modified;
+      }
+
+      /* retrieve the previous element in the list */
+      current_element = LPREV(current_element);
+   }
+
+   /* return 1 if another liveness iteration is required */
+   return modified;
+}
+
+/* alloc a variable identifier */
+t_cflow_var * allocVariable (t_cflow_Graph *graph, int identifier)
+{
+   t_cflow_var * result;
+   t_list *elementFound;
+
+   if (graph == NULL)
+   {
+      cflow_errorcode = CFLOW_GRAPH_UNDEFINED;
+      return NULL;
+   }
+
+   /* alloc memory for a variable information */
+   result = _AXE_ALLOC_FUNCTION(sizeof(t_cflow_var));
+   if (result == NULL) {
+      cflow_errorcode = CFLOW_OUT_OF_MEMORY;
+      return NULL;
+   }
+
+   /* update the value of result */
+   result->ID = identifier;
+   
+   /* test if a variable with the same identifier was already present */
+   elementFound = CustomfindElement
+         (graph->cflow_variables, result, compare_CFLOW_Variables);
+   
+   if (elementFound == NULL)
+   {
+      /* update the set of variables */
+      graph->cflow_variables = addElement
+            (graph->cflow_variables, result, -1);
+   }
+   else
+   {
+      _AXE_FREE_FUNCTION(result);
+      result = (t_cflow_var *) LDATA(elementFound);
+      assert(result != NULL);
+      assert(result->ID == identifier);
+   }
+   
+   /* return a new var identifier */
+   return result;
+}
+
+/* set the def-use values for the current node */
+void setDefUses(t_cflow_Graph *graph, t_cflow_Node *node)
+{
+   t_axe_instruction *instr;
+   t_cflow_var *varDest;
+   t_cflow_var *varSource1;
+   t_cflow_var *varSource2;
+
+   /* preconditions */
+   if (graph == NULL) {
+      cflow_errorcode = CFLOW_GRAPH_UNDEFINED;
+      return;
+   }
+   
+   if (node == NULL) {
+      cflow_errorcode = CFLOW_INVALID_NODE;
+      return;
+   }
+
+   if (node->instr == NULL) {
+      cflow_errorcode = CFLOW_INVALID_INSTRUCTION;
+      return;
+   }
+
+   if ((node->instr)->opcode == INVALID_OPCODE) {
+      cflow_errorcode = CFLOW_INVALID_INSTRUCTION;
+      return;
+   }
+   
+   /* update the value of `instr' */
+   instr = node->instr;
+
+   /* if the instruction is a Jump instruction then does nothing */
+   if ( isJumpInstruction(instr))
+      return;
+
+   /* initialize the values of varDest, varSource1 and varSource2 */
+   varDest = NULL;
+   varSource1 = NULL;
+   varSource2 = NULL;
+
+   /* update the values of the variables */
+   if (instr->reg_1 != NULL)
+      varDest = allocVariable(graph, (instr->reg_1)->ID);
+   if (instr->reg_2 != NULL)
+      varSource1 = allocVariable(graph, (instr->reg_2)->ID);
+   if (instr->reg_3 != NULL)
+      varSource2 = allocVariable(graph, (instr->reg_3)->ID);
+   
+   switch(instr->opcode)
+   {
+      case LOAD : case AXE_READ : node->def = varDest; break;
+      case STORE : case AXE_WRITE : (node->uses)[0] = varDest; break;
+      case SGE : case SGT: case SLE : case SLT : case SNE :
+      case SEQ : node->def = varDest; break;
+      case HALT : case RET : case JSR : case NOP : break;
+      case MOVA : node->def = varDest; break;
+      case NOTB : case NOTL : case ROTRI : case ROTLI :
+      case SHRI : case SHLI : case DIVI : case MULI :
+      case EORBI : case ORBI : case ANDBI : case EORLI :
+      case ORLI : case ANDLI : case SUBI : case ADDI :
+                node->def = varDest;
+                (node->uses)[0] = varSource1; break;
+      default :
+                if ((instr->reg_1)->indirect)
+                     (node->uses)[2] = varDest;
+                else
+                     node->def = varDest;
+                (node->uses)[0] = varSource1;
+                (node->uses)[1] = varSource2;
+   }
+}
+
+/* test if the current instruction `instr' is a BT or a BF */
+int isUnconditionalJump(t_axe_instruction *instr)
+{
+   if (isJumpInstruction(instr))
+   {
+      if ((instr->opcode == BT) || (instr->opcode == BF))
+         return 1;
+   }
+
+   return 0;
+}
+
+/* test if the current instruction `instr' is a branch instruction */
+int isJumpInstruction(t_axe_instruction *instr)
+{
+   if (instr == NULL)
+      return 0;
+
+   switch(instr->opcode)
+   {
+      case BT :
+      case BF :
+      case BHI :
+      case BLS :
+      case BCC :
+      case BCS :
+      case BNE :
+      case BEQ :
+      case BVC :
+      case BVS :
+      case BPL :
+      case BMI :
+      case BGE :
+      case BLT :
+      case BGT :
+      case BLE : return 1;
+      default : return 0;
+   }
+}
+
+/* look up for a label inside the graph */
+t_basic_block * searchLabel(t_cflow_Graph *graph, t_axe_label *label)
+{
+   t_list *current_element;
+   t_basic_block *bblock;
+   t_cflow_Node *current_node;
+   
+   /* preconditions: graph should not be a NULL pointer */
+   if (graph == NULL){
+      cflow_errorcode = CFLOW_GRAPH_UNDEFINED;
+      return NULL;
+   }
+
+   /* test if we haven't to search for a label */
+   if (label == NULL)
+      return NULL;
+   
+   /* initialize `bblock' */
+   bblock = NULL;
+   
+   current_element = graph->blocks;
+   while(current_element != NULL)
+   {
+      bblock = (t_basic_block *) LDATA(current_element);
+      assert(bblock != NULL);
+      assert(bblock->nodes != NULL);
+
+      /* retrieve the first node of the basic block */
+      current_node = (t_cflow_Node *) LDATA(bblock->nodes);
+      assert(current_node != NULL);
+
+      /* if the first node holds a label information, we
+       * have to verify if we have found the right label */
+      if ((current_node->instr)->labelID != NULL)
+      {
+         if (compareLabels((current_node->instr)->labelID, label))
+            /* we found the correct basic block */
+            break;
+      }
+
+      /* retrieve the next element */
+      current_element = LNEXT(current_element);
+   }
+
+   return bblock;
+}
+
+/* test if the current instruction `instr' is a labelled instruction */
+int isStartingNode(t_axe_instruction *instr)
+{
+   /* preconditions */
+   if ((instr == NULL) || (instr->opcode == INVALID_OPCODE))
+   {
+      cflow_errorcode = CFLOW_INVALID_INSTRUCTION;
+      return 0;
+   }
+
+   /* test if the instruction holds a label identifier */
+   if (instr->labelID != NULL)
+   {
+      if ((instr->labelID)->labelID == LABEL_UNSPECIFIED)
+      {
+         cflow_errorcode = CFLOW_INVALID_INSTRUCTION;
+         return 0;
+      }
+
+      return 1;
+   }
+   
+   return 0;
+}
+
+/* test if the current instruction will end a basic block */
+int isEndingNode(t_axe_instruction *instr)
+{
+   /* preconditions */
+   if ((instr == NULL) || (instr->opcode == INVALID_OPCODE))
+   {
+      cflow_errorcode = CFLOW_INVALID_INSTRUCTION;
+      return 0;
+   }
+
+   switch (instr->opcode)
+   {
+      case JSR :
+      case RET :
+      case HALT:
+      case BT :
+      case BF :
+      case BHI :
+      case BLS :
+      case BCC :
+      case BCS :
+      case BNE :
+      case BEQ :
+      case BVC :
+      case BVS :
+      case BPL :
+      case BMI :
+      case BGE :
+      case BLT :
+      case BGT :
+      case BLE : return 1;
+      default : return 0;
+   }
+}
+
+/* allocate memory for a control flow graph */
+t_cflow_Graph * allocGraph()
+{
+   t_cflow_Graph *result;
+
+   result = _AXE_ALLOC_FUNCTION(sizeof(t_cflow_Graph));
+   if (result == NULL) {
+      cflow_errorcode = CFLOW_OUT_OF_MEMORY;
+      return NULL;
+   }
+
+   /* initialize `result' */
+   result->startingBlock = NULL;
+   result->blocks = NULL;
+   result->cflow_variables = NULL;
+   result->endingBlock = allocBasicBlock();
+
+   /* test if an error occurred */
+   if (result->endingBlock == NULL) {
+      cflow_errorcode = CFLOW_OUT_OF_MEMORY;
+      _AXE_FREE_FUNCTION(result);
+      return NULL;
+   }
+
+   /* return the just created cflow graph */
+   return result;
+}
+
+/* finalize the memory associated with the given control flow graph */
+void finalizeGraph(t_cflow_Graph *graph)
+{
+   t_list *current_element;
+   t_basic_block *current_block;
+
+   if (graph == NULL)
+      return;
+
+   current_element = graph->blocks;
+   while (current_element != NULL)
+   {
+      /* retrieve the current node */
+      current_block = (t_basic_block *) LDATA(current_element);
+      assert(current_block != NULL);
+
+      finalizeBasicBlock(current_block);
+
+      current_element = LNEXT(current_element);
+   }
+
+   if (graph->blocks != NULL)
+      freeList(graph->blocks);
+   if (graph->endingBlock != NULL)
+      finalizeBasicBlock(graph->endingBlock);
+   if (graph->cflow_variables != NULL)
+   {
+      t_list *current_element;
+      t_cflow_var *current_variable;
+
+      current_element = graph->cflow_variables;
+      while (current_element != NULL)
+      {
+         current_variable = (t_cflow_var *) LDATA(current_element);
+
+         if (current_variable != NULL)
+            _AXE_FREE_FUNCTION(current_variable);
+
+         /* retrieve the next variable in the list */
+         current_element = LNEXT(current_element);
+      }
+
+      freeList(graph->cflow_variables);
+   }
+
+   _AXE_FREE_FUNCTION(graph);
+}
+
+/* allocate memory for a basic block */
+t_basic_block * allocBasicBlock()
+{
+   t_basic_block *result;
+   
+   result = _AXE_ALLOC_FUNCTION(sizeof(t_basic_block));
+   if (result == NULL)
+   {
+      cflow_errorcode = CFLOW_OUT_OF_MEMORY;
+      return NULL;
+   }
+
+   /* initialize result */
+   result->pred = NULL;
+   result->succ = NULL;
+   result->nodes = NULL;
+
+   return result;
+}
+
+/* free the memory associated with a given basic block */
+void finalizeBasicBlock(t_basic_block *block)
+{
+   t_list *current_element;
+   t_cflow_Node *current_node;
+
+   if (block == NULL)
+      return;
+
+   if (block->pred != NULL)
+      freeList(block->pred);
+   if (block->succ != NULL)
+      freeList(block->succ);
+
+   /* initialize current_element */
+   current_element = block->nodes;
+   
+   while (current_element != NULL)
+   {
+      /* retrieve the current node */
+      current_node = (t_cflow_Node *) LDATA(current_element);
+
+      /* free the memory associated with the current node */
+      finalizeNode(current_node);
+
+      /* retrieve the next node in the list */
+      current_element = LNEXT(current_element);
+   }
+
+   freeList(block->nodes);
+   
+   /* free the memory associated with this basic block */
+   _AXE_FREE_FUNCTION(block);
+}
+
+/* free the memory associated with a node of the graph */
+void finalizeNode(t_cflow_Node *node)
+{
+   if (node == NULL)
+      return;
+
+   /* free the two lists `in' and `out' */
+   if (node->in != NULL)
+      freeList(node->in);
+   if (node->out != NULL)
+      freeList(node->out);
+
+   /* free the current node */
+   _AXE_FREE_FUNCTION(node);
+}
+
+t_cflow_Node * allocNode
+      (t_cflow_Graph *graph, t_axe_instruction *instr)
+{
+   t_cflow_Node *result;
+
+   /* test the preconditions */
+   if (graph == NULL) {
+      cflow_errorcode = CFLOW_GRAPH_UNDEFINED;
+      return NULL;
+   }
+   
+   if (instr == NULL)
+   {
+      cflow_errorcode = CFLOW_INVALID_INSTRUCTION;
+      return NULL;
+   }
+
+   /* create a new instance of type `t_cflow_node' */
+   result = _AXE_ALLOC_FUNCTION(sizeof(t_cflow_Node));
+
+   /* test if an error occurred */
+   if (result == NULL) {
+      cflow_errorcode = CFLOW_OUT_OF_MEMORY;
+      return NULL;
+   }
+
+   /* initialize result */
+   result->def = NULL;
+   result->uses[0] = NULL;
+   result->uses[1] = NULL;
+   result->uses[2] = NULL;
+   result->instr = instr;
+
+   /* set the def-uses for the current node */
+   setDefUses(graph, result);
+
+   /* test if an error occurred */
+   if (cflow_errorcode != CFLOW_OK) {
+      _AXE_FREE_FUNCTION(result);
+      return NULL;
+   }
+
+   /* set the list of variables that are live in
+    * and live out from the current node */
+   result->in = NULL;
+   result->out = NULL;
+   
+   /* return the node */
+   return result;
+}
+
+void setPred(t_basic_block *block, t_basic_block *pred)
+{
+   /* preconditions */
+   if (block == NULL) {
+      cflow_errorcode = CFLOW_BBLOCK_UNDEFINED;
+      return;
+   }
+
+   if (pred == NULL) {
+      cflow_errorcode = CFLOW_INVALID_BBLOCK;
+      return;
+   }
+
+   /* test if the block is already inserted in the list of predecessors */
+   if (findElement(block->pred, pred) == NULL)
+   {
+      block->pred = addElement(block->pred, pred, -1);
+      pred->succ = addElement(pred->succ, block, -1);
+   }
+}
+
+void setSucc(t_basic_block *block, t_basic_block *succ)
+{
+   t_list *element_found;
+   
+   /* preconditions */
+   if (block == NULL) {
+      cflow_errorcode = CFLOW_BBLOCK_UNDEFINED;
+      return;
+   }
+
+   if (succ == NULL) {
+      cflow_errorcode = CFLOW_INVALID_BBLOCK;
+      return;
+   }
+
+   element_found = findElement(block->succ, succ);
+   
+   /* test if the node is already inserted in the list of successors */
+   if (element_found == NULL)
+   {
+      block->succ = addElement(block->succ, succ, -1);
+      succ->pred = addElement(succ->pred, block, -1);
+   }
+}
+
+void insertBlock(t_cflow_Graph *graph, t_basic_block *block)
+{
+   /* preconditions */
+   if (graph == NULL)
+   {
+      cflow_errorcode = CFLOW_GRAPH_UNDEFINED;
+      return;
+   }
+   
+   if (block == NULL)
+   {
+      cflow_errorcode = CFLOW_INVALID_BBLOCK;
+      return;
+   }
+
+   if (findElement(graph->blocks, block) != NULL)
+   {
+      cflow_errorcode = CFLOW_BBLOCK_ALREADY_INSERTED;
+      return;
+   }
+
+   /* add the current node to the basic block */
+   graph->blocks = addElement(graph->blocks, block, -1);
+
+   /* test if this is the first basic block for the program */
+   if (graph->startingBlock == NULL)
+      graph->startingBlock = block;
+}
+
+/* insert a new node without updating the dataflow informations */
+void insertNodeBefore(t_basic_block *block
+      , t_cflow_Node *before_node, t_cflow_Node *new_node)
+{
+   int before_node_posn;
+   t_list *before_node_elem;
+   
+   /* preconditions */
+   if (block == NULL)
+   {
+      cflow_errorcode = CFLOW_INVALID_BBLOCK;
+      return;
+   }
+   
+   if (  (new_node == NULL)
+         || (new_node->instr == NULL)
+         || (before_node == NULL) )
+   {
+      cflow_errorcode = CFLOW_INVALID_NODE;
+      return;
+   }
+
+   before_node_elem = findElement(block->nodes, before_node);
+   if (before_node_elem == NULL)
+   {
+      cflow_errorcode = CFLOW_INVALID_NODE;
+      return;
+   }
+   
+   if (findElement(block->nodes, new_node) != NULL)
+   {
+      cflow_errorcode = CFLOW_NODE_ALREADY_INSERTED;
+      return;
+   }
+
+   /* get the position of the before node */
+   before_node_posn = getPosition(block->nodes, before_node_elem);
+   assert(before_node_posn != -1);
+
+   /* add the current node to the basic block */
+   block->nodes = addElement(block->nodes, new_node, before_node_posn);
+}
+
+/* insert a new node without updating the dataflow informations */
+void insertNodeAfter(t_basic_block *block
+      , t_cflow_Node *after_node, t_cflow_Node *new_node)
+{
+   int after_node_posn;
+   t_list *after_node_elem;
+   
+   /* preconditions */
+   if (block == NULL)
+   {
+      cflow_errorcode = CFLOW_INVALID_BBLOCK;
+      return;
+   }
+   
+   if (  (new_node == NULL)
+         || (new_node->instr == NULL)
+         || (after_node == NULL) )
+   {
+      cflow_errorcode = CFLOW_INVALID_NODE;
+      return;
+   }
+
+   after_node_elem = findElement(block->nodes, after_node);
+   if (after_node_elem == NULL)
+   {
+      cflow_errorcode = CFLOW_INVALID_NODE;
+      return;
+   }
+   
+   if (findElement(block->nodes, new_node) != NULL)
+   {
+      cflow_errorcode = CFLOW_NODE_ALREADY_INSERTED;
+      return;
+   }
+
+   /* get the position of the after node */
+   after_node_posn = getPosition(block->nodes, after_node_elem);
+   assert(after_node_posn != -1);
+
+   /* add the current node to the basic block */
+   block->nodes = addElement(block->nodes, new_node, (after_node_posn + 1));
+}
+
+void insertNode(t_basic_block *block, t_cflow_Node *node)
+{
+   /* preconditions */
+   if (block == NULL)
+   {
+      cflow_errorcode = CFLOW_INVALID_BBLOCK;
+      return;
+   }
+   
+   if (node == NULL || node->instr == NULL)
+   {
+      cflow_errorcode = CFLOW_INVALID_NODE;
+      return;
+   }
+
+   if (findElement(block->nodes, node) != NULL)
+   {
+      cflow_errorcode = CFLOW_NODE_ALREADY_INSERTED;
+      return;
+   }
+
+   /* add the current node to the basic block */
+   block->nodes = addElement(block->nodes, node, -1);
+}
+
+t_cflow_Graph * createFlowGraph(t_list *instructions)
+{
+   t_cflow_Graph *result;
+   t_basic_block *bblock;
+   t_list *current_element;
+   t_cflow_Node *current_node;
+   t_axe_instruction *current_instr;
+   int startingNode;
+   int endingNode;
+
+   /* initialize the global variable `cflow_errorcode' */
+   cflow_errorcode = CFLOW_OK;
+   
+   /* preconditions */
+   if (instructions == NULL){
+      cflow_errorcode = CFLOW_INVALID_PROGRAM_INFO;
+      return NULL;
+   }
+   
+   /* alloc memory for a new control flow graph */
+   result = allocGraph();
+   if (result == NULL)
+      return NULL;
+
+   /* set the starting basic block */
+   bblock = NULL;
+
+   /* initialize the current element */
+   current_element = instructions;
+   while(current_element != NULL)
+   {
+      /* retrieve the current instruction */
+      current_instr = (t_axe_instruction *) LDATA(current_element);
+      assert(current_instr != NULL);
+
+      if (isLoadInstruction(current_instr))
+      {
+         current_element = LNEXT(current_element);
+         continue;
+      }
+         
+      /* create a new node for the current basic block */
+      current_node = allocNode(result, current_instr);
+      if (current_node == NULL){
+         finalizeGraph(result);
+         return NULL;
+      }
+
+      /* test if the current instruction will start or end a block */
+      startingNode = isStartingNode(current_instr);
+      endingNode = isEndingNode(current_instr);
+
+      if (startingNode || bblock == NULL)
+      {
+         /* alloc a new basic block */
+         bblock = allocBasicBlock();
+         if (bblock == NULL) {
+            finalizeGraph(result);
+            finalizeNode(current_node);
+            return NULL;
+         }
+
+         /* add the current instruction to the newly created
+          * basic block */
+         insertNode(bblock, current_node);
+         if (cflow_errorcode != CFLOW_OK) {
+            finalizeGraph(result);
+            finalizeNode(current_node);
+            finalizeBasicBlock(bblock);
+            return NULL;
+         }
+
+         /* add the new basic block to the control flow graph */
+         insertBlock(result, bblock);
+         if (cflow_errorcode != CFLOW_OK) {
+            finalizeGraph(result);
+            finalizeNode(current_node);
+            finalizeBasicBlock(bblock);
+            return NULL;
+         }
+      }
+      else
+      {
+         /* add the current instruction to the current
+          * basic block */
+         insertNode(bblock, current_node);
+         if (cflow_errorcode != CFLOW_OK) {
+            finalizeGraph(result);
+            finalizeNode(current_node);
+            return NULL;
+         }
+      }
+
+      if (endingNode)
+         bblock = NULL;
+
+      /* retrieve the next element */
+      current_element = LNEXT(current_element);
+   }
+
+   /* update the basic blocks chain */
+   updateFlowGraph(result);
+   if (cflow_errorcode != CFLOW_OK) {
+      finalizeGraph(result);
+      return NULL;
+   }
+
+   /*return the graph */
+   return result;
+}
+
+void updateFlowGraph(t_cflow_Graph *graph)
+{
+   t_list *current_element;
+   t_basic_block *current_block;
+   t_basic_block *successor;
+   
+   /* preconditions: graph should not be a NULL pointer */
+   if (graph == NULL){
+      cflow_errorcode = CFLOW_GRAPH_UNDEFINED;
+      return;
+   }
+
+   successor = NULL;
+   current_element = graph->blocks;
+   while(current_element != NULL)
+   {
+      t_list *last_element;
+      t_cflow_Node *last_node;
+      t_axe_instruction *last_instruction;
+      t_basic_block *jumpBlock;
+      
+      /* retrieve the current block */
+      current_block = (t_basic_block *) LDATA(current_element);
+      assert(current_block != NULL);
+      assert(current_block->nodes != NULL);
+
+      /* get the last node of the basic block */
+      last_element = getLastElement(current_block->nodes);
+      assert(last_element != NULL);
+      
+      last_node = (t_cflow_Node *) LDATA(last_element);
+      assert(last_node != NULL);
+
+      last_instruction = last_node->instr;
+      assert(last_instruction != NULL);
+
+      if (isHaltInstruction(last_instruction))
+      {
+         setSucc(current_block, graph->endingBlock);
+         setPred(graph->endingBlock, current_block);
+      }
+      else
+      {
+         if (isJumpInstruction(last_instruction))
+         {
+            if (  (last_instruction->address == NULL)
+                  || ((last_instruction->address)->labelID == NULL) )
+            {
+               cflow_errorcode = CFLOW_INVALID_LABEL_FOUND;
+               return;
+            }
+         
+            jumpBlock = searchLabel(graph
+                  , (last_instruction->address)->labelID);
+            if (jumpBlock == NULL) {
+               cflow_errorcode = CFLOW_INVALID_LABEL_FOUND;
+               return;
+            }
+
+            /* add the jumpBlock to the list of successors of current_block */
+            /* add also current_block to the list of predecessors of jumpBlock */
+            setPred(jumpBlock, current_block);
+            if (cflow_errorcode != CFLOW_OK)
+               return;
+            setSucc(current_block, jumpBlock);
+            if (cflow_errorcode != CFLOW_OK)
+               return;
+         }
+
+         if (!isUnconditionalJump(last_instruction))
+         {
+            t_basic_block *nextBlock;
+            t_list *next_element;
+            
+            next_element = LNEXT(current_element);
+            if (next_element != NULL)
+            {
+               nextBlock = LDATA(next_element);
+               assert(nextBlock != NULL);
+               
+               setSucc(current_block, nextBlock);
+               setPred(nextBlock, current_block);
+            }
+            else
+            {
+               setSucc(current_block, graph->endingBlock);
+               setPred(graph->endingBlock, current_block);
+            }
+         
+            if (cflow_errorcode != CFLOW_OK)
+               return;
+         }
+      }
+
+      /* update the value of `current_element' */
+      current_element = LNEXT(current_element);
+   }
+}

+ 86 - 0
acse/axe_cflow_graph.h

@@ -0,0 +1,86 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * axe_cflow_graph.h
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#ifndef _AXE_CFLOW_GRAPH_H
+#define _AXE_CFLOW_GRAPH_H
+
+#include <stdio.h>
+#include "axe_struct.h"
+#include "collections.h"
+
+extern int cflow_errorcode;
+
+
+/* a variable of the intermediate code */
+typedef struct t_cflow_var
+{
+   int ID;   /* variable identifier */
+} t_cflow_var;
+
+/* A Node exists only in a basic block. It defines a list of
+ * def-uses and it is associated with a specific instruction
+ * inside the code */
+typedef struct t_cflow_Node
+{
+   t_cflow_var *def;        /* A variable that is defined by this node */
+   t_cflow_var *uses[3];    /* set of variables that will be used by this node */
+   t_axe_instruction *instr;  /* a pointer to the instruction associated
+                               * with this node */
+   t_list *in;             /* variables that are live-in the current node */
+   t_list *out;            /* variables that are live-out the current node */
+} t_cflow_Node;
+
+/* an ordered list of nodes with only one predecessor and one successor */
+typedef struct t_basic_block
+{
+   t_list *pred;  /* predecessors : a list of basic blocks */
+   t_list *succ;  /* successors : a list of basic blocks */
+   t_list *nodes; /* an ordered list of instructions */
+} t_basic_block;
+
+/* a control flow graph */
+typedef struct t_cflow_Graph
+{
+   t_basic_block *startingBlock; /* the starting basic block of code */
+   t_basic_block *endingBlock;   /* the last block of the graph */
+   t_list *blocks;               /* an ordered list of all the basic blocks */
+   t_list *cflow_variables;      /* a list of all the variable identifiers */
+} t_cflow_Graph;
+
+
+/* functions that are used in order to allocate/deallocate instances
+ * of basic blocks, instruction nodes and flow graphs */
+extern t_cflow_Node * allocNode
+      (t_cflow_Graph *graph, t_axe_instruction *instr);
+extern void finalizeNode(t_cflow_Node *node);
+extern t_basic_block * allocBasicBlock();
+extern void finalizeBasicBlock(t_basic_block *block);
+extern t_cflow_Graph * allocGraph();
+extern void finalizeGraph(t_cflow_Graph *graph);
+
+/* working with basic blocks */
+extern void setPred(t_basic_block *block, t_basic_block *pred);
+extern void setSucc(t_basic_block *block, t_basic_block *succ);
+extern void insertNode(t_basic_block *block, t_cflow_Node *node);
+extern void insertNodeBefore(t_basic_block *block
+      , t_cflow_Node *before_node, t_cflow_Node *new_node);
+extern void insertNodeAfter(t_basic_block *block
+      , t_cflow_Node *after_node, t_cflow_Node *new_node);
+extern t_list * getLiveINVars(t_basic_block *bblock);
+extern t_list * getLiveOUTVars(t_basic_block *bblock);
+
+/* working with the control flow graph */
+extern void insertBlock(t_cflow_Graph *graph, t_basic_block *block);
+extern t_cflow_Graph * createFlowGraph(t_list *instructions);
+
+/* dataflow analysis */
+extern void performLivenessAnalysis(t_cflow_Graph *graph);
+
+
+#endif

+ 155 - 0
acse/axe_constants.h

@@ -0,0 +1,155 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * axe_constants.h
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#ifndef _AXE_CONSTANTS_H
+#define _AXE_CONSTANTS_H
+
+/* registers */
+
+#define REG_INVALID -1
+#define REG_0 0
+#define NUM_REGISTERS 31
+
+/* opcodes pseudo-M68000 */
+#define ADD 0
+#define SUB 1
+#define ANDL 2
+#define ORL 3
+#define EORL 4
+#define ANDB 5
+#define ORB 6
+#define EORB 7
+#define MUL 8
+#define DIV 9
+#define SHL 10
+#define SHR 11
+#define ROTL 12
+#define ROTR 13
+#define NEG 14
+#define SPCL 15
+#define ADDI 16
+#define SUBI 17
+#define ANDLI 18
+#define ORLI 19
+#define EORLI 20
+#define ANDBI 21
+#define ORBI 22
+#define EORBI 23
+#define MULI 24
+#define DIVI 25
+#define SHLI 26
+#define SHRI 27
+#define ROTLI 28
+#define ROTRI 29
+#define NOTL 30
+#define NOTB 31
+#define NOP 32
+#define MOVA 33
+#define JSR 34
+#define RET 35
+#define HALT 36
+#define SEQ 37
+#define SGE 38
+#define SGT 39
+#define SLE 40
+#define SLT 41
+#define SNE 42
+#define BT 43
+#define BF 44
+#define BHI 45
+#define BLS 46
+#define BCC 47
+#define BCS 48
+#define BNE 49
+#define BEQ 50
+#define BVC 51
+#define BVS 52
+#define BPL 53
+#define BMI 54
+#define BGE 55
+#define BLT 56
+#define BGT 57
+#define BLE 58
+#define LOAD 59
+#define STORE 60
+#define AXE_READ 61
+#define AXE_WRITE 62
+#define INVALID_OPCODE -1
+
+/* data types */
+#define INTEGER_TYPE 0
+#define UNKNOWN_TYPE -1
+
+/* label special values */
+#define LABEL_UNSPECIFIED -1
+
+/* WARNINGS */
+#define WARN_DIVISION_BY_ZERO 1
+
+/* SIM errorcodes */
+#define AXE_OK 0
+#define AXE_OUT_OF_MEMORY 1
+#define AXE_PROGRAM_NOT_INITIALIZED 2
+#define AXE_INVALID_INSTRUCTION 3
+#define AXE_VARIABLE_ID_UNSPECIFIED 4
+#define AXE_VARIABLE_ALREADY_DECLARED 5
+#define AXE_INVALID_TYPE 6
+#define AXE_FOPEN_ERROR 7
+#define AXE_FCLOSE_ERROR 8
+#define AXE_INVALID_INPUT_FILE 9
+#define AXE_FWRITE_ERROR 10
+#define AXE_INVALID_DATA_FORMAT 11
+#define AXE_INVALID_OPCODE 12
+#define AXE_INVALID_REGISTER_INFO 13
+#define AXE_INVALID_LABEL 14
+#define AXE_INVALID_ARRAY_SIZE 15
+#define AXE_INVALID_VARIABLE 16
+#define AXE_INVALID_ADDRESS 17
+#define AXE_INVALID_EXPRESSION 18
+#define AXE_UNKNOWN_VARIABLE 19
+#define AXE_LABEL_ALREADY_ASSIGNED 20
+#define AXE_INVALID_LABEL_MANAGER 21
+#define AXE_SY_TABLE_ERROR 22
+#define AXE_NULL_DECLARATION 23
+#define AXE_INVALID_CFLOW_GRAPH 24
+#define AXE_INVALID_REG_ALLOC 25
+#define AXE_REG_ALLOC_ERROR 26
+#define AXE_TRANSFORM_ERROR 27
+#define AXE_SYNTAX_ERROR 28
+#define AXE_UNKNOWN_ERROR 29
+
+/* DIRECTIVE TYPES */
+#define DIR_WORD 0
+#define DIR_SPACE 1
+#define DIR_INVALID -1
+
+/* ADDRESS TYPES */
+#define ADDRESS_TYPE 0
+#define LABEL_TYPE 1
+
+/* CODEGEN FLAGS */
+#define CG_DIRECT_ALL 0
+#define CG_INDIRECT_ALL 3
+#define CG_INDIRECT_DEST 1
+#define CG_INDIRECT_SOURCE 2
+
+/* EXPRESSION TYPES */
+#define IMMEDIATE 0
+#define REGISTER 1
+#define INVALID_EXPRESSION -1
+
+/* binary comparison constants */
+#define _LT_ 0
+#define _GT_ 1
+#define _EQ_ 2
+#define _NOTEQ_ 3
+#define _LTEQ_ 4
+#define _GTEQ_ 5
+
+#endif

+ 354 - 0
acse/axe_debug.c

@@ -0,0 +1,354 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * axe_debug.c
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#include "axe_debug.h"
+#include "collections.h"
+#include "reg_alloc_constants.h"
+#include "cflow_constants.h"
+
+static void printListOfVariables(t_list *variables, FILE *fout);
+static void printBBlockInfos(t_basic_block *block, FILE *fout, int verbose);
+static void printLiveIntervals(t_list *intervals, FILE *fout);
+static void printBindings(int *bindings, int numVars, FILE *fout);
+
+void printBindings(int *bindings, int numVars, FILE *fout)
+{
+   int counter;
+   
+   if (bindings == NULL)
+      return;
+
+   if (fout == NULL)
+      return;
+
+   /* initialize counter */
+   counter = 0;
+   fprintf(fout, "BINDINGS : \n");
+   while(counter <= numVars)
+   {
+      if (bindings[counter] != RA_SPILL_REQUIRED)
+      {
+         fprintf(fout, "VAR T%d will be assigned to register R%d \n"
+                  , counter, bindings[counter]);
+      }
+      else
+      {
+         fprintf(fout, "VAR T%d will be spilled \n", counter);
+      }
+      
+      counter++;
+   }
+}
+
+void printRegAllocInfos(t_reg_allocator *RA, FILE *fout)
+{
+   if (RA == NULL)
+      return;
+   if (fout == NULL)
+      return;
+   fprintf(fout, "\n\n*************************\n");
+   fprintf(fout, "REGISTER ALLOCATION INFOS\n");
+   fprintf(fout, "*************************\n");
+   fprintf(fout, "AVAILABLE REGISTERS : %d \n", RA->regNum + 3);
+   fprintf(fout, "USED VARIABLES : %d \n", RA->varNum);
+   fprintf(fout, "-------------------------\n");
+   printLiveIntervals(RA->live_intervals, fout);
+   fprintf(fout, "-------------------------\n");
+   printBindings(RA->bindings, RA->varNum, fout);
+   fprintf(fout, "*************************\n\n");
+}
+
+void printLiveIntervals(t_list *intervals, FILE *fout)
+{
+   t_list *current_element;
+   t_live_interval *interval;
+
+   /* precondition */
+   if (fout == NULL)
+      return;
+
+   fprintf(fout, "LIVE_INTERVALS:\n");
+
+   /* retireve the first element of the list */
+   current_element = intervals;
+   while (current_element != NULL)
+   {
+      interval = (t_live_interval *) LDATA(current_element);
+
+      fprintf(fout, "\tLIVE_INTERVAL of T%d : [%d, %d] \n"
+            , interval->varID, interval->startPoint, interval->endPoint);
+      
+      /* retrieve the next element in the list of intervals */
+      current_element = LNEXT(current_element);
+   }
+}
+
+void printBBlockInfos(t_basic_block *block, FILE *fout, int verbose)
+{
+   t_list *current_element;
+   t_cflow_Node *current_node;
+   int count;
+   
+   /* preconditions */
+   if (block == NULL)
+      return;
+   if (fout == NULL)
+      return;
+
+   fprintf(fout,"NUMBER OF PREDECESSORS : %d \n"
+         , getLength(block->pred) );
+   fprintf(fout,"NUMBER OF SUCCESSORS : %d \n"
+         , getLength(block->succ) );
+   fprintf(fout,"NUMBER OF INSTRUCTIONS : %d \n"
+         , getLength(block->nodes) );
+
+   count = 1;
+   current_element = block->nodes;
+   while(current_element != NULL)
+   {
+      current_node = (t_cflow_Node *) LDATA(current_element);
+      fprintf(fout,"\t%d.  ", count);
+      debug_printInstruction(current_node->instr, fout);
+      if (verbose != 0)
+      {
+         if (current_node->def != NULL)
+            fprintf(fout, "\n\t\t\tDEF = [R%d]", (current_node->def)->ID);
+         if (current_node->uses[0] != NULL)
+         {
+            fprintf(fout, "\n\t\t\tUSES = [R%d", ((current_node->uses)[0])->ID);
+            if (current_node->uses[1] != NULL)
+               fprintf(fout, ", R%d", ((current_node->uses)[1])->ID);
+            if (current_node->uses[2] != NULL)
+               fprintf(fout, ", R%d", ((current_node->uses)[2])->ID);
+            fprintf(fout, "]");
+         }
+         fprintf(fout, "\n\t\t\tLIVE IN = [");
+         printListOfVariables(current_node->in, fout);
+         fprintf(fout, "]");
+         fprintf(fout, "\n\t\t\tLIVE OUT = [");
+         printListOfVariables(current_node->out, fout);
+         fprintf(fout, "]");
+      }
+      
+      fprintf(fout, "\n");
+      count++;
+      current_element = LNEXT(current_element);
+   }
+}
+
+void printListOfVariables(t_list *variables, FILE *fout)
+{
+   t_list *current_element;
+   t_cflow_var *current_variable;
+   
+   if (variables == NULL)
+      return;
+   if (fout == NULL)
+      return;
+
+   current_element = variables;
+   while(current_element != NULL)
+   {
+      current_variable = (t_cflow_var *) LDATA(current_element);
+      fprintf(fout, "R%d", current_variable->ID);
+      if (LNEXT(current_element) != NULL)
+         fprintf(fout, ", ");
+      
+      current_element = LNEXT(current_element);
+   }
+}
+
+void printGraphInfos(t_cflow_Graph *graph, FILE *fout, int verbose)
+{
+   int counter;
+   t_list *current_element;
+   t_basic_block *current_bblock;
+   
+   /* preconditions */
+   if (graph == NULL)
+      return;
+   if (fout == NULL)
+      return;
+
+   /* initialization of the local variables */
+   counter = 1;
+   
+   fprintf(fout,"NOTE : Temporary registers are considered as\n"
+                "       variables of the intermediate language. \n");
+#if CFLOW_ALWAYS_LIVEIN_R0 == (1)
+   fprintf(fout,"       Variable \'R0\' (that refers to the \n"
+                "       physical register \'RO\') is always \n"
+                "       considered LIVE-IN for each node of \n"
+                "       a basic block. \n"
+                "       Thus, in the following control flow graph, \n"
+                "       \'R0\' will never appear as LIVE-IN or LIVE-OUT\n"
+                "       variable for a statement.\n\n"
+                "       If you want to consider \'R0\' as\n"
+                "       a normal variable, you have to set\n"
+                "       to 0 the value of the macro CFLOW_ALWAYS_LIVEIN_R0\n"
+                "       defined in \"cflow_constants.h\".\n\n");
+#endif
+   fprintf(fout,"\n");
+   fprintf(fout,"**************************\n");
+   fprintf(fout,"     CONTROL FLOW GRAPH   \n");
+   fprintf(fout,"**************************\n");
+   fprintf(fout,"NUMBER OF BASIC BLOCKS : %d \n"
+         , getLength(graph->blocks));
+   fprintf(fout,"NUMBER OF USED VARIABLES : %d \n"
+         , getLength(graph->cflow_variables));
+   fprintf(fout,"--------------------------\n");
+   fprintf(fout,"START BASIC BLOCK INFOS.  \n");
+   fprintf(fout,"--------------------------\n");
+
+   /* initialize `current_block' */
+   current_element = graph->blocks;
+   while(current_element != NULL)
+   {
+      current_bblock = (t_basic_block *) LDATA(current_element);
+      fprintf(fout,"[BLOCK %d] \n", counter);
+      printBBlockInfos(current_bblock, fout, verbose);
+      if (LNEXT(current_element) != NULL)
+         fprintf(fout,"--------------------------\n");
+      else
+         fprintf(fout,"**************************\n");
+
+      counter++;
+      current_element = LNEXT(current_element);
+   }
+   
+   fprintf(fout,"\n\n");
+}
+
+
+void debug_printInstruction(t_axe_instruction *instr, FILE *fout)
+{
+   /* preconditions */
+   if (fout == NULL)
+      return;
+   
+   if (instr == NULL)
+   {
+      fprintf(fout, "[NULL] \n");
+      return;
+   }
+
+   if (instr->labelID != NULL)
+      fprintf(fout, "L%d\t", (instr->labelID)->labelID);
+   else
+      fprintf(fout, "\t");
+   
+   switch(instr->opcode)
+   {
+      case ADD : fprintf(fout, "ADD "); break;
+      case SUB : fprintf(fout, "SUB "); break;
+      case ANDL : fprintf(fout, "ANDL "); break;
+      case ORL : fprintf(fout, "ORL "); break;
+      case EORL : fprintf(fout, "EORL "); break;
+      case ANDB : fprintf(fout, "ANDB "); break;
+      case ORB : fprintf(fout, "ORB "); break;
+      case EORB : fprintf(fout, "EORB "); break;
+      case MUL : fprintf(fout, "MUL "); break;
+      case DIV : fprintf(fout, "DIV "); break;
+      case SHL : fprintf(fout, "SHL "); break;
+      case SHR : fprintf(fout, "SHR "); break;
+      case ROTL : fprintf(fout, "ROTL "); break;
+      case ROTR : fprintf(fout, "ROTR "); break;
+      case NEG : fprintf(fout, "NEG "); break;
+      case SPCL : fprintf(fout, "SPCL "); break;
+      case ADDI : fprintf(fout, "ADDI "); break;
+      case SUBI : fprintf(fout, "SUBI "); break;
+      case ANDLI : fprintf(fout, "ANDLI "); break;
+      case ORLI : fprintf(fout, "ORLI "); break;
+      case EORLI : fprintf(fout, "EORLI "); break;
+      case ANDBI : fprintf(fout, "ANDBI "); break;
+      case ORBI : fprintf(fout, "ORBI "); break;
+      case EORBI : fprintf(fout, "EORBI "); break;
+      case MULI : fprintf(fout, "MULI "); break;
+      case DIVI : fprintf(fout, "DIVI "); break;
+      case SHLI : fprintf(fout, "SHLI "); break;
+      case SHRI : fprintf(fout, "SHRI "); break;
+      case ROTLI : fprintf(fout, "ROTLI "); break;
+      case ROTRI : fprintf(fout, "ROTRI "); break;
+      case NOTL : fprintf(fout, "NOTL "); break;
+      case NOTB : fprintf(fout, "NOTB "); break;
+      case NOP : fprintf(fout, "NOP "); break;
+      case MOVA : fprintf(fout, "MOVA "); break;
+      case JSR : fprintf(fout, "JSR "); break;
+      case RET : fprintf(fout, "RET "); break;
+      case HALT : fprintf(fout, "HALT "); break;
+      case SEQ : fprintf(fout, "SEQ "); break;
+      case SGE : fprintf(fout, "SGE "); break;
+      case SGT : fprintf(fout, "SGT "); break;
+      case SLE : fprintf(fout, "SLE "); break;
+      case SLT : fprintf(fout, "SLT "); break;
+      case SNE : fprintf(fout, "SNE "); break;
+      case BT : fprintf(fout, "BT "); break;
+      case BF : fprintf(fout, "BF "); break;
+      case BHI : fprintf(fout, "BHI "); break;
+      case BLS : fprintf(fout, "BLS "); break;
+      case BCC : fprintf(fout, "BCC "); break;
+      case BCS : fprintf(fout, "BCS "); break;
+      case BNE : fprintf(fout, "BNE "); break;
+      case BEQ : fprintf(fout, "BEQ "); break;
+      case BVC : fprintf(fout, "BVC "); break;
+      case BVS : fprintf(fout, "BVS "); break;
+      case BPL : fprintf(fout, "BPL "); break;
+      case BMI : fprintf(fout, "BMI "); break;
+      case BGE : fprintf(fout, "BGE "); break;
+      case BLT : fprintf(fout, "BLT "); break;
+      case BGT : fprintf(fout, "BGT "); break;
+      case BLE : fprintf(fout, "BLE "); break;
+      case LOAD : fprintf(fout, "LOAD "); break;
+      case STORE : fprintf(fout, "STORE "); break;
+      case AXE_READ : fprintf(fout, "READ "); break;
+      case AXE_WRITE : fprintf(fout, "WRITE "); break;
+      case INVALID_OPCODE : fprintf(fout, "[INVALID] ");
+   }
+
+   if (instr->reg_1 != NULL)
+   {
+      if (!(instr->reg_1)->indirect)
+         fprintf(fout, "R%d ", (instr->reg_1)->ID);
+      else
+         fprintf(fout, "(R%d) ", (instr->reg_1)->ID);
+   }
+   if (instr->reg_2 != NULL)
+   {
+      if (!(instr->reg_2)->indirect)
+         fprintf(fout, "R%d ", (instr->reg_2)->ID);
+      else
+         fprintf(fout, "(R%d) ", (instr->reg_2)->ID);
+      if (instr->reg_3 != NULL)
+      {
+         if (!(instr->reg_3)->indirect)
+            fprintf(fout, "R%d ", (instr->reg_3)->ID);
+         else
+            fprintf(fout, "(R%d) ", (instr->reg_3)->ID);
+      }
+      else
+         fprintf(fout, "#%d ", instr->immediate);
+   }
+   
+   if (instr->address != NULL)
+   {
+      if ((instr->address)->type == LABEL_TYPE)
+         fprintf(fout, "L%d ", ((instr->address)->labelID)->labelID);
+      else
+         fprintf(fout, "%d ", (instr->address)->addr);
+   }
+}
+
+char * dataTypeToString(int codedType)
+{
+   switch (codedType)
+   {
+      case INTEGER_TYPE : return "INTEGER";
+      default : return "<INVALID_TYPE>";
+   }
+}

+ 31 - 0
acse/axe_debug.h

@@ -0,0 +1,31 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * axe_debug.h
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#ifndef _AXE_DEBUG_H
+#define _AXE_DEBUG_H
+
+#include <stdio.h>
+#include "axe_struct.h"
+#include "axe_cflow_graph.h"
+#include "axe_reg_alloc.h"
+
+/* a debug routine used to print on a specific output file the string
+ * representation of an instruction */
+extern void debug_printInstruction(t_axe_instruction *instr, FILE *fout);
+
+/* print debug informations about the control flow graph */
+extern void printGraphInfos(t_cflow_Graph *graph, FILE *fout, int verbose);
+
+/* print debug informations about register allocation infos */
+extern void printRegAllocInfos(t_reg_allocator *RA, FILE *fout);
+
+/* returns a string that represent the codedType given as input */
+extern char * dataTypeToString(int codedType);
+
+#endif

+ 904 - 0
acse/axe_engine.c

@@ -0,0 +1,904 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * axe_engine.c
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include "axe_engine.h"
+#include "symbol_table.h"
+#include "axe_errors.h"
+
+/* global variable errorcode */
+int errorcode;
+
+/* Function used when a compare is needed between two labels */
+static int compareVariables (void *Var_A, void *Var_B);
+
+/* Finalize the memory associated with an instruction */
+static void finalizeInstructions(t_list *instructions);
+
+/* Finalize the data segment */
+static void finalizeDataSegment(t_list *dataDirectives);
+
+/* finalize the informations associated with all the variables */
+static void finalizeVariables(t_list *variables);
+
+/* Translate the assembler directives (definitions inside the data segment */
+static void translateDataSegment(t_program_infos *program, FILE *fp);
+
+/* Translate all the instructions within the code segment */
+static void translateCodeSegment(t_program_infos *program, FILE *fp);
+
+/* print out to the file `fp' an opcode */
+static void printOpcode(int opcode, FILE *fp);
+
+/* print out to the file `fp' a register information */
+static void printRegister(t_axe_register *reg, FILE *fp);
+
+/* add a variable to the program */
+static void addVariable(t_program_infos *program, t_axe_variable *variable);
+
+      
+/* create a new variable */
+void createVariable(t_program_infos *program, char *ID
+      , int type, int isArray, int arraySize, int init_val)
+{
+   t_axe_variable *var;
+         
+   /* test the preconditions */
+   if (program == NULL)
+      notifyError(AXE_PROGRAM_NOT_INITIALIZED);
+
+   /* initialize a new variable */
+   var = alloc_variable(ID, type, isArray, arraySize, init_val);
+   if (var == NULL)
+      notifyError(AXE_OUT_OF_MEMORY);
+   
+   /* assign a new label to the newly created variable `var' */
+   var->labelID = newLabel(program);
+
+   /* add the new variable to program */
+   addVariable(program, var);
+}
+
+/* translate each instruction in his assembler symbolic representation */
+void translateCodeSegment(t_program_infos *program, FILE *fp)
+{
+   t_list *current_element;
+   t_axe_instruction *current_instruction;
+   int _error;
+   
+   /* preconditions */
+   if (fp == NULL)
+      notifyError(AXE_INVALID_INPUT_FILE);
+
+   if (program == NULL)
+   {
+      _error = fclose(fp);
+      if (_error == EOF)
+         notifyError(AXE_FCLOSE_ERROR);
+      notifyError(AXE_PROGRAM_NOT_INITIALIZED);
+   }
+
+   /* initialize the current_element */
+   current_element = program->instructions;
+
+   /* write the .text directive */
+   if (current_element != NULL)
+   {
+      if (fprintf(fp, "\t.text\n") < 0)
+      {
+         _error = fclose(fp);
+         if (_error == EOF)
+            notifyError(AXE_FCLOSE_ERROR);
+         notifyError(AXE_FWRITE_ERROR);
+      }
+   }
+
+   while (current_element != NULL)
+   {
+      /* retrieve the current instruction */
+      current_instruction = (t_axe_instruction *) LDATA(current_element);
+      assert(current_instruction != NULL);
+      assert(current_instruction->opcode != INVALID_OPCODE);
+
+      if (current_instruction->labelID != NULL)
+      {
+            /* create a string identifier for the label */
+            if (  fprintf(fp, "L%d : \t"
+                     , (current_instruction->labelID)->labelID ) < 0)
+            {
+              _error = fclose(fp);
+               if (_error == EOF)
+                  notifyError(AXE_FCLOSE_ERROR);
+               notifyError(AXE_FWRITE_ERROR);
+            }
+      }
+      else
+      {
+            /* create a string identifier for the label */
+            if (fprintf(fp, "\t") < 0)
+            {
+              _error = fclose(fp);
+               if (_error == EOF)
+                  notifyError(AXE_FCLOSE_ERROR);
+               notifyError(AXE_FWRITE_ERROR);
+            }
+      }
+
+      /* print the opcode */
+      printOpcode(current_instruction->opcode, fp);
+
+      if (  (current_instruction->opcode == HALT)
+            || (current_instruction->opcode == NOP) )
+      {
+         if (fprintf(fp, "\n") < 0)
+         {
+              _error = fclose(fp);
+               if (_error == EOF)
+                  notifyError(AXE_FCLOSE_ERROR);
+               notifyError(AXE_FWRITE_ERROR);
+         }
+
+         /* update the current_element */
+         current_element = LNEXT(current_element);
+         continue;
+      }
+      
+      if (fputc(' ', fp) == EOF)
+      {
+         _error = fclose(fp);
+         if (_error == EOF)
+            notifyError(AXE_FCLOSE_ERROR);
+         notifyError(AXE_FWRITE_ERROR);
+      }
+
+      if (current_instruction->reg_1 != NULL)
+      {
+         printRegister(current_instruction->reg_1, fp);
+         
+         if (fputc(' ', fp) == EOF)
+         {
+            _error = fclose(fp);
+            if (_error == EOF)
+               notifyError(AXE_FCLOSE_ERROR);
+            notifyError(AXE_FWRITE_ERROR);
+         }
+      }
+      if (current_instruction->reg_2 != NULL)
+      {
+         printRegister(current_instruction->reg_2, fp);
+         if (errorcode != AXE_OK)
+            return;
+
+         if (fputc(' ', fp) == EOF)
+         {
+            _error = fclose(fp);
+            if (_error == EOF)
+               notifyError(AXE_FCLOSE_ERROR);
+            notifyError(AXE_FWRITE_ERROR);
+         }
+      }
+      if (current_instruction->reg_3 != NULL)
+      {
+         printRegister(current_instruction->reg_3, fp);
+
+         if (fprintf(fp, "\n") < 0) {
+            _error = fclose(fp);
+            if (_error == EOF)
+               notifyError(AXE_FCLOSE_ERROR);
+            notifyError(AXE_FWRITE_ERROR);
+         }
+
+         /* update the current_element */
+         current_element = LNEXT(current_element);
+         continue;
+      }
+
+      if (current_instruction->address != NULL)
+      {
+         if ((current_instruction->address)->type == ADDRESS_TYPE)
+         {
+            if (fprintf(fp, "%d", (current_instruction->address)->addr) < 0)
+            {
+               _error = fclose(fp);
+               if (_error == EOF)
+                  notifyError(AXE_FCLOSE_ERROR);
+               notifyError(AXE_FWRITE_ERROR);
+            }
+         }
+         else
+         {
+            assert((current_instruction->address)->type == LABEL_TYPE);
+            if (  fprintf(fp, "L%d"
+                     , ((current_instruction->address)->labelID)
+                              ->labelID) < 0)
+            {
+               _error = fclose(fp);
+               if (_error == EOF)
+                  notifyError(AXE_FCLOSE_ERROR);
+               notifyError(AXE_FWRITE_ERROR);
+            }
+         }
+         
+         if (fprintf(fp, "\n") < 0) {
+            _error = fclose(fp);
+            if (_error == EOF)
+               notifyError(AXE_FCLOSE_ERROR);
+            notifyError(AXE_FWRITE_ERROR);
+         }
+
+         /* update the current_element */
+         current_element = LNEXT(current_element);
+         continue;
+      }
+
+      if (fprintf(fp, "#%d", current_instruction->immediate) < 0)
+      {
+         _error = fclose(fp);
+         if (_error == EOF)
+            notifyError(AXE_FCLOSE_ERROR);
+         notifyError(AXE_FWRITE_ERROR);
+      }
+
+      if (fprintf(fp, "\n") < 0) {
+         _error = fclose(fp);
+         if (_error == EOF)
+            notifyError(AXE_FCLOSE_ERROR);
+         notifyError(AXE_FWRITE_ERROR);
+      }
+
+      /* loop termination condition */
+      current_element = LNEXT(current_element);
+   }
+}
+
+void translateDataSegment(t_program_infos *program, FILE *fp)
+{
+   t_list *current_element;
+   t_axe_data *current_data;
+   int _error;
+   int fprintf_error;
+   
+   /* preconditions */
+   if (fp == NULL)
+      notifyError(AXE_INVALID_INPUT_FILE);
+
+   /* initialize the local variable `fprintf_error' */
+   fprintf_error = 0;
+   
+   if (program == NULL)
+   {
+      _error = fclose(fp);
+      if (_error == EOF)
+         notifyError(AXE_FCLOSE_ERROR);
+
+      notifyError(AXE_PROGRAM_NOT_INITIALIZED);
+   }
+
+   /* initialize the value of `current_element' */
+   current_element = program->data;
+
+   /* write the .data directive */
+   if (current_element != NULL)
+   {
+      if (fprintf(fp, "\t.data\n") < 0)
+      {
+         _error = fclose(fp);
+         if (_error == EOF)
+            notifyError(AXE_FCLOSE_ERROR);
+         notifyError(AXE_FWRITE_ERROR);
+      }
+   }
+
+   /* iterate all the elements inside the data segment */
+   while (current_element != NULL)
+   {
+      /* retrieve the current data element */
+      current_data = (t_axe_data *) LDATA(current_element);
+
+      /* assertions */
+      assert (current_data->directiveType != DIR_INVALID);
+
+      /* create a string identifier for the label */
+      if ( (current_data->labelID != NULL)
+            && ((current_data->labelID)->labelID != LABEL_UNSPECIFIED) )
+      {
+         fprintf_error = fprintf(fp, "L%d : \t"
+                  , (current_data->labelID)->labelID);
+      }
+      else
+      {
+         fprintf_error = fprintf(fp, "\t");
+      }
+
+      /* test if an error occurred while executing the `fprintf' function */
+      if (fprintf_error < 0)
+      {
+         _error = fclose(fp);
+         if (_error == EOF)
+            notifyError(AXE_FCLOSE_ERROR);
+         notifyError(AXE_FWRITE_ERROR);
+      }
+
+      /* print the directive identifier */
+      if (current_data->directiveType == DIR_WORD)
+      {
+         if (fprintf(fp, ".WORD ") < 0)
+         {
+            _error = fclose(fp);
+            if (_error == EOF)
+               notifyError(AXE_FCLOSE_ERROR);
+            notifyError(AXE_FWRITE_ERROR);
+         }
+      }
+      
+      else if (current_data->directiveType == DIR_SPACE)
+      {
+         if (fprintf(fp, ".SPACE ") < 0)
+         {
+            _error = fclose(fp);
+            if (_error == EOF)
+               notifyError(AXE_FCLOSE_ERROR);
+            notifyError(AXE_FWRITE_ERROR);
+         }
+      }
+
+      /* print the value associated with the directive */
+      if (fprintf(fp, "%d\n", current_data->value) < 0)
+      {
+         _error = fclose(fp);
+         if (_error == EOF)
+            notifyError(AXE_FCLOSE_ERROR);
+         notifyError(AXE_FWRITE_ERROR);
+      }
+
+      /* loop termination condition */
+      current_element = LNEXT(current_element);
+   }
+}
+
+void finalizeDataSegment(t_list *dataDirectives)
+{
+   t_list *current_element;
+   t_axe_data *current_data;
+
+   /* nothing to finalize */
+   if (dataDirectives == NULL)
+      return;
+
+   current_element = dataDirectives;
+   while(current_element != NULL)
+   {
+      /* retrieve the current instruction */
+      current_data = (t_axe_data *) LDATA(current_element);
+      if (current_data != NULL)
+         free_Data(current_data);
+
+      current_element = LNEXT(current_element);
+   }
+
+   /* free the list of instructions */
+   freeList(dataDirectives);
+}
+
+void finalizeInstructions(t_list *instructions)
+{
+   t_list *current_element;
+   t_axe_instruction *current_instr;
+
+   /* nothing to finalize */
+   if (instructions == NULL)
+      return;
+
+   current_element = instructions;
+   while(current_element != NULL)
+   {
+      /* retrieve the current instruction */
+      current_instr = (t_axe_instruction *) LDATA(current_element);
+      if (current_instr != NULL)
+         free_Instruction(current_instr);
+
+      current_element = LNEXT(current_element);
+   }
+
+   /* free the list of instructions */
+   freeList(instructions);
+}
+
+int compareVariables (void *Var_A, void *Var_B)
+{
+   t_axe_variable *va;
+   t_axe_variable *vb;
+   
+   if (Var_A == NULL)
+   {
+      if (Var_B == NULL)
+         return 1;
+   }
+
+   if (Var_B == NULL)
+      return 0;
+
+   va = (t_axe_variable *) Var_A;
+   vb = (t_axe_variable *) Var_B;
+
+   /* test if the name is the same */
+   return (!strcmp(va->ID, vb->ID));
+}
+
+t_axe_variable * getVariable
+      (t_program_infos *program, char *ID)
+{
+   t_axe_variable search_pattern;
+   t_list *elementFound;
+   
+   /* preconditions */
+   if (program == NULL)
+      notifyError(AXE_PROGRAM_NOT_INITIALIZED);
+
+   if (ID == NULL)
+      notifyError(AXE_VARIABLE_ID_UNSPECIFIED);
+
+   /* initialize the pattern */
+   search_pattern.ID = ID;
+   
+   /* search inside the list of variables */
+   elementFound = CustomfindElement
+         (program->variables, &search_pattern, compareVariables);
+
+   /* if the element is found return it to the caller. Otherwise return NULL. */
+   if (elementFound != NULL)
+      return (t_axe_variable *) LDATA(elementFound);
+
+   return NULL;
+}
+
+/* initialize an instance of `t_program_infos' */
+t_program_infos * allocProgramInfos()
+{
+   t_program_infos *result;
+
+   /* initialize the local variable `result' */
+   result = (t_program_infos *)
+         _AXE_ALLOC_FUNCTION(sizeof(t_program_infos));
+
+   /* verify if an error occurred during the memory allocation
+    * process */
+   if (result == NULL)
+      notifyError(AXE_OUT_OF_MEMORY);
+
+   /* initialize the new instance of `result' */
+   result->variables = NULL;
+   result->instructions = NULL;
+   result->data = NULL;
+   result->current_register = 1; /* we are excluding the register R0 */
+   result->lmanager = initialize_label_manager();
+
+   if (result->lmanager == NULL)
+   {
+      finalizeProgramInfos(result);
+      notifyError(AXE_OUT_OF_MEMORY);
+   }
+
+   result->sy_table = initialize_sy_table();
+   
+   /* test if the sy_table is a NULL pointer */
+   if (result->sy_table == NULL)
+   {
+      finalizeProgramInfos(result);
+      notifyError(AXE_OUT_OF_MEMORY);
+   }
+   
+   /* postcondition: return an instance of `t_program_infos' */
+   return result;
+}
+
+/* add an instruction at the tail of the list `program->instructions'.
+ * Returns an error code. */
+void addInstruction(t_program_infos *program, t_axe_instruction *instr)
+{
+   /* test the preconditions */
+   if (program == NULL)
+      notifyError(AXE_PROGRAM_NOT_INITIALIZED);
+   
+   if (instr == NULL)
+      notifyError(AXE_INVALID_INSTRUCTION);
+
+   if (program->lmanager == NULL)
+      notifyError(AXE_INVALID_LABEL_MANAGER);
+
+   instr->labelID = assign_label(program->lmanager);
+
+   /* update the list of instructions */
+   program->instructions = addElement(program->instructions, instr, -1);
+}
+
+/* reserve a new label identifier for future uses */
+t_axe_label * newLabel(t_program_infos *program)
+{
+   /* test the preconditions */
+   if (program == NULL)
+      notifyError(AXE_PROGRAM_NOT_INITIALIZED);
+
+   if (program->lmanager == NULL)
+      notifyError(AXE_INVALID_LABEL_MANAGER);
+
+   return newLabelID(program->lmanager);
+}
+
+/* assign a new label identifier to the next instruction */
+t_axe_label * assignLabel(t_program_infos *program, t_axe_label *label)
+{
+   /* test the preconditions */
+   if (program == NULL)
+      notifyError(AXE_PROGRAM_NOT_INITIALIZED);
+
+   if (program->lmanager == NULL)
+      notifyError(AXE_INVALID_LABEL_MANAGER);
+
+   /* fix the label */
+   return assignLabelID(program->lmanager, label);
+}
+
+/* reserve a new label identifier */
+t_axe_label * assignNewLabel(t_program_infos *program)
+{
+   t_axe_label * reserved_label;
+
+   /* reserve a new label */
+   reserved_label = newLabel(program);
+   if (reserved_label == NULL)
+      return NULL;
+
+   /* fix the label */
+   return assignLabel(program, reserved_label);
+}
+
+void addVariable(t_program_infos *program, t_axe_variable *variable)
+{
+   t_axe_variable *variableFound;
+   t_axe_data *new_data_info;
+   int sy_error;
+   
+   /* test the preconditions */
+   if (variable == NULL)
+      notifyError(AXE_INVALID_VARIABLE);
+
+   if (program == NULL)
+   {
+      free_variable(variable);
+      notifyError(AXE_PROGRAM_NOT_INITIALIZED);
+   }
+
+   if (variable->ID == NULL)
+   {
+      free_variable(variable);
+      notifyError(AXE_VARIABLE_ID_UNSPECIFIED);
+   }
+
+   if (variable->type == UNKNOWN_TYPE)
+   {
+      free_variable(variable);
+      notifyError(AXE_INVALID_TYPE);
+   }
+
+   if (variable->isArray)
+   {
+      if (variable->arraySize <= 0)
+      {
+         free_variable(variable);
+         notifyError(AXE_INVALID_ARRAY_SIZE);
+      }
+   }
+   
+   if (variable->labelID == NULL)
+   {
+      free_variable(variable);
+      notifyError(AXE_INVALID_LABEL);
+   }
+   
+   /* we have to test if already exists a variable with the same ID */
+   variableFound = getVariable(program, variable->ID);
+
+   if (variableFound != NULL)
+   {
+      free_variable(variable);
+      notifyError(AXE_VARIABLE_ALREADY_DECLARED);
+   }
+
+   /* now we can add the new variable to the program */
+   program->variables = addElement(program->variables, variable, -1);
+
+   /* create an instance of `t_axe_data' */
+   if (variable->type == INTEGER_TYPE)
+   {
+      if (variable->isArray)
+      {
+         new_data_info = alloc_data
+               (DIR_SPACE, (variable->arraySize * 4), variable->labelID);
+         
+         if (new_data_info == NULL)
+            notifyError(AXE_OUT_OF_MEMORY);
+      }
+      else
+      {
+         new_data_info = alloc_data
+            (DIR_WORD, variable->init_val, variable->labelID);
+         
+         if (new_data_info == NULL)
+            notifyError(AXE_OUT_OF_MEMORY);
+      }
+   }
+
+   /* update the list of directives */
+   program->data = addElement(program->data, new_data_info, -1);
+
+   /* update the content of the symbol table */
+   sy_error = putSym(program->sy_table, variable->ID, variable->type);
+     
+   if (sy_error != SY_TABLE_OK)
+      notifyError(AXE_SY_TABLE_ERROR);
+}
+
+int getNewRegister(t_program_infos *program)
+{
+   int result;
+   
+   /* test the preconditions */
+   if (program == NULL)
+      notifyError(AXE_PROGRAM_NOT_INITIALIZED);
+
+   result = program->current_register;
+   program->current_register++;
+   
+   /* return the current label identifier */
+   return result;
+}
+
+void finalizeProgramInfos(t_program_infos *program)
+{
+   if (program == NULL)
+      return;
+   if (program->variables != NULL)
+      finalizeVariables(program->variables);
+   if (program->instructions != NULL)
+      finalizeInstructions(program->instructions);
+   if (program->data != NULL)
+      finalizeDataSegment(program->data);
+   if (program->lmanager != NULL)
+      finalize_label_manager(program->lmanager);
+   if (program->sy_table != NULL)
+      finalize_sy_table(program->sy_table);
+
+   _AXE_FREE_FUNCTION(program);
+}
+
+void writeAssembly(t_program_infos *program, char *output_file)
+{
+   FILE *fp;
+   int _error;
+
+   /* test the preconditions */
+   if (program == NULL)
+      notifyError(AXE_PROGRAM_NOT_INITIALIZED);
+
+   /* If necessary, set the value of `output_file' to "output.asm" */
+   if (output_file == NULL)
+   {
+      /* set "output.o" as output file name */
+      output_file = "output.asm";
+   }
+
+#ifndef NDEBUG
+   fprintf(stdout, "\n\n*******************************************\n");
+   fprintf(stdout, "INITIALIZING OUTPUT FILE: %s. \n", output_file);
+   fprintf(stdout, "CODE SEGMENT has a size of %d instructions \n"
+         , getLength(program->instructions));
+   fprintf(stdout, "DATA SEGMENT has a size of %d elements \n"
+         , getLength(program->data));
+   fprintf(stdout, "NUMBER OF LABELS : %d. \n"
+         , get_number_of_labels(program->lmanager));
+   fprintf(stdout, "*******************************************\n\n");
+#endif
+   
+   /* open a new file */
+   fp = fopen(output_file, "w");
+   if (fp == NULL)
+      notifyError(AXE_FOPEN_ERROR);
+
+   /* print the data segment */
+   translateDataSegment(program, fp);
+
+   /* print the code segment */
+   translateCodeSegment(program, fp);
+
+   /* close the file and return */
+   _error = fclose(fp);
+   if (_error == EOF)
+      notifyError(AXE_FCLOSE_ERROR);
+}
+
+void printOpcode(int opcode, FILE *fp)
+{
+   char *opcode_to_string;
+   int _error;
+   
+   /* preconditions: fp must be different from NULL */
+   if (fp == NULL)
+      notifyError(AXE_INVALID_INPUT_FILE);
+
+   switch(opcode)
+   {
+      case ADD : opcode_to_string = "ADD"; break;
+      case SUB : opcode_to_string = "SUB"; break;
+      case ANDL : opcode_to_string = "ANDL"; break;
+      case ORL : opcode_to_string = "ORL"; break;
+      case EORL : opcode_to_string = "EORL"; break;
+      case ANDB : opcode_to_string = "ANDB"; break;
+      case ORB : opcode_to_string = "ORB"; break;
+      case EORB : opcode_to_string = "EORB"; break;
+      case MUL : opcode_to_string = "MUL"; break;
+      case DIV : opcode_to_string = "DIV"; break;
+      case SHL : opcode_to_string = "SHL"; break;
+      case SHR : opcode_to_string = "SHR"; break;
+      case ROTL : opcode_to_string = "ROTL"; break;
+      case ROTR : opcode_to_string = "ROTR"; break;
+      case NEG : opcode_to_string = "NEG"; break;
+      case SPCL : opcode_to_string = "SPCL"; break;
+      case ADDI : opcode_to_string = "ADDI"; break;
+      case SUBI : opcode_to_string = "SUBI"; break;
+      case ANDLI : opcode_to_string = "ANDLI"; break;
+      case ORLI : opcode_to_string = "ORLI"; break;
+      case EORLI : opcode_to_string = "EORLI"; break;
+      case ANDBI : opcode_to_string = "ANDBI"; break;
+      case ORBI : opcode_to_string = "ORBI"; break;
+      case EORBI : opcode_to_string = "EORBI"; break;
+      case MULI : opcode_to_string = "MULI"; break;
+      case DIVI : opcode_to_string = "DIVI"; break;
+      case SHLI : opcode_to_string = "SHLI"; break;
+      case SHRI : opcode_to_string = "SHRI"; break;
+      case ROTLI : opcode_to_string = "ROTLI"; break;
+      case ROTRI : opcode_to_string = "ROTRI"; break;
+      case NOTL : opcode_to_string = "NOTL"; break;
+      case NOTB : opcode_to_string = "NOTB"; break;
+      case NOP : opcode_to_string = "NOP"; break;
+      case MOVA : opcode_to_string = "MOVA"; break;
+      case JSR : opcode_to_string = "JSR"; break;
+      case RET : opcode_to_string = "RET"; break;
+      case HALT : opcode_to_string = "HALT"; break;
+      case BT : opcode_to_string = "BT"; break;
+      case BF : opcode_to_string = "BF"; break;
+      case BHI : opcode_to_string = "BHI"; break;
+      case BLS : opcode_to_string = "BLS"; break;
+      case BCC : opcode_to_string = "BCC"; break;
+      case BCS : opcode_to_string = "BCS"; break;
+      case BNE : opcode_to_string = "BNE"; break;
+      case BEQ : opcode_to_string = "BEQ"; break;
+      case BVC : opcode_to_string = "BVC"; break;
+      case BVS : opcode_to_string = "BVS"; break;
+      case BPL : opcode_to_string = "BPL"; break;
+      case BMI : opcode_to_string = "BMI"; break;
+      case BGE : opcode_to_string = "BGE"; break;
+      case BLT : opcode_to_string = "BLT"; break;
+      case BGT : opcode_to_string = "BGT"; break;
+      case BLE : opcode_to_string = "BLE"; break;
+      case LOAD : opcode_to_string = "LOAD"; break;
+      case STORE : opcode_to_string = "STORE"; break;
+      case SEQ : opcode_to_string = "SEQ"; break;
+      case SGE : opcode_to_string = "SGE"; break;
+      case SGT : opcode_to_string = "SGT"; break;
+      case SLE : opcode_to_string = "SLE"; break;
+      case SLT : opcode_to_string = "SLT"; break;
+      case SNE : opcode_to_string = "SNE"; break;
+      case AXE_READ : opcode_to_string = "READ"; break;
+      case AXE_WRITE : opcode_to_string = "WRITE"; break;
+      default :
+         /* close the file and return */
+         _error = fclose(fp);
+         if (_error == EOF)
+            notifyError(AXE_FCLOSE_ERROR);
+         notifyError(AXE_INVALID_OPCODE);
+   }
+      
+   /* postconditions */
+   if (fprintf(fp, "%s", opcode_to_string) < 0)
+   {
+      _error = fclose(fp);
+      if (_error == EOF)
+         notifyError(AXE_FCLOSE_ERROR);
+      notifyError(AXE_FWRITE_ERROR);
+   }
+}
+
+void printRegister(t_axe_register *reg, FILE *fp)
+{
+   int _error;
+   
+   /* preconditions: fp must be different from NULL */
+   if (fp == NULL)
+      notifyError(AXE_INVALID_INPUT_FILE);
+   if (reg == NULL)
+   {
+      _error = fclose(fp);
+      if (_error == EOF)
+         notifyError(AXE_FCLOSE_ERROR);
+      notifyError(AXE_INVALID_REGISTER_INFO);
+   }
+   if (reg->ID == REG_INVALID)
+   {
+      _error = fclose(fp);
+      if (_error == EOF)
+         notifyError(AXE_FCLOSE_ERROR);
+      notifyError(AXE_INVALID_REGISTER_INFO);
+   }
+
+   if (reg->indirect)
+   {
+      if (fprintf(fp, "(R%d)", reg->ID) < 0)
+      {
+         _error = fclose(fp);
+         if (_error == EOF)
+            notifyError(AXE_FCLOSE_ERROR);
+         notifyError(AXE_FWRITE_ERROR);
+      }
+   }
+   else
+   {
+      if (fprintf(fp, "R%d", reg->ID) < 0)
+      {
+         _error = fclose(fp);
+         if (_error == EOF)
+            notifyError(AXE_FCLOSE_ERROR);
+         notifyError(AXE_FWRITE_ERROR);
+      }
+   }
+}
+
+t_axe_label * getLabelFromVariableID(t_program_infos *program, char *ID)
+{
+   t_axe_variable *var;
+   
+   var = getVariable(program, ID);
+   if (var == NULL)
+      return NULL;
+
+   /* test the postconditions */
+   assert(var->labelID != NULL);
+   
+   return var->labelID;
+}
+
+void finalizeVariables(t_list *variables)
+{
+   t_list *current_element;
+   t_axe_variable *current_var;
+
+   if (variables == NULL)
+      return;
+
+   /* initialize the `current_element' */
+   current_element = variables;
+   while(current_element != NULL)
+   {
+      current_var = (t_axe_variable *) LDATA(current_element);
+      if (current_var != NULL)
+      {
+         if (current_var->ID != NULL)
+            free(current_var->ID);
+         
+         _AXE_FREE_FUNCTION(current_var);
+      }
+      
+      current_element = LNEXT(current_element);
+   }
+
+   /* free the list of variables */
+   freeList(variables);
+}

+ 74 - 0
acse/axe_engine.h

@@ -0,0 +1,74 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * axe_engine.h
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#ifndef _AXE_ENGINE_H
+#define _AXE_ENGINE_H
+
+#include "axe_struct.h"
+#include "axe_labels.h"
+#include "collections.h"
+#include "symbol_table.h"
+
+typedef struct t_program_infos
+{
+  t_list *variables;
+  t_list *instructions;
+  t_list *data;
+  t_axe_label_manager *lmanager;
+  t_symbol_table *sy_table;
+  int current_register;
+} t_program_infos;
+
+
+/* initialize the informations associated with the program. This function is
+ * called at the beginning of the translation process. This function
+ * is called once: its only purpouse is to initialize an instance of the struct
+ * `t_program_infos' that will contain all the informations about the program
+ * that will be compiled */
+extern t_program_infos * allocProgramInfos();
+
+/* add a new instruction to the current program. This function is directly
+ * called by all the functions defined in `axe_gencode.h' */
+extern void addInstruction(t_program_infos *program, t_axe_instruction *instr);
+
+/* reserve a new label identifier and return the identifier to the caller */
+extern t_axe_label * newLabel(t_program_infos *program);
+
+/* assign the given label identifier to the next instruction. Returns
+ * the label assigned; otherwise (an error occurred) LABEL_UNSPECIFIED */
+extern t_axe_label * assignLabel(t_program_infos *program, t_axe_label *label);
+
+/* reserve and fix a new label. It returns either the label assigned or the
+ * value LABEL_UNSPECIFIED if an error occurred */
+extern t_axe_label * assignNewLabel(t_program_infos *program);
+
+/* add a variable to the program */
+extern void createVariable(t_program_infos *program
+      , char *ID, int type, int isArray, int arraySize, int init_val);
+
+/* get a previously allocated variable */
+extern t_axe_variable * getVariable
+      (t_program_infos *program, char *ID);
+
+/* get the label that marks the starting address of the variable
+ * with name "ID" */
+extern t_axe_label * getLabelFromVariableID
+            (t_program_infos *program, char *ID);
+
+/* get a register still not used. This function returns
+ * the ID of the register found*/
+extern int getNewRegister(t_program_infos *program);
+
+/* finalize all the data structures associated with `program' */
+extern void finalizeProgramInfos(t_program_infos *program);
+
+/* write the corresponding assembly for the given program */
+extern void writeAssembly(t_program_infos *program, char *output_file);
+
+#endif

+ 145 - 0
acse/axe_errors.c

@@ -0,0 +1,145 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * axe_errors.c
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#include "axe_errors.h"
+#include "axe_utils.h"
+#include "cflow_constants.h"
+
+/* @see Acse.y for these declarations */
+extern int num_warning;
+extern int num_error;
+extern int line_num;
+extern int errorcode;
+extern int cflow_errorcode;
+
+
+static void abortProgram();
+static void printErrorMessage(int errorcode);
+
+void abortProgram()
+{
+   if (num_error > 0)
+   {
+      fprintf(stderr,   "Input file contains some errors. "
+                        "No assembly file written\n");
+      fprintf(stderr, "**%d error(s) found \n\n", num_error);
+   }
+
+   /* finalize all the data structures */
+   shutdownCompiler(-1);
+}
+
+void printWarningMessage(int warningcode)
+{
+   char *msg;
+   
+   switch (warningcode)
+   {
+      case WARN_DIVISION_BY_ZERO : msg = "warning: division by zero"; break;
+      default : msg = "<invalid warning>"; break;
+   }
+   
+   /* print out to the standard error the warning message */
+   printMessage(msg);
+
+   /* update the value of num_warning */
+   num_warning++;
+}
+
+static void printErrorMessage(int errorcode)
+{
+   char *msg;
+  
+   switch(errorcode)
+   {
+      case AXE_OUT_OF_MEMORY : msg = "error: Out of memory"; break;
+      case AXE_PROGRAM_NOT_INITIALIZED :
+                  msg = "error: Program not initialized"; break;
+      case AXE_INVALID_INSTRUCTION :
+                  msg = "error: Invalid instruction"; break;
+      case AXE_VARIABLE_ID_UNSPECIFIED :
+                  msg = "error: Variable ID unspecified"; break;
+      case AXE_VARIABLE_ALREADY_DECLARED :
+                  msg = "error: Variable already declared"; break;
+      case AXE_INVALID_TYPE : msg = "error: Invalid type"; break;
+      case AXE_FOPEN_ERROR : msg = "error: fopen failed"; break;
+      case AXE_FCLOSE_ERROR : msg = "error: fclose failed"; break;
+      case AXE_INVALID_INPUT_FILE : msg = "error: Wrong file pointer"; break;
+      case AXE_FWRITE_ERROR : msg = "error: Error while writing on file"; break;
+      case AXE_INVALID_DATA_FORMAT : msg = "error: Invalid data format"; break;
+      case AXE_INVALID_OPCODE : msg = "error: Invalid opcode found"; break;
+      case AXE_INVALID_REGISTER_INFO :
+                  msg = "error: Invalid register infos"; break;
+      case AXE_INVALID_LABEL : msg = "error: Invalid label found"; break;
+      case AXE_INVALID_LABEL_MANAGER :
+                  msg = "error: Invalid label manager"; break;
+      case AXE_INVALID_ARRAY_SIZE : msg = "error: Invalid array size"; break;
+      case AXE_INVALID_VARIABLE : msg = "error: Invalid variable found"; break;
+      case AXE_INVALID_ADDRESS : msg = "error: Invalid address"; break;
+      case AXE_INVALID_EXPRESSION :
+                  msg = "error: Invalid expression found"; break;
+      case AXE_UNKNOWN_VARIABLE : msg = "error: Unknown variable found"; break;
+      case AXE_SY_TABLE_ERROR :
+                  msg = "error: Symbol table returned an errorcode"; break;
+      case AXE_NULL_DECLARATION : msg = "error: NULL declaration found"; break;
+      case AXE_LABEL_ALREADY_ASSIGNED :
+                  msg = "error: label already assigned"; break;
+      case AXE_INVALID_CFLOW_GRAPH : msg = "error: Invalid "
+                  "control-dataflow graph informations"; break;
+      case AXE_INVALID_REG_ALLOC : msg = "error: Invalid "
+                  "register allocator instance found"; break;
+      case AXE_REG_ALLOC_ERROR : msg = "error: "
+                  "register allocation failed"; break;
+      case AXE_TRANSFORM_ERROR : msg = "error: "
+                  "Invalid operation while modifying the instructions"; break;
+      case AXE_SYNTAX_ERROR : msg = "error: "
+                  "Syntax error found"; break;
+      case AXE_UNKNOWN_ERROR : msg = "error: Unknown error"; break;
+      default : msg = "<invalid errorcode>"; break;
+   }
+   
+   /* print out to the standard error the error message */
+   printMessage(msg);
+
+   /* update the value of num_error */
+   num_error++;
+}
+
+void printMessage(const char *msg)
+{
+   if (line_num != -1)
+      fprintf(stderr, "\nAt line %d , %s.\n", line_num, msg);
+   else
+      fprintf(stderr, "%s.\n", msg);
+}
+
+void notifyError(int axe_errorcode)
+{
+   errorcode = axe_errorcode;
+   checkConsistency();
+}
+
+void checkConsistency()
+{
+   /* test if an error occurred */
+   if (errorcode != AXE_OK) {
+      printErrorMessage(errorcode);
+      abortProgram();
+   }
+
+   if (cflow_errorcode != CFLOW_OK)
+   {
+      fprintf(stderr, "An error occurred while working with the "
+                 "cflow graph. cflow_errorcode = %d"
+                 "\n(see axe_cflow_graph.[ch])\n", cflow_errorcode);
+      
+      printErrorMessage(AXE_UNKNOWN_ERROR);
+      abortProgram();
+   }
+}

+ 21 - 0
acse/axe_errors.h

@@ -0,0 +1,21 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * axe_errors.h
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#ifndef _AXE_ERRORS_H
+#define _AXE_ERRORS_H
+
+#include "axe_engine.h"
+#include "axe_constants.h"
+
+extern void printWarningMessage(int warningcode);
+extern void printMessage(const char *msg);
+extern void notifyError(int axe_errorcode);
+extern void checkConsistency();
+
+#endif

+ 298 - 0
acse/axe_expressions.c

@@ -0,0 +1,298 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * axe_expressions.c
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#include "axe_expressions.h"
+#include "axe_gencode.h"
+#include "axe_errors.h"
+#include "axe_utils.h"
+
+
+static t_axe_expression handle_bin_numeric_op_Imm
+         (int val1, int val2, int binop);
+         
+static t_axe_expression handle_bin_comparison_Imm
+         (int val1, int val2, int condition);
+
+
+static t_axe_expression normalize(t_program_infos *program,
+                                  t_axe_expression exp);
+
+t_axe_expression handle_bin_numeric_op (t_program_infos *program
+         , t_axe_expression exp1, t_axe_expression exp2, int binop)
+{
+   int output_register;
+   t_axe_expression result;
+
+   /* initialize result */
+   result.expression_type = INVALID_EXPRESSION;
+
+   /* we have to test if one (or both) of
+   * the two operands is an immediate value */
+   if (  (exp2.expression_type == IMMEDIATE)
+         && (exp1.expression_type == IMMEDIATE) )
+   {
+      return handle_bin_numeric_op_Imm(exp1.value, exp2.value, binop);
+   }
+
+   exp1 = normalize(program, exp1);
+   exp2 = normalize(program, exp2);
+   
+   /* at first we have to ask for a free register
+   * where to store the result of the operation. */
+   output_register = getNewRegister(program);
+
+   if (exp2.expression_type == IMMEDIATE)
+   {
+      /* we have to produce an instruction */
+      switch(binop)
+      {
+         case ADD : gen_addi_instruction (program, output_register
+                             , exp1.value, exp2.value); break;
+         case ANDB : gen_andbi_instruction (program, output_register
+                              , exp1.value, exp2.value); break;
+         case ORB  : gen_orbi_instruction (program, output_register
+                             , exp1.value, exp2.value); break;
+         case SUB : gen_subi_instruction (program, output_register
+                             , exp1.value, exp2.value); break;
+         case MUL : gen_muli_instruction (program, output_register
+                             , exp1.value, exp2.value); break;
+         case SHL : gen_shli_instruction (program, output_register
+                             , exp1.value, exp2.value); break;
+         case SHR : gen_shri_instruction (program, output_register
+                             , exp1.value, exp2.value); break;
+         case DIV :
+               if (exp2.value == 0){
+                  printWarningMessage(WARN_DIVISION_BY_ZERO);
+               }
+               gen_divi_instruction (program, output_register
+                        , exp1.value, exp2.value);
+               break;
+         default :
+               notifyError(AXE_INVALID_EXPRESSION);
+      }
+   }
+   else if (exp1.expression_type == IMMEDIATE)
+   {
+      int other_reg;
+
+      /* we have to produce an instruction */
+      switch(binop)
+      {
+         case ADD :  gen_addi_instruction (program, output_register
+                              , exp2.value, exp1.value); break;
+         case ANDB :  gen_andbi_instruction (program, output_register
+                              , exp2.value, exp1.value); break;
+         case ORB  :  gen_orbi_instruction (program, output_register
+                              , exp2.value, exp1.value); break;
+         case SUB :
+                  gen_subi_instruction (program, output_register
+                           , exp2.value, exp1.value);
+
+                  /* we have to produce a NEG instruction */
+                  gen_neg_instruction (program, output_register
+                           , output_register, CG_DIRECT_ALL);
+                  break;
+         case MUL :  gen_muli_instruction (program, output_register
+                              , exp2.value, exp1.value); break;
+         case DIV :
+                  /* we have to load into a register the immediate value */
+                  other_reg = getNewRegister(program);
+
+                  /* In order to load the immediate inside a new
+                   * register we have to insert an ADDI instr. */
+                  gen_addi_instruction (program, other_reg
+                           , REG_0, exp1.value);
+
+                  /* we have to produce a DIV instruction */
+                  gen_div_instruction (program, output_register
+                           , other_reg, exp2.value, CG_DIRECT_ALL);
+                  break;
+         case SHL :
+                  /* we have to load into a register the immediate value */
+                  other_reg = getNewRegister(program);
+
+                  /* In order to load the immediate inside a new
+                   * register we have to insert an ADDI instr. */
+                  gen_addi_instruction (program, other_reg
+                           , REG_0, exp1.value);
+
+                  /* we have to produce a SHL instruction */
+                  gen_shl_instruction (program, output_register
+                           , other_reg, exp2.value, CG_DIRECT_ALL);
+                  break;
+         case SHR :
+                  /* we have to load into a register the immediate value */
+                  other_reg = getNewRegister(program);
+
+                  /* In order to load the immediate inside a new
+                   * register we have to insert an ADDI instr. */
+                  gen_addi_instruction (program, other_reg
+                           , REG_0, exp1.value);
+
+                  /* we have to produce a SHR instruction */
+                  gen_shr_instruction (program, output_register
+                           , other_reg, exp2.value, CG_DIRECT_ALL);
+                  break;
+         default :
+                  notifyError(AXE_INVALID_EXPRESSION);
+      }
+   }
+   else
+   {
+      /* we have to produce an instruction */
+      switch(binop)
+      {
+         case ADD :  gen_add_instruction (program, output_register
+                              , exp1.value, exp2.value, CG_DIRECT_ALL);
+                     break;
+         case ANDB :  gen_andb_instruction (program, output_register
+                              , exp1.value, exp2.value, CG_DIRECT_ALL);
+                     break;
+         case ORB :  gen_orb_instruction (program, output_register
+                              , exp1.value, exp2.value, CG_DIRECT_ALL);
+                     break;
+         case SUB :  gen_sub_instruction (program, output_register
+                              , exp1.value, exp2.value, CG_DIRECT_ALL);
+                     break;
+         case MUL :  gen_mul_instruction (program, output_register
+                              , exp1.value, exp2.value, CG_DIRECT_ALL);
+                     break;
+         case DIV :  gen_div_instruction (program, output_register
+                              , exp1.value, exp2.value, CG_DIRECT_ALL);
+                     break;
+         case SHL :  gen_shl_instruction (program, output_register
+                              , exp1.value, exp2.value, CG_DIRECT_ALL);
+                     break;
+         case SHR :  gen_shr_instruction (program, output_register
+                              , exp1.value, exp2.value, CG_DIRECT_ALL);
+                     break;
+         default :
+                     notifyError(AXE_INVALID_EXPRESSION);
+      }
+   }
+         
+   /* assign a value to result */
+   return create_expression (output_register, REGISTER);
+}
+
+t_axe_expression handle_bin_numeric_op_Imm
+         (int val1, int val2, int binop)
+{
+   switch(binop)
+   {
+      case ADD : return create_expression ((val1 + val2), IMMEDIATE);
+      case ANDB : return create_expression ((val1 & val2), IMMEDIATE);
+      case ORB  : return create_expression ((val1 | val2), IMMEDIATE);
+      case SUB : return create_expression ((val1 - val2), IMMEDIATE);
+      case MUL : return create_expression ((val1 * val2), IMMEDIATE);
+      case SHL : return create_expression ((val1 << val2), IMMEDIATE);
+      case SHR : return create_expression ((val1 >> val2), IMMEDIATE);
+      case DIV :
+         if (val2 == 0){
+            printWarningMessage(WARN_DIVISION_BY_ZERO);
+         }
+         return create_expression ((val1 / val2), IMMEDIATE);
+      default :
+         notifyError(AXE_INVALID_EXPRESSION);
+   }
+   
+   return create_expression (0, INVALID_EXPRESSION);
+}
+
+t_axe_expression handle_bin_comparison_Imm
+         (int val1, int val2, int condition)
+{
+   switch(condition)
+   {
+      case _LT_ : return create_expression ((val1 < val2), IMMEDIATE);
+      case _GT_ : return create_expression ((val1 > val2), IMMEDIATE);
+      case _EQ_  : return create_expression ((val1 == val2), IMMEDIATE);
+      case _NOTEQ_ : return create_expression ((val1 != val2), IMMEDIATE);
+      case _LTEQ_ : return create_expression ((val1 <= val2), IMMEDIATE);
+      case _GTEQ_ : return create_expression ((val1 >= val2), IMMEDIATE);
+      default :
+         notifyError(AXE_INVALID_EXPRESSION);
+   }
+
+   return create_expression (0, INVALID_EXPRESSION);
+}
+
+t_axe_expression normalize(t_program_infos *program, t_axe_expression exp)
+{
+   if (exp.expression_type ==  IMMEDIATE && !is_int16(exp.value))
+   {
+      int tmp_reg = gen_load_immediate(program, exp.value);
+      return create_expression(tmp_reg, REGISTER);
+   }
+   return exp;
+}
+
+t_axe_expression handle_binary_comparison (t_program_infos *program
+         , t_axe_expression exp1, t_axe_expression exp2, int condition)
+{
+   t_axe_expression result;
+   int output_register;
+   
+   /* initialize result */
+   result.expression_type = INVALID_EXPRESSION;
+
+   /* we have to test if one (or both) of
+   * the two operands is an immediate value */
+   if (  (exp2.expression_type == IMMEDIATE)
+         && (exp1.expression_type == IMMEDIATE) )
+   {
+      return handle_bin_comparison_Imm
+                  (exp1.value, exp2.value, condition);
+   }
+
+   exp1 = normalize(program, exp1);
+   exp2 = normalize(program, exp2);
+                     
+   /* at first we have to ask for a free register
+   * where to store the result of the comparison. */
+   output_register = getNewRegister(program);
+
+   if (exp2.expression_type == IMMEDIATE)
+   {
+      /* we have to produce a SUBI instruction */
+      gen_subi_instruction (program, output_register
+               , exp1.value, exp2.value);
+   }
+   else if (exp1.expression_type == IMMEDIATE)
+   {
+      gen_subi_instruction (program, output_register
+               , exp2.value, exp1.value);
+
+      /* we have to produce a NEG instruction */
+      gen_neg_instruction (program, output_register
+               , output_register, CG_DIRECT_ALL);
+   }
+   else
+   {
+      /* we have to produce a SUB instruction */
+      gen_sub_instruction (program, output_register
+               , exp1.value, exp2.value, CG_DIRECT_ALL);
+   }
+
+   /* generate a set instruction */
+   switch(condition)
+   {
+      case _LT_ : gen_slt_instruction (program, output_register); break;
+      case _GT_ : gen_sgt_instruction (program, output_register); break;
+      case _EQ_  : gen_seq_instruction (program, output_register); break;
+      case _NOTEQ_ : gen_sne_instruction (program, output_register); break;
+      case _LTEQ_ : gen_sle_instruction (program, output_register); break;
+      case _GTEQ_ : gen_sge_instruction (program, output_register); break;
+      default :
+         notifyError(AXE_INVALID_EXPRESSION);
+   }
+
+   /* return the new expression */
+   return create_expression (output_register, REGISTER);
+}

+ 53 - 0
acse/axe_expressions.h

@@ -0,0 +1,53 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * axe_expressions.h
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#ifndef _AXE_EXPRESSIONS_H
+#define _AXE_EXPRESSIONS_H
+
+#include "axe_engine.h"
+
+/* This function generats instructions for binary numeric
+ * operations.  It takes as input two expressions and a binary
+ * operation identifier, and it returns a new expression that
+ * represents the result of the specified binary operation
+ * applied to `exp1' and `exp2'.
+ *
+ * Valid values for `binop' are:
+ * ADD
+ * ANDB
+ * ORB
+ * SUB
+ * MUL
+ * DIV */
+extern t_axe_expression handle_bin_numeric_op (t_program_infos *program
+         , t_axe_expression exp1, t_axe_expression exp2, int binop);
+
+/* This function generates instructions that perform a
+ * comparison between two values.  It takes as input two
+ * expressions and a binary comparison identifier, and it
+ * returns a new expression that represents the result of the
+ * specified binary comparison between `exp1' and `exp2'.
+ *
+ * Valid values for `condition' are:
+ * _LT_     (used when is needed to test if the value of `exp1' is less than
+ *           the value of `exp2')
+ * _GT_     (used when is needed to test if the value of `exp1' is greater than
+ *           the value of `exp2')
+ * _EQ_     (used when is needed to test if the value of `exp1' is equal to
+ *           the value of `exp2')
+ * _NOTEQ_  (used when is needed to test if the value of `exp1' is not equal to
+ *           the value of `exp2')
+ * _LTEQ_     (used when is needed to test if the value of `exp1' is less than
+ *          or equal to the value of `exp2')
+ * _GTEQ_     (used when is needed to test if the value of `exp1' is greater than
+ *           the value of `exp2')  */
+extern t_axe_expression handle_binary_comparison (t_program_infos *program
+         , t_axe_expression exp1, t_axe_expression exp2, int condition);
+
+#endif

+ 682 - 0
acse/axe_gencode.c

@@ -0,0 +1,682 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * axe_gencode.c
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#include "axe_gencode.h"
+#include "axe_errors.h"
+
+
+static t_axe_instruction * gen_unary_instruction (t_program_infos *program
+         , int opcode, int r_dest, t_axe_label *label, int addr);
+static t_axe_instruction * gen_binary_instruction (t_program_infos *program
+      , int opcode, int r_dest, int r_source1, int immediate);
+static t_axe_instruction * gen_ternary_instruction (t_program_infos *program
+      , int opcode, int r_dest, int r_source1, int r_source2, int flags);
+static t_axe_instruction * gen_jump_instruction (t_program_infos *program
+      , int opcode, t_axe_label *label, int addr);
+
+
+t_axe_instruction * gen_bt_instruction
+      (t_program_infos *program, t_axe_label *label, int addr)
+{
+   return gen_jump_instruction (program, BT, label, addr);
+}
+
+t_axe_instruction * gen_bf_instruction
+      (t_program_infos *program, t_axe_label *label, int addr)
+{
+   return gen_jump_instruction (program, BF, label, addr);
+}
+
+t_axe_instruction * gen_bhi_instruction
+      (t_program_infos *program, t_axe_label *label, int addr)
+{
+   return gen_jump_instruction (program, BHI, label, addr);
+}      
+      
+t_axe_instruction * gen_bls_instruction
+      (t_program_infos *program, t_axe_label *label, int addr)
+{
+   return gen_jump_instruction (program, BLS, label, addr);
+}
+
+t_axe_instruction * gen_bcc_instruction
+      (t_program_infos *program, t_axe_label *label, int addr)
+{
+   return gen_jump_instruction (program, BCC, label, addr);
+}
+
+t_axe_instruction * gen_bcs_instruction
+      (t_program_infos *program, t_axe_label *label, int addr)
+{
+   return gen_jump_instruction (program, BCS, label, addr);
+}
+
+t_axe_instruction * gen_bne_instruction
+      (t_program_infos *program, t_axe_label *label, int addr)
+{
+   return gen_jump_instruction (program, BNE, label, addr);
+}
+
+t_axe_instruction * gen_beq_instruction
+      (t_program_infos *program, t_axe_label *label, int addr)
+{
+   return gen_jump_instruction (program, BEQ, label, addr);
+}
+
+t_axe_instruction * gen_bvc_instruction
+      (t_program_infos *program, t_axe_label *label, int addr)
+{
+   return gen_jump_instruction (program, BVC, label, addr);
+}
+
+t_axe_instruction * gen_bvs_instruction
+      (t_program_infos *program, t_axe_label *label, int addr)
+{
+   return gen_jump_instruction (program, BVS, label, addr);
+}
+
+t_axe_instruction * gen_bpl_instruction
+      (t_program_infos *program, t_axe_label *label, int addr)
+{
+   return gen_jump_instruction (program, BPL, label, addr);
+}
+
+t_axe_instruction * gen_bmi_instruction
+      (t_program_infos *program, t_axe_label *label, int addr)
+{
+   return gen_jump_instruction (program, BMI, label, addr);
+}
+
+t_axe_instruction * gen_bge_instruction
+      (t_program_infos *program, t_axe_label *label, int addr)
+{
+   return gen_jump_instruction (program, BGE, label, addr);
+}
+
+t_axe_instruction * gen_blt_instruction
+      (t_program_infos *program, t_axe_label *label, int addr)
+{
+   return gen_jump_instruction (program, BLT, label, addr);
+}
+
+t_axe_instruction * gen_bgt_instruction
+      (t_program_infos *program, t_axe_label *label, int addr)
+{
+   return gen_jump_instruction (program, BGT, label, addr);
+}
+
+t_axe_instruction * gen_ble_instruction
+      (t_program_infos *program, t_axe_label *label, int addr)
+{
+   return gen_jump_instruction (program, BLE, label, addr);
+}
+
+t_axe_instruction * gen_add_instruction (t_program_infos *program
+      , int r_dest, int r_source1, int r_source2, int flags)
+{
+   return gen_ternary_instruction
+         (program, ADD, r_dest, r_source1, r_source2, flags);
+}
+
+t_axe_instruction * gen_sub_instruction (t_program_infos *program
+      , int r_dest, int r_source1, int r_source2, int flags)
+{
+   return gen_ternary_instruction
+         (program, SUB, r_dest, r_source1, r_source2, flags);
+}
+
+t_axe_instruction * gen_andl_instruction (t_program_infos *program
+      , int r_dest, int r_source1, int r_source2, int flags)
+{
+   return gen_ternary_instruction
+         (program, ANDL, r_dest, r_source1, r_source2, flags);
+}
+
+t_axe_instruction * gen_orl_instruction (t_program_infos *program
+      , int r_dest, int r_source1, int r_source2, int flags)
+{
+   return gen_ternary_instruction
+         (program, ORL, r_dest, r_source1, r_source2, flags);
+}
+
+t_axe_instruction * gen_eorl_instruction (t_program_infos *program
+      , int r_dest, int r_source1, int r_source2, int flags)
+{
+   return gen_ternary_instruction
+         (program, EORL, r_dest, r_source1, r_source2, flags);
+}
+
+t_axe_instruction * gen_andb_instruction (t_program_infos *program
+      , int r_dest, int r_source1, int r_source2, int flags)
+{
+   return gen_ternary_instruction
+         (program, ANDB, r_dest, r_source1, r_source2, flags);
+}
+
+t_axe_instruction * gen_orb_instruction (t_program_infos *program
+      , int r_dest, int r_source1, int r_source2, int flags)
+{
+   return gen_ternary_instruction
+         (program, ORB, r_dest, r_source1, r_source2, flags);
+}
+
+t_axe_instruction * gen_eorb_instruction (t_program_infos *program
+      , int r_dest, int r_source1, int r_source2, int flags)
+{
+   return gen_ternary_instruction
+         (program, EORB, r_dest, r_source1, r_source2, flags);
+}
+
+t_axe_instruction * gen_mul_instruction (t_program_infos *program
+      , int r_dest, int r_source1, int r_source2, int flags)
+{
+   return gen_ternary_instruction
+         (program, MUL, r_dest, r_source1, r_source2, flags);
+}
+
+t_axe_instruction * gen_div_instruction (t_program_infos *program
+      , int r_dest, int r_source1, int r_source2, int flags)
+{
+   return gen_ternary_instruction
+         (program, DIV, r_dest, r_source1, r_source2, flags);
+}
+
+t_axe_instruction * gen_shl_instruction (t_program_infos *program
+      , int r_dest, int r_source1, int r_source2, int flags)
+{
+   /* The SHL operational semantic is: source2 << source1. Because of this we
+   * need to put the value to shift in source2, and the shift-amount in source1
+   */
+   return gen_ternary_instruction
+         (program, SHL, r_dest, r_source2, r_source1, flags);
+}
+
+t_axe_instruction * gen_shr_instruction (t_program_infos *program
+      , int r_dest, int r_source1, int r_source2, int flags)
+{
+   /* The SHR operational semantic is: source2 >> source1. Because of this we
+   * need to put the value to shift in source2, and the shift-amount in source1
+   */
+   return gen_ternary_instruction
+         (program, SHR, r_dest, r_source2, r_source1, flags);
+}
+
+t_axe_instruction * gen_neg_instruction (t_program_infos *program
+      , int r_dest, int r_source, int flags)
+{
+   return gen_ternary_instruction
+         (program, SUB, r_dest, REG_0, r_source, flags);
+}
+
+t_axe_instruction * gen_spcl_instruction (t_program_infos *program
+      , int r_dest, int r_source1, int r_source2, int flags)
+{
+   return gen_ternary_instruction
+         (program, SPCL, r_dest, r_source1, r_source2, flags);
+}
+
+t_axe_instruction * gen_addi_instruction
+      (t_program_infos *program, int r_dest, int r_source1, int immediate)
+{
+   return gen_binary_instruction(program, ADDI
+         , r_dest, r_source1, immediate);
+}
+
+t_axe_instruction * gen_subi_instruction
+      (t_program_infos *program, int r_dest, int r_source1, int immediate)
+{
+   return gen_binary_instruction(program, SUBI
+         , r_dest, r_source1, immediate);
+}
+
+t_axe_instruction * gen_andli_instruction
+      (t_program_infos *program, int r_dest, int r_source1, int immediate)
+{
+   return gen_binary_instruction(program, ANDLI
+         , r_dest, r_source1, immediate);
+}
+
+t_axe_instruction * gen_orli_instruction
+      (t_program_infos *program, int r_dest, int r_source1, int immediate)
+{
+   return gen_binary_instruction(program, ORLI
+         , r_dest, r_source1, immediate);
+}
+
+t_axe_instruction * gen_eorli_instruction
+      (t_program_infos *program, int r_dest, int r_source1, int immediate)
+{
+   return gen_binary_instruction(program, EORLI
+         , r_dest, r_source1, immediate);
+}
+
+t_axe_instruction * gen_andbi_instruction
+      (t_program_infos *program, int r_dest, int r_source1, int immediate)
+{
+   return gen_binary_instruction(program, ANDBI
+         , r_dest, r_source1, immediate);
+}
+
+t_axe_instruction * gen_muli_instruction
+      (t_program_infos *program, int r_dest, int r_source1, int immediate)
+{
+   return gen_binary_instruction(program, MULI
+         , r_dest, r_source1, immediate);
+}
+
+t_axe_instruction * gen_orbi_instruction
+      (t_program_infos *program, int r_dest, int r_source1, int immediate)
+{
+   return gen_binary_instruction(program, ORBI
+         , r_dest, r_source1, immediate);
+}
+
+t_axe_instruction * gen_eorbi_instruction
+      (t_program_infos *program, int r_dest, int r_source1, int immediate)
+{
+   return gen_binary_instruction(program, EORBI
+         , r_dest, r_source1, immediate);
+}
+
+t_axe_instruction * gen_divi_instruction
+      (t_program_infos *program, int r_dest, int r_source1, int immediate)
+{
+   return gen_binary_instruction(program, DIVI
+         , r_dest, r_source1, immediate);
+}
+
+t_axe_instruction * gen_shli_instruction
+      (t_program_infos *program, int r_dest, int r_source1, int immediate)
+{
+   return gen_binary_instruction(program, SHLI
+         , r_dest, r_source1, immediate);
+}
+
+t_axe_instruction * gen_shri_instruction
+      (t_program_infos *program, int r_dest, int r_source1, int immediate)
+{
+   return gen_binary_instruction(program, SHRI
+         , r_dest, r_source1, immediate);
+}
+
+t_axe_instruction * gen_notl_instruction
+      (t_program_infos *program, int r_dest, int r_source1)
+{
+   return gen_binary_instruction(program, NOTL
+         , r_dest, r_source1, 0);
+}
+
+t_axe_instruction * gen_notb_instruction
+      (t_program_infos *program, int r_dest, int r_source1)
+{
+   return gen_binary_instruction(program, NOTB
+         , r_dest, r_source1, 0);
+}
+
+t_axe_instruction * gen_read_instruction
+               (t_program_infos *program, int r_dest)
+{
+   return gen_unary_instruction(program, AXE_READ, r_dest, NULL, 0);
+}
+
+t_axe_instruction * gen_write_instruction
+               (t_program_infos *program, int r_dest)
+{
+   return gen_unary_instruction(program, AXE_WRITE, r_dest, NULL, 0);
+}
+
+t_axe_instruction * gen_load_instruction
+      (t_program_infos *program, int r_dest, t_axe_label *label, int address)
+{
+   return gen_unary_instruction(program, LOAD, r_dest, label, address);
+}
+
+t_axe_instruction * gen_store_instruction
+      (t_program_infos *program, int r_dest, t_axe_label *label, int address)
+{
+   return gen_unary_instruction(program, STORE, r_dest, label, address);
+}
+
+t_axe_instruction * gen_mova_instruction
+      (t_program_infos *program, int r_dest, t_axe_label *label, int address)
+{
+   return gen_unary_instruction(program, MOVA, r_dest, label, address);
+}
+
+t_axe_instruction * gen_sge_instruction
+                  (t_program_infos *program, int r_dest)
+{
+   return gen_unary_instruction(program, SGE, r_dest, NULL, 0);
+}
+   
+t_axe_instruction * gen_seq_instruction
+                  (t_program_infos *program, int r_dest)
+{
+   return gen_unary_instruction(program, SEQ, r_dest, NULL, 0);
+}
+
+t_axe_instruction * gen_sgt_instruction
+                  (t_program_infos *program, int r_dest)
+{
+   return gen_unary_instruction(program, SGT, r_dest, NULL, 0);
+}
+
+t_axe_instruction * gen_sle_instruction
+                  (t_program_infos *program, int r_dest)
+{
+   return gen_unary_instruction(program, SLE, r_dest, NULL, 0);
+}
+
+t_axe_instruction * gen_slt_instruction
+                  (t_program_infos *program, int r_dest)
+{
+   return gen_unary_instruction(program, SLT, r_dest, NULL, 0);
+}
+
+t_axe_instruction * gen_sne_instruction
+                  (t_program_infos *program, int r_dest)
+{
+   return gen_unary_instruction(program, SNE, r_dest, NULL, 0);
+}
+
+t_axe_instruction * gen_halt_instruction
+      (t_program_infos *program)
+{
+   t_axe_instruction *instr;
+
+   /* test if program is initialized */
+   if (program == NULL)
+      notifyError(AXE_PROGRAM_NOT_INITIALIZED);
+      
+   /* create an instance of `t_axe_instruction' */
+   instr = alloc_instruction(HALT);
+
+   if (instr == NULL)
+      notifyError(AXE_OUT_OF_MEMORY);
+
+   /* add the newly created instruction to the current program */
+   addInstruction(program, instr);
+
+   /* return the load instruction */
+   return instr;
+}
+
+t_axe_instruction * gen_nop_instruction(t_program_infos *program)
+{
+   t_axe_instruction *instr;
+
+   /* test if program is initialized */
+   if (program == NULL)
+      notifyError(AXE_PROGRAM_NOT_INITIALIZED);
+   
+   /* create an instance of `t_axe_instruction' */
+   instr = alloc_instruction(NOP);
+
+   if (instr == NULL)
+      notifyError(AXE_OUT_OF_MEMORY);
+
+   /* add the newly created instruction to the current program */
+   addInstruction(program, instr);
+
+   /* return the load instruction */
+   return instr;
+}
+
+t_axe_instruction * gen_unary_instruction (t_program_infos *program
+         , int opcode, int r_dest, t_axe_label *label, int addr)
+{
+   t_axe_instruction *instr;
+   t_axe_register *reg;
+   t_axe_address *address;
+   int addressType;
+
+   /* test if program is initialized */
+   if (program == NULL)
+      notifyError(AXE_PROGRAM_NOT_INITIALIZED);
+
+   if (r_dest == REG_INVALID)
+      notifyError(AXE_INVALID_REGISTER_INFO);
+   
+   /* test if value is correctly initialized */
+   if (label != NULL)
+   {
+      if (label->labelID == LABEL_UNSPECIFIED)
+      {
+         notifyError(AXE_INVALID_LABEL);
+      }
+
+      /* address type is a label type */
+      addressType = LABEL_TYPE;
+   }
+   else
+   {
+      if (addr < 0)
+         notifyError(AXE_INVALID_ADDRESS);
+
+      /* address type is a label type */
+      addressType = ADDRESS_TYPE;
+
+   }
+
+   /* test if the opcode is a valid opcode */
+   if (opcode == INVALID_OPCODE)
+      notifyError(AXE_INVALID_OPCODE);
+
+   /* create an instance of `t_axe_instruction' */
+   instr = alloc_instruction(opcode);
+
+   if (instr == NULL)
+      notifyError(AXE_OUT_OF_MEMORY);
+
+   /* initialize a register info */
+   reg = alloc_register(r_dest, 0);
+
+   if (reg == NULL)
+   {
+      free_Instruction(instr);
+      notifyError(AXE_OUT_OF_MEMORY);
+   }
+   
+   /* update the reg_1 info */
+   instr->reg_1 = reg;
+
+   /* initialize an address info */
+   address = alloc_address(addressType, addr, label);
+   
+   if (address == NULL)
+   {
+      free_Instruction(instr);
+      notifyError(AXE_OUT_OF_MEMORY);
+   }
+
+   /* update the instruction address info */
+   instr->address = address;
+
+   /* add the newly created instruction to the current program */
+   addInstruction(program, instr);
+
+   /* return the load instruction */
+   return instr;
+}
+
+t_axe_instruction * gen_binary_instruction (t_program_infos *program
+      , int opcode, int r_dest, int r_source1, int immediate)
+{
+   t_axe_instruction *instr;
+   t_axe_register *reg_dest;
+   t_axe_register *reg_source1;
+
+   /* test if program is initialized */
+   if (program == NULL)
+      notifyError(AXE_PROGRAM_NOT_INITIALIZED);
+
+   /* test if value is correctly initialized */
+   if (  (r_dest == REG_INVALID)
+         || (r_source1 == REG_INVALID) )
+   {
+      notifyError(AXE_INVALID_REGISTER_INFO);
+   }
+
+   /* create an instance of `t_axe_instruction' */
+   instr = alloc_instruction(opcode);
+
+   if (instr == NULL)
+      notifyError(AXE_OUT_OF_MEMORY);
+
+   /* initialize a register info */
+   reg_dest = alloc_register(r_dest, 0);
+   if (reg_dest == NULL)
+   {
+      free_Instruction(instr);
+      notifyError(AXE_OUT_OF_MEMORY);
+   }
+
+   /* update the reg_1 info */
+   instr->reg_1 = reg_dest;
+
+   reg_source1 = alloc_register(r_source1, 0);
+   if (reg_source1 == NULL)
+   {
+      free_Instruction(instr);
+      notifyError(AXE_OUT_OF_MEMORY);
+      return NULL;
+   }
+
+   /* update the reg_1 info */
+   instr->reg_2 = reg_source1;
+
+   /* assign an immediate value */
+   instr->immediate = immediate;
+
+   /* add the newly created instruction to the current program */
+   addInstruction(program, instr);
+
+   /* return the load instruction */
+   return instr;
+}
+
+t_axe_instruction * gen_ternary_instruction (t_program_infos *program
+      , int opcode, int r_dest, int r_source1, int r_source2, int flags)
+{
+   t_axe_instruction *instr;
+   t_axe_register *reg_dest;
+   t_axe_register *reg_source1;
+   t_axe_register *reg_source2;
+   
+   /* test if program is initialized */
+   if (program == NULL)
+      notifyError(AXE_PROGRAM_NOT_INITIALIZED);
+
+   /* test if value is correctly initialized */
+   if (  (r_dest == REG_INVALID)
+         || (r_source1 == REG_INVALID)
+         || (r_source2 == REG_INVALID))
+   {
+      notifyError(AXE_INVALID_REGISTER_INFO);
+   }
+
+   /* create an instance of `t_axe_instruction' */
+   instr = alloc_instruction(opcode);
+
+   if (instr == NULL)
+      notifyError(AXE_OUT_OF_MEMORY);
+
+   /* initialize a register info */
+   reg_dest = alloc_register(r_dest, ((flags & CG_INDIRECT_DEST)? 1 : 0) );
+   if (reg_dest == NULL)
+   {
+      free_Instruction(instr);
+      notifyError(AXE_OUT_OF_MEMORY);
+   }
+
+   /* update the reg_1 info */
+   instr->reg_1 = reg_dest;
+
+   reg_source1 = alloc_register(r_source1, 0);
+   if (reg_source1 == NULL)
+   {
+      free_Instruction(instr);
+      notifyError(AXE_OUT_OF_MEMORY);
+   }
+
+   /* update the reg_2 info */
+   instr->reg_2 = reg_source1;
+
+   reg_source2 = alloc_register(r_source2, ((flags & CG_INDIRECT_SOURCE)? 1 : 0));
+   if (reg_source1 == NULL)
+   {
+      free_Instruction(instr);
+      notifyError(AXE_OUT_OF_MEMORY);
+   }
+
+   /* update the reg_3 info */
+   instr->reg_3 = reg_source2;
+
+   /* add the newly created instruction to the current program */
+   addInstruction(program, instr);
+
+   /* return the load instruction */
+   return instr;
+}
+
+t_axe_instruction * gen_jump_instruction (t_program_infos *program
+      , int opcode, t_axe_label *label, int addr)
+{
+   t_axe_instruction *instr;
+   t_axe_address * address;
+   int addressType;
+
+   /* test if program is initialized */
+   if (program == NULL)
+      notifyError(AXE_PROGRAM_NOT_INITIALIZED);
+
+   /* test if value is correctly initialized */
+   if (label != NULL)
+   {
+      if (label->labelID == LABEL_UNSPECIFIED)
+         notifyError(AXE_INVALID_LABEL);
+
+      addressType = LABEL_TYPE;
+   }
+   else
+   {
+      if (addr < 0)
+         notifyError(AXE_INVALID_ADDRESS);
+
+      addressType = ADDRESS_TYPE;
+   }
+
+   /* test if the opcode is a valid opcode */
+   if (opcode == INVALID_OPCODE)
+      notifyError(AXE_INVALID_OPCODE);
+
+   /* create an instance of `t_axe_instruction' */
+   instr = alloc_instruction(opcode);
+
+   if (instr == NULL)
+      notifyError(AXE_OUT_OF_MEMORY);
+
+   /* initialize an address info */
+   address = alloc_address(addressType, addr, label);
+   
+   if (address == NULL)
+   {
+      free_Instruction(instr);
+      notifyError(AXE_OUT_OF_MEMORY);
+   }
+
+   /* update the instruction address info */
+   instr->address = address;
+
+   /* add the newly created instruction to the current program */
+   addInstruction(program, instr);
+
+   /* return the load instruction */
+   return instr;
+}

+ 499 - 0
acse/axe_gencode.h

@@ -0,0 +1,499 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * axe_gencode.h
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#ifndef _AXE_GENCODE_H
+#define _AXE_GENCODE_H
+
+#include "axe_engine.h"
+#include "axe_struct.h"
+
+/*----------------------------------------------------
+ *                   NOP & HALT
+ *---------------------------------------------------*/
+
+/* By calling this function, a new NOP instruction will be added
+ * to `program'. A NOP instruction doesn't make use of
+ * any kind of parameter */
+extern t_axe_instruction * gen_nop_instruction
+      (t_program_infos *program);
+
+/* By calling this function, a new HALT instruction will be added
+ * to `program'. An HALT instruction doesn't require
+ * any kind of parameter */
+extern t_axe_instruction * gen_halt_instruction
+      (t_program_infos *program);
+
+/*----------------------------------------------------
+ *                   UNARY OPERATIONS
+ *---------------------------------------------------*/
+ 
+/* A LOAD instruction requires the following parameters:
+ * 1.  A destination register (where will be loaded the requested value)
+ * 2.  A label information (can be a NULL pointer. If so, the addess
+ *     value will be taken into consideration)
+ * 3.  A direct address (if label is different from NULL) */
+extern t_axe_instruction * gen_load_instruction
+      (t_program_infos *program, int r_dest, t_axe_label *label, int address);
+
+/* A READ instruction requires only one parameter:
+ * A destination register (where will be loaded the value
+ * read from standard input). */
+extern t_axe_instruction * gen_read_instruction
+               (t_program_infos *program, int r_dest);
+
+/* A WRITE instruction requires only one parameter:
+ * A destination register (where is located the value
+ * that will be written to the standard output). */
+extern t_axe_instruction * gen_write_instruction
+               (t_program_infos *program, int r_dest);
+
+/* A STORE instruction copies a value from a register to a
+ * specific memory location. The memory location can be
+ * either a label identifier or a address reference.
+ * In order to create a STORE instruction the caller must
+ * privide a valid register location (`r_dest') and an
+ * instance of `t_axe_label' or a numeric address */
+extern t_axe_instruction * gen_store_instruction
+      (t_program_infos *program, int r_dest, t_axe_label *label, int address);
+
+/* A MOVA instruction copies an address value into a register.
+ * An address can be either an instance of `t_axe_label'
+ * or a number (numeric address) */
+extern t_axe_instruction * gen_mova_instruction
+      (t_program_infos *program, int r_dest, t_axe_label *label, int address);
+
+/* A SGE instruction tests the content of the STATUS REGISTER. To be more
+ * specific, an SGE instruction set to #1 the content of the register
+ * `r_dest' if the condition (N.V + ~N.~V) is TRUE; otherwise the content
+ * of `r_dest' is set to 0.
+ * (I.e.: r_dest will be set to #1 only if the value computed by
+ * the last numeric operation returned a value
+ * greater or equal to zero). */
+extern t_axe_instruction * gen_sge_instruction
+                  (t_program_infos *program, int r_dest);
+
+/* A SEQ instruction tests the content of the STATUS REGISTER. In particular,
+ * an SEQ instruction set to #1 the content of the register
+ * `r_dest' if the condition Z is TRUE; otherwise the content of `r_dest' is set
+ * to 0. (I.e.: r_dest will be set to #1 only if the value computed by
+ * the last numeric operation returned a value equal to zero). */
+extern t_axe_instruction * gen_seq_instruction
+                  (t_program_infos *program, int r_dest);
+
+/* A SGT instruction tests the content of the STATUS REGISTER. In particular,
+ * an SGT instruction set to #1 the content of the register
+ * `r_dest' if the condition (N.V.~Z + ~N.~V.~Z) is TRUE;
+ * otherwise the content of `r_dest' is set to 0. (I.e.: r_dest will be
+ * set to #1 only if the value computed by the last numeric operation
+ * returned a value greater than zero). */
+extern t_axe_instruction * gen_sgt_instruction
+                  (t_program_infos *program, int r_dest);
+
+/* A SLE instruction tests the content of the STATUS REGISTER. In particular,
+ * an SLE instruction set to #1 the content of the register
+ * `r_dest' if the condition (Z + N.~V + ~N.V) is TRUE;
+ * otherwise the content of `r_dest' is set to 0. (I.e.: r_dest will be
+ * set to #1 only if the value computed by the last numeric operation
+ * returned a value less than zero). */
+extern t_axe_instruction * gen_sle_instruction
+                  (t_program_infos *program, int r_dest);
+
+/* A SLT instruction tests the content of the STATUS REGISTER. In particular,
+ * an SLT instruction set to #1 the content of the register
+ * `r_dest' if the condition (N.~V + ~N.V) is TRUE;
+ * otherwise the content of `r_dest' is set to 0. (I.e.: r_dest will be
+ * set to #1 only if the value computed by the last numeric operation
+ * returned a value less than or equal to zero). */
+extern t_axe_instruction * gen_slt_instruction
+                  (t_program_infos *program, int r_dest);
+
+/* A SNE instruction tests the content of the STATUS REGISTER. In particular,
+ * an SNE instruction set to #1 the content of the register
+ * `r_dest' if the condition ~N is TRUE;
+ * otherwise the content of `r_dest' is set to 0. (I.e.: r_dest will be
+ * set to #1 only if the value computed by the last numeric operation
+ * returned a value different from zero). */
+extern t_axe_instruction * gen_sne_instruction
+                  (t_program_infos *program, int r_dest);
+
+/*----------------------------------------------------
+ *                   BINARY OPERATIONS
+ *---------------------------------------------------*/
+
+/* Used in order to create and assign to the current `program'
+ * an ADDI instruction. The semantic of an ADDI instruction
+ * is the following: ADDI r_dest, r_source1, immediate. `RDest' is a register
+ * location identifier: the result of the ADDI instruction will be
+ * stored in that register. Using an RTL representation we can say
+ * that an ADDI instruction of the form: ADDI R1 R2 #IMM can be represented
+ * in the following manner: R1 <-- R2 + IMM.
+ * `Rsource1' and `#IMM' are the two operands of the binary numeric
+ * operation. `r_dest' is a register location, `immediate' is an immediate
+ * value. The content of `r_source1' is added to the value of `immediate'
+ * and the result is then stored into the register `RDest'. */
+extern t_axe_instruction * gen_addi_instruction
+      (t_program_infos *program, int r_dest, int r_source1, int immediate);
+
+/* Used in order to create and assign to the current `program'
+ * a SUBI instruction. The semantic of an SUBI instruction
+ * is the following: SUBI r_dest, r_source1, immediate. `RDest' is a register
+ * location identifier: the result of the SUBI instruction will be
+ * stored in that register. Using an RTL representation we can say
+ * that a SUBI instruction of the form: SUBI R1 R2 #IMM can be represented
+ * in the following manner: R1 <-- R2 - IMM.
+ * `Rsource1' and `#IMM' are the two operands of the binary numeric
+ * operation. `r_dest' is a register location, `immediate' is an immediate
+ * value. The content of `r_source1' is subtracted to the value of `immediate'
+ * and the result is then stored into the register `RDest'. */
+extern t_axe_instruction * gen_subi_instruction
+      (t_program_infos *program, int r_dest, int r_source1, int immediate);
+
+/* Used in order to create and assign to the current `program'
+ * a ANDLI instruction.An RTL representation for an ANDLI instruction
+ * of the form: ANDLI R1 R2 #IMM can be represented
+ * as follows: R1 <-- R2 && IMM.
+ * `r_source1' and `immediate' are the two operands of the binary numeric
+ * comparison. `r_dest' is a register location, `immediate' is an immediate
+ * value. */
+extern t_axe_instruction * gen_andli_instruction
+      (t_program_infos *program, int r_dest, int r_source1, int immediate);
+
+/* Used in order to create and assign to the current `program'
+ * a ORLI instruction.An RTL representation for an ORLI instruction
+ * of the form: ORLI R1 R2 #IMM can be represented
+ * as follows: R1 <-- R2 || IMM.
+ * `r_source1' and `immediate' are the two operands of the binary numeric
+ * comparison. `r_dest' is a register location, `immediate' is an immediate
+ * value. */
+extern t_axe_instruction * gen_orli_instruction
+      (t_program_infos *program, int r_dest, int r_source1, int immediate);
+
+/* Used in order to create and assign to the current `program'
+ * a EORLI instruction.An RTL representation for an EORLI instruction
+ * of the form: EORLI R1 R2 #IMM can be represented as follows:
+ * R1 <-- R2 XOR IMM (Where XOR is the operator: logical exclusive OR).
+ * `r_source1' and `immediate' are the two operands of the binary numeric
+ * comparison. `r_dest' is a register location, `immediate' is an immediate
+ * value. */
+extern t_axe_instruction * gen_eorli_instruction
+      (t_program_infos *program, int r_dest, int r_source1, int immediate);
+
+/* Used in order to create and assign to the current `program'
+ * a ANDBI instruction. An RTL representation for an ANDBI instruction
+ * of the form: ANDBI R1 R2 #IMM can be represented
+ * as follows: R1 <-- R2 & IMM (bitwise AND).
+ * `r_source1' and `immediate' are the two operands of the binary numeric
+ * comparison. `r_dest' is a register location, `immediate' is an immediate
+ * value. */
+extern t_axe_instruction * gen_andbi_instruction
+      (t_program_infos *program, int r_dest, int r_source1, int immediate);
+
+/* Used in order to create and assign to the current `program'
+ * a MULI instruction.An RTL representation for an MULI instruction
+ * of the form: MULI R1 R2 #IMM can be represented as follows:
+ * R1 <-- R2 * IMM.
+ * `r_source1' and `immediate' are the two operands of the binary numeric
+ * comparison. `r_dest' is a register location, `immediate' is an immediate
+ * value. */
+extern t_axe_instruction * gen_muli_instruction
+      (t_program_infos *program, int r_dest, int r_source1, int immediate);
+
+/* Used in order to create and assign to the current `program'
+ * a ORBI instruction.An RTL representation for an ORBI instruction
+ * of the form: ORBI R1 R2 #IMM can be represented as follows:
+ * R1 <-- R2 | IMM.
+ * `r_source1' and `immediate' are the two operands of the binary numeric
+ * comparison. `r_dest' is a register location, `immediate' is an immediate
+ * value. */
+extern t_axe_instruction * gen_orbi_instruction
+      (t_program_infos *program, int r_dest, int r_source1, int immediate);
+
+/* Used in order to create and assign to the current `program'
+ * a EORBI instruction.An RTL representation for an EORBI instruction
+ * of the form: EORBI R1 R2 #IMM can be represented as follows:
+ * R1 <-- R2 ^ IMM.
+ * `r_source1' and `immediate' are the two operands of the binary numeric
+ * comparison. `r_dest' is a register location, `immediate' is an immediate
+ * value. */
+extern t_axe_instruction * gen_eorbi_instruction
+      (t_program_infos *program, int r_dest, int r_source1, int immediate);
+
+/* Used in order to create and assign to the current `program'
+ * a DIVI instruction.An RTL representation for an DIVI instruction
+ * of the form: DIVI R1 R2 #IMM can be represented as follows:
+ * R1 <-- R2 / IMM.
+ * `r_source1' and `immediate' are the two operands of the binary numeric
+ * comparison. `r_dest' is a register location, `immediate' is an immediate
+ * value. */
+extern t_axe_instruction * gen_divi_instruction
+      (t_program_infos *program, int r_dest, int r_source1, int immediate);
+
+/* Used in order to create and assign to the current `program'
+ * a SHLI instruction. An RTL representation for an SHLI instruction
+ * of the form: SHLI R1 R2 #IMM can be represented as follows:
+ * R1 <-- R2 / IMM.
+ * `r_source1' and `immediate' are the two operands of the binary numeric
+ * comparison. `r_dest' is a register location, `immediate' is an immediate
+ * value. */
+extern t_axe_instruction * gen_shli_instruction
+      (t_program_infos *program, int r_dest, int r_source1, int immediate);
+
+/* Used in order to create and assign to the current `program'
+ * a SHRI instruction. An RTL representation for an SHRI instruction
+ * of the form: SHRI R1 R2 #IMM can be represented as follows:
+ * R1 <-- R2 / IMM.
+ * `r_source1' and `immediate' are the two operands of the binary numeric
+ * comparison. `r_dest' is a register location, `immediate' is an immediate
+ * value. */
+extern t_axe_instruction * gen_shri_instruction
+      (t_program_infos *program, int r_dest, int r_source1, int immediate);
+
+/* Used in order to create and assign to the current `program'
+ * a NOTL instruction. An RTL representation for an NOTL instruction
+ * of the form: NOTL R1 R2 can be represented as follows:
+ * R1 <-- !R2. */
+extern t_axe_instruction * gen_notl_instruction
+      (t_program_infos *program, int r_dest, int r_source1);
+
+/* Used in order to create and assign to the current `program'
+ * a NOTB instruction. An RTL representation for an NOTB instruction
+ * of the form: NOTB R1 R2 can be represented as follows:
+ * R1 <-- ~R2. */
+extern t_axe_instruction * gen_notb_instruction
+      (t_program_infos *program, int r_dest, int r_source1);
+/*----------------------------------------------------
+ *                   TERNARY OPERATIONS
+ *---------------------------------------------------*/
+
+/* Used in order to create and assign to the current `program'
+ * a ADD instruction.An RTL representation for an ADD instruction
+ * of the form: ADD R1 R2 R3 can be represented
+ * as follows: R1 <-- R2 + R3.
+ * `r_source1' and `r_source2' are the two operands of the binary numeric
+ * comparison. `r_dest' is a register location. `r_dest' and `r_source2'
+ * are register locations that can be directly or indirectly addressed. */
+extern t_axe_instruction * gen_add_instruction (t_program_infos *program
+      , int r_dest, int r_source1, int r_source2, int flags);
+
+/* Used in order to create and assign to the current `program'
+ * a SUB instruction.An RTL representation for an SUB instruction
+ * of the form: SUB R1 R2 R3 can be represented
+ * as follows: R1 <-- R2 - R3.
+ * `r_source1' and `r_source2' are the two operands of the binary numeric
+ * comparison. `r_dest' is a register location. `r_dest' and `r_source2'
+ * are register locations that can be directly or indirectly addressed. */
+extern t_axe_instruction * gen_sub_instruction (t_program_infos *program
+      , int r_dest, int r_source1, int r_source2, int flags);
+
+/* Used in order to create and assign to the current `program'
+ * a ANDL instruction.An RTL representation for an ANDL instruction
+ * of the form: ANDL R1 R2 R3 can be represented
+ * as follows: R1 <-- R2 && R3.
+ * `r_source1' and `r_source2' are the two operands of the binary numeric
+ * comparison. `r_dest' is a register location. `r_dest' and `r_source2'
+ * are register locations that can be directly or indirectly addressed. */
+extern t_axe_instruction * gen_andl_instruction (t_program_infos *program
+      , int r_dest, int r_source1, int r_source2, int flags);
+
+/* Used in order to create and assign to the current `program'
+ * a ORL instruction.An RTL representation for an ORL instruction
+ * of the form: ORL R1 R2 R3 can be represented
+ * as follows: R1 <-- R2 || R3.
+ * `r_source1' and `r_source2' are the two operands of the binary numeric
+ * comparison. `r_dest' is a register location. `r_dest' and `r_source2'
+ * are register locations that can be directly or indirectly addressed. */
+extern t_axe_instruction * gen_orl_instruction (t_program_infos *program
+      , int r_dest, int r_source1, int r_source2, int flags);
+
+/* Used in order to create and assign to the current `program'
+ * a EORL instruction.An RTL representation for an EORL instruction
+ * of the form: EORL R1 R2 R3 can be represented
+ * as follows: R1 <-- R2 XORL R3.
+ * `r_source1' and `r_source2' are the two operands of the binary numeric
+ * comparison. `r_dest' is a register location. `r_dest' and `r_source2'
+ * are register locations that can be directly or indirectly addressed. */
+extern t_axe_instruction * gen_eorl_instruction (t_program_infos *program
+      , int r_dest, int r_source1, int r_source2, int flags);
+
+/* Used in order to create and assign to the current `program'
+ * a ANDB instruction.An RTL representation for an ANDB instruction
+ * of the form: ANDB R1 R2 R3 can be represented
+ * as follows: R1 <-- R2 & R3.
+ * `r_source1' and `r_source2' are the two operands of the binary numeric
+ * comparison. `r_dest' is a register location. `r_dest' and `r_source2'
+ * are register locations that can be directly or indirectly addressed. */
+extern t_axe_instruction * gen_andb_instruction (t_program_infos *program
+      , int r_dest, int r_source1, int r_source2, int flags);
+
+/* Used in order to create and assign to the current `program'
+ * a ORB instruction.An RTL representation for an ORB instruction
+ * of the form: ORB R1 R2 R3 can be represented
+ * as follows: R1 <-- R2 | R3.
+ * `r_source1' and `r_source2' are the two operands of the binary numeric
+ * comparison. `r_dest' is a register location. `r_dest' and `r_source2'
+ * are register locations that can be directly or indirectly addressed. */
+extern t_axe_instruction * gen_orb_instruction (t_program_infos *program
+      , int r_dest, int r_source1, int r_source2, int flags);
+
+/* Used in order to create and assign to the current `program'
+ * a EORB instruction.An RTL representation for an EORB instruction
+ * of the form: EORB R1 R2 R3 can be represented
+ * as follows: R1 <-- R2 XORB R3.
+ * `r_source1' and `r_source2' are the two operands of the binary numeric
+ * comparison. `r_dest' is a register location. `r_dest' and `r_source2'
+ * are register locations that can be directly or indirectly addressed. */
+extern t_axe_instruction * gen_eorb_instruction (t_program_infos *program
+      , int r_dest, int r_source1, int r_source2, int flags);
+
+/* Used in order to create and assign to the current `program'
+ * a MUL instruction. An RTL representation for an MUL instruction
+ * of the form: MUL R1 R2 R3 can be represented
+ * as follows: R1 <-- R2 * R3.
+ * `r_source1' and `r_source2' are the two operands of the binary numeric
+ * comparison. `r_dest' is a register location. `r_dest' and `r_source2'
+ * are register locations that can be directly or indirectly addressed. */
+extern t_axe_instruction * gen_mul_instruction (t_program_infos *program
+      , int r_dest, int r_source1, int r_source2, int flags);
+
+/* Used in order to create and assign to the current `program'
+ * a DIV instruction. An RTL representation for an DIV instruction
+ * of the form: DIV R1 R2 R3 can be represented
+ * as follows: R1 <-- R2 / R3.
+ * `r_source1' and `r_source2' are the two operands of the binary numeric
+ * comparison. `r_dest' is a register location. `r_dest' and `r_source2'
+ * are register locations that can be directly or indirectly addressed. */
+extern t_axe_instruction * gen_div_instruction (t_program_infos *program
+      , int r_dest, int r_source1, int r_source2, int flags);
+
+/* Used in order to create and assign to the current `program'
+ * a SHL instruction. An RTL representation for an SHL instruction
+ * of the form: SHL R1 R2 R3 can be represented
+ * as follows: R1 <-- R2 shifted to left by R3.
+ * `r_source1' and `r_source2' are the two operands of the binary numeric
+ * comparison. `r_dest' is a register location. `r_dest' and `r_source2'
+ * are register locations that can be directly or indirectly addressed. */
+extern t_axe_instruction * gen_shl_instruction (t_program_infos *program
+      , int r_dest, int r_source1, int r_source2, int flags);
+
+/* Used in order to create and assign to the current `program'
+ * a SHR instruction. An RTL representation for an SHR instruction
+ * of the form: SHR R1 R2 R3 can be represented
+ * as follows: R1 <-- R2 shifted to right by R3.
+ * `r_source1' and `r_source2' are the two operands of the binary numeric
+ * comparison. `r_dest' is a register location. `r_dest' and `r_source2'
+ * are register locations that can be directly or indirectly addressed. */
+extern t_axe_instruction * gen_shr_instruction (t_program_infos *program
+      , int r_dest, int r_source1, int r_source2, int flags);
+
+/* Used in order to create and assign to the current `program'
+ * a NEG instruction. An RTL representation for an NEG instruction
+ * of the form: NEG R1 R2 can be represented
+ * as follows: R1 <-- (-)R2.
+ * `r_source' is the only operand for this instruction.
+ * `r_dest' is a register location. `r_dest' and `r_source'
+ * are register locations that can be directly or indirectly addressed. */
+extern t_axe_instruction * gen_neg_instruction (t_program_infos *program
+      , int r_dest, int r_source, int flags);
+
+/* Actually this instruction is not used.
+ * This will be used for future implementations. */
+extern t_axe_instruction * gen_spcl_instruction (t_program_infos *program
+      , int r_dest, int r_source1, int r_source2, int flags);
+/*----------------------------------------------------
+ *                   JUMP INSTRUCTIONS
+ *---------------------------------------------------*/
+
+/* create a branch true instruction. By executing this instruction
+ * the control is always passed to either the instruction with the label `label'
+ * associated with, or (if `label' is a NULL pointer) to the explicit `address' */
+extern t_axe_instruction * gen_bt_instruction
+      (t_program_infos *program, t_axe_label *label, int addr);
+
+/* create a branch true instruction. By executing this instruction
+ * the control is always passed to the next instruction in the program
+ * (i.e.: the instruction pointed by PC + 1). */
+extern t_axe_instruction * gen_bf_instruction
+      (t_program_infos *program, t_axe_label *label, int addr);
+
+/* create a "branch on higher than" instruction. */
+extern t_axe_instruction * gen_bhi_instruction
+      (t_program_infos *program, t_axe_label *label, int addr);
+
+/* create a "branch on less than" instruction. According to the value
+ * of the status register, the branch will be taken if the expression
+ * (~C.~Z) is TRUE. */
+extern t_axe_instruction * gen_bls_instruction
+      (t_program_infos *program, t_axe_label *label, int addr);
+
+/* create a "branch on carry clear" instruction. If the bit `C' of the
+ * status register is not set, then the branch is taken. */
+extern t_axe_instruction * gen_bcc_instruction
+      (t_program_infos *program, t_axe_label *label, int addr);
+
+/* create a "branch on carry clear" instruction. If the bit `C' of the
+ * status register is set, then the branch is taken. */
+extern t_axe_instruction * gen_bcs_instruction
+      (t_program_infos *program, t_axe_label *label, int addr);
+
+/* create a "branch on not equal" instruction. If the bit `Z' of the
+ * status register is not set, then the branch is taken. */
+extern t_axe_instruction * gen_bne_instruction
+      (t_program_infos *program, t_axe_label *label, int addr);
+
+/* create a "branch on equal" instruction. If the bit `Z' of the
+ * status register is set, then the branch is taken. */
+extern t_axe_instruction * gen_beq_instruction
+      (t_program_infos *program, t_axe_label *label, int addr);
+
+/* create a "branch on overflow clear" instruction. If the bit `V' of the
+ * status register is not set, then the branch is taken. */
+extern t_axe_instruction * gen_bvc_instruction
+      (t_program_infos *program, t_axe_label *label, int addr);
+
+/* create a "branch on overflow set" instruction. If the bit `V' of the
+ * status register is set, then the branch is taken. */
+extern t_axe_instruction * gen_bvs_instruction
+      (t_program_infos *program, t_axe_label *label, int addr);
+
+/* create a "branch on plus (i.e. positive)" instruction. If the bit `N' of the
+ * status register is not set, then the branch is taken. */
+extern t_axe_instruction * gen_bpl_instruction
+      (t_program_infos *program, t_axe_label *label, int addr);
+
+/* create a "branch on minus (i.e. negative)" instruction. If the bit `N' of the
+ * status register is set, then the branch is taken. */
+extern t_axe_instruction * gen_bmi_instruction
+      (t_program_infos *program, t_axe_label *label, int addr);
+
+/* create a "branch on greater or equal" instruction. According to the value
+ * of the status register, the branch will be taken if the expression
+ * (N.V + ~N.~V) is TRUE. */
+extern t_axe_instruction * gen_bge_instruction
+      (t_program_infos *program, t_axe_label *label, int addr);
+
+/* create a "branch on less than" instruction. According to the value
+ * of the status register, the branch will be taken if the expression
+ * (N.~V + ~N.V) is TRUE. */
+extern t_axe_instruction * gen_blt_instruction
+      (t_program_infos *program, t_axe_label *label, int addr);
+
+/* create a "branch on less than" instruction. According to the value
+ * of the status register, the branch will be taken if the expression
+ * (N.V.~Z + ~N.~V.~Z) is TRUE. */
+extern t_axe_instruction * gen_bgt_instruction
+      (t_program_infos *program, t_axe_label *label, int addr);
+
+/* create a "branch on less than or equal" instruction. According to the value
+ * of the status register, the branch will be taken if the expression
+ * (Z + N.~V + ~N.V) is TRUE. */
+extern t_axe_instruction * gen_ble_instruction
+      (t_program_infos *program, t_axe_label *label, int addr);
+
+
+#endif

+ 126 - 0
acse/axe_io_manager.c

@@ -0,0 +1,126 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * axe_io_manager.c
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#include <stdlib.h>
+#include "axe_io_manager.h"
+
+static t_io_infos * allocOutputInfos();
+
+
+t_io_infos * initializeOutputInfos(int argc, char **argv)
+{
+   t_io_infos *result;
+
+   /* create a new instance of `t_io_infos' */
+   result = allocOutputInfos();
+   if (result == NULL)
+      return NULL;
+   
+   argc--;
+   argv++;
+
+   if (argc > 0)
+   {
+      result->input_file = fopen(argv[0], "r");
+      if (result->input_file == NULL)
+      {
+         fprintf( stderr, "File not found : %s.\n", argv[0]);
+         exit(-1);
+      }
+#ifndef NDEBUG
+      fprintf(stdout, "Input file: %s. \n", argv[0]);
+#endif
+   }
+#ifndef NDEBUG
+   else
+      fprintf(stdout, "Input file: %s. \n", "standard input");
+#endif
+
+   /* update the value of yyin */
+   yyin = result->input_file;
+
+   if (argc == 2)
+      result->output_file_name = argv[1];
+   else
+      result->output_file_name = "output.asm";
+
+#ifndef NDEBUG
+   fprintf(stdout, "Output will be written on file : "
+         "\"%s\". \n", result->output_file_name);
+   fprintf(stdout, "The Symbol Table will be written on file : "
+         "\"%s\". \n", "sy_table.out");
+   fprintf(stdout, "Intermediate code will be written on file : "
+         "\"%s\". \n", "output.cfg");
+   fprintf(stdout, "control/dataflow informations will "
+                   "be written on file : \"%s\". \n", "dataflow.cfg");
+   fprintf(stdout, "Output of the register allocator "
+                   "will be written on file  : \"%s\". \n\n", "regalloc.out");
+
+   result->reg_alloc_output = fopen("regalloc.out", "w");
+   if (result->reg_alloc_output == NULL)
+      fprintf( stderr, "WARNING : Unable to create file: %s.\n", "regalloc.out");
+   result->cfg_1 = fopen("output.cfg", "w");
+   result->cfg_2 = fopen("dataflow.cfg", "w");
+   result->syTable_output = fopen("sy_table.out", "w");
+   if (result->cfg_1 == NULL)
+      fprintf( stderr, "WARNING : Unable to create file: %s.\n", "output.cfg");
+   if (result->cfg_2 == NULL)
+      fprintf( stderr, "WARNING : Unable to create file: %s.\n", "dataflow.cfg");
+   if (result->syTable_output == NULL)
+      fprintf( stderr, "WARNING : Unable to create file: %s.\n", "sy_table.out");
+#endif
+
+   return result;
+}
+
+t_io_infos * allocOutputInfos()
+{
+   t_io_infos *result;
+
+   /* Allocate memory for an instance of `t_output_infos' */
+   result = (t_io_infos *)
+         _AXE_ALLOC_FUNCTION(sizeof(t_io_infos));
+
+   /* test if _AXE_ALLOC_FUNCTION returned a null pointer */
+   if (result == NULL)
+      return NULL;
+      
+   /* initialize the instance internal data */
+   result->output_file_name = NULL;
+   result->input_file = stdin;
+#ifndef NDEBUG
+   result->cfg_1 = stdout;
+   result->cfg_2 = stdout;
+   result->reg_alloc_output = stdout;
+   result->syTable_output = stdout;
+#endif
+
+   /* return the result */
+   return result;
+}
+
+void finalizeOutputInfos(t_io_infos *infos)
+{
+   if (infos == NULL)
+      return;
+   if (infos->input_file != NULL)
+      fclose(infos->input_file);
+#ifndef NDEBUG
+   if (infos->cfg_1 != NULL)
+      fclose(infos->cfg_1);
+   if (infos->cfg_2 != NULL)
+      fclose(infos->cfg_2);
+   if (infos->reg_alloc_output != NULL)
+      fclose(infos->reg_alloc_output);
+   if (infos->syTable_output != NULL)
+      fclose(infos->syTable_output);
+#endif
+
+   _AXE_FREE_FUNCTION(infos);
+}

+ 35 - 0
acse/axe_io_manager.h

@@ -0,0 +1,35 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * axe_io_manager.h
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#ifndef _AXE_IO_MANAGER_H
+#define _AXE_IO_MANAGER_H
+
+#include <stdio.h>
+#include "axe_struct.h"
+
+extern FILE *yyin;
+
+typedef struct t_io_infos
+{
+   char *output_file_name;
+   FILE *input_file;
+#ifndef NDEBUG
+   FILE *cfg_1;
+   FILE *cfg_2;
+   FILE *reg_alloc_output;
+   FILE *syTable_output;
+#endif
+}t_io_infos;
+
+
+extern void finalizeOutputInfos(t_io_infos *infos);
+extern t_io_infos * initializeOutputInfos(int argc, char **argv);
+
+      
+#endif

+ 182 - 0
acse/axe_labels.c

@@ -0,0 +1,182 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * axe_labels.c
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#include "axe_errors.h"
+#include "axe_labels.h"
+#include "collections.h"
+
+
+struct t_axe_label_manager
+{
+   t_list *labels;
+   int current_label_ID;
+   t_axe_label *label_to_assign;
+};
+
+int isAssignedLabel(t_axe_label_manager *lmanager)
+{
+   /* preconditions: lmanager must be different from NULL */
+   if (lmanager == NULL)
+      notifyError(AXE_INVALID_LABEL_MANAGER);
+
+   if (  (lmanager->label_to_assign != NULL)
+         && ((lmanager->label_to_assign)->labelID != LABEL_UNSPECIFIED) )
+   {
+      return 1;
+   }
+
+   return 0;
+}
+
+int compareLabels(t_axe_label *labelA, t_axe_label *labelB)
+{
+   if ( (labelA == NULL) || (labelB == NULL) )
+      return 0;
+
+   if (labelA->labelID == labelB->labelID)
+      return 1;
+   return 0;
+}
+
+/* reserve a new label identifier and return the identifier to the caller */
+t_axe_label * newLabelID(t_axe_label_manager *lmanager)
+{
+   t_axe_label *result;
+
+   /* preconditions: lmanager must be different from NULL */
+   assert(lmanager != NULL);
+   
+   /* initialize a new label */
+   result = alloc_label(lmanager->current_label_ID);
+
+   /* update the value of `current_label_ID' */
+   lmanager->current_label_ID++;
+   
+   /* tests if an out of memory occurred */
+   if (result == NULL)
+      return NULL;
+
+   /* add the new label to the list of labels */
+   lmanager->labels = addElement(lmanager->labels, result, -1);
+
+   /* return the new label */
+   return result;
+}
+
+/* assign the given label identifier to the next instruction. Returns
+ * NULL if an error occurred; otherwise the assigned label */
+t_axe_label * assignLabelID(t_axe_label_manager *lmanager, t_axe_label *label)
+{
+   /* precondition: lmanager must be different from NULL */
+   assert(lmanager != NULL);
+
+   /* precondition: label must be different from NULL and
+    * must always carry a valid identifier */
+   if (  (label == NULL)
+         || (label->labelID == LABEL_UNSPECIFIED)
+         || (label->labelID >= lmanager->current_label_ID))
+   {
+      notifyError(AXE_INVALID_LABEL);
+   }
+
+   /* test if the next instruction has already a label */
+   if (  (lmanager->label_to_assign != NULL)
+         && ((lmanager->label_to_assign)->labelID != LABEL_UNSPECIFIED) )
+   {
+      label->labelID = (lmanager->label_to_assign)->labelID;
+   }
+   else
+      lmanager->label_to_assign = label;
+
+   /* all went good */
+   return label;
+}
+
+/* initialize the memory structures for the label manager */
+t_axe_label_manager * initialize_label_manager()
+{
+   t_axe_label_manager *result;
+
+   /* create an instance of `t_axe_label_manager' */
+   result = (t_axe_label_manager *)
+         _AXE_ALLOC_FUNCTION (sizeof(t_axe_label_manager));
+
+   if (result == NULL)
+      notifyError(AXE_OUT_OF_MEMORY);
+
+   /* initialize the new instance */
+   result->labels = NULL;
+   result->current_label_ID = 0;
+   result->label_to_assign = NULL;
+
+   return result;
+}
+
+/* finalize an instance of `t_axe_label_manager' */
+void finalize_label_manager(t_axe_label_manager *lmanager)
+{
+   t_list *current_element;
+   t_axe_label *current_label;
+   
+   /* preconditions */
+   if (lmanager == NULL)
+      return;
+
+   /* initialize `current_element' to the head of the list
+    * of labels */
+   current_element = lmanager->labels;
+
+   while (current_element != NULL)
+   {
+      /* retrieve the current label */
+      current_label = (t_axe_label *) LDATA(current_element);
+      assert(current_label != NULL);
+
+      /* free the memory associated with the current label */
+      _AXE_FREE_FUNCTION(current_label);
+
+      /* fetch the next label */
+      current_element = LNEXT(current_element);
+   }
+
+   /* free the memory associated to the list of labels */
+   freeList(lmanager->labels);
+
+   _AXE_FREE_FUNCTION(lmanager);
+}
+
+t_axe_label * assign_label(t_axe_label_manager *lmanager)
+{
+   t_axe_label *result;
+   
+   /* precondition: lmanager must be different from NULL */
+   if (lmanager == NULL)
+      notifyError(AXE_INVALID_LABEL_MANAGER);
+
+   /* the label that must be returned (can be a NULL pointer) */
+   result = lmanager->label_to_assign;
+
+   /* update the value of `lmanager->label_to_assign' */
+   lmanager->label_to_assign = NULL;
+
+   /* return the label */
+   return result;
+}
+
+int get_number_of_labels(t_axe_label_manager *lmanager)
+{
+   if (lmanager == NULL)
+      return 0;
+
+   if (lmanager->labels == NULL)
+      return 0;
+
+   /* postconditions */
+   return getLength(lmanager->labels);
+}

+ 46 - 0
acse/axe_labels.h

@@ -0,0 +1,46 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * axe_labels.h
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#ifndef _AXE_LABELS_H
+#define _AXE_LABELS_H
+
+#include "axe_struct.h"
+
+
+struct t_axe_label_manager;
+
+/* Typedef for the struct t_axe_label_manager */
+typedef struct t_axe_label_manager t_axe_label_manager;
+
+/* reserve a new label identifier and return the identifier to the caller */
+extern t_axe_label * newLabelID(t_axe_label_manager *lmanager);
+
+/* assign the given label identifier to the next instruction. Returns
+ * FALSE if an error occurred; otherwise true */
+extern t_axe_label * assignLabelID(t_axe_label_manager *lmanager, t_axe_label *label);
+
+/* initialize the memory structures for the label manager */
+extern t_axe_label_manager * initialize_label_manager();
+
+/* retrieve the label that will be assigned to the next instruction */
+extern t_axe_label * assign_label(t_axe_label_manager *lmanager);
+
+/* finalize an instance of `t_axe_label_manager' */
+extern void finalize_label_manager(t_axe_label_manager *lmanager);
+
+/* get the number of labels inside the list of labels */
+extern int get_number_of_labels(t_axe_label_manager *lmanager);
+
+/* return TRUE if the two labels hold the same identifier */
+extern int compareLabels(t_axe_label *labelA, t_axe_label *labelB);
+
+/* test if a label will be assigned to the next instruction */
+extern int isAssignedLabel(t_axe_label_manager *lmanager);
+
+#endif

+ 690 - 0
acse/axe_reg_alloc.c

@@ -0,0 +1,690 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * axe_reg_alloc.c
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#include "axe_reg_alloc.h"
+#include "reg_alloc_constants.h"
+#include "axe_debug.h"
+#include "axe_errors.h"
+
+extern int errorcode;
+
+static int compareIntervalIDs(void *varA, void *varB);
+static int compareStartPoints(void *varA, void *varB);
+static int compareEndPoints(void *varA, void *varB);
+static t_list * updateListOfIntervals(t_list *result
+            , t_cflow_Node *current_node, int counter);
+static t_list * allocFreeRegisters(int regNum);
+static t_list * addFreeRegister
+      (t_list *registers, int regID, int position);
+static int assignRegister(t_reg_allocator *RA);
+static t_list * expireOldIntervals(t_reg_allocator *RA
+            , t_list *active_intervals, t_live_interval *interval);
+static t_list * getLiveIntervals(t_cflow_Graph *graph);
+static int insertListOfIntervals(t_reg_allocator *RA, t_list *intervals);
+static int insertLiveInterval(t_reg_allocator *RA, t_live_interval *interval);
+static void finalizeLiveInterval (t_live_interval *interval);
+static t_live_interval * allocLiveInterval(int varID, int startPoint, int endPoint);
+static t_list * spillAtInterval(t_reg_allocator *RA
+      , t_list *active_intervals, t_live_interval *interval);
+
+
+/*
+ * Perform a spill that allows the allocation of the given
+ * interval, given the list of active live intervals
+ */
+t_list * spillAtInterval(t_reg_allocator *RA
+      , t_list *active_intervals, t_live_interval *interval)
+{
+   t_list *last_element;
+   t_live_interval *last_interval;
+   
+   /* get the last element of the list of active intervals */
+   /* Precondition: if the list of active intervals is empty
+    * we are working on a machine with 0 registers available
+    * for the register allocation */
+   if (active_intervals == NULL)
+   {
+      RA->bindings[interval->varID] = RA_SPILL_REQUIRED;
+      return active_intervals;
+   }
+   
+   last_element = getLastElement(active_intervals);
+   last_interval = (t_live_interval *) LDATA(last_element);
+
+   /* If the current interval ends before the last one, spill
+    * the last one, otherwise spill the current interval   */
+   if (last_interval->endPoint > interval->endPoint)
+   {
+      RA->bindings[interval->varID]
+            = RA->bindings[last_interval->varID];
+      RA->bindings[last_interval->varID] = RA_SPILL_REQUIRED;
+
+      active_intervals = removeElement(active_intervals, last_interval);
+      
+      active_intervals = addSorted(active_intervals
+                  , interval, compareEndPoints);
+   }
+   else
+      RA->bindings[interval->varID] = RA_SPILL_REQUIRED;
+
+   return active_intervals;
+}
+
+/*
+ * Given two live intervals, compare them by
+ * the start point (find whichever starts first)
+ */
+int compareStartPoints(void *varA, void *varB)
+{
+   t_live_interval *liA;
+   t_live_interval *liB;
+   
+   if (varA == NULL)
+      return 0;
+
+   if (varB == NULL)
+      return 0;
+
+   liA = (t_live_interval *) varA;
+   liB = (t_live_interval *) varB;
+
+   return (liA->startPoint - liB->startPoint);
+}
+
+/*
+ * Given two live intervals, compare them
+ * by the end point (find whichever ends first)
+ */
+int compareEndPoints(void *varA, void *varB)
+{
+   t_live_interval *liA;
+   t_live_interval *liB;
+   
+   if (varA == NULL)
+     return 0;
+
+   if (varB == NULL)
+      return 0;
+
+   liA = (t_live_interval *) varA;
+   liB = (t_live_interval *) varB;
+
+   return (liA->endPoint - liB->endPoint);
+}
+
+/*
+ * Given two live intervals, check if they
+ * refer to the same interval
+ */
+int compareIntervalIDs(void *varA, void *varB)
+{
+   t_live_interval *liA;
+   t_live_interval *liB;
+
+   if (varA == NULL)
+      return 0;
+
+   if (varB == NULL)
+      return 0;
+
+   liA = (t_live_interval *) varA;
+   liB = (t_live_interval *) varB;
+
+   return (liA->varID == liB->varID);
+}
+
+/*
+ * Insert a live interval in the register allocator
+ */
+int insertLiveInterval(t_reg_allocator *RA, t_live_interval *interval)
+{
+   /* test the preconditions */
+   if (RA == NULL)
+      return RA_INVALID_ALLOCATOR;
+
+   if (interval == NULL)
+      return RA_INVALID_INTERVAL;
+
+   /* test if an interval for the requested variable is already inserted */
+   if (CustomfindElement(RA->live_intervals
+               , interval, compareIntervalIDs) != NULL)
+   {
+      return RA_INTERVAL_ALREADY_INSERTED;
+   }
+
+   /* add the given interval to the list of intervals,
+    * in order of starting point */
+    RA->live_intervals = addSorted(RA->live_intervals
+            , interval, compareStartPoints);
+   
+   return RA_OK;
+}
+
+/*
+ * Allocate and initialize the free registers list,
+ * assuming regNum general purpose registers
+ */
+t_list * allocFreeRegisters(int regNum)
+{
+   int count;
+   t_list *result;
+
+   /* initialize the local variables */
+   count = 1;
+   result = NULL;
+   
+   while(count <= regNum)
+   {
+      /* add a new register to the list of free registers */
+      result = addFreeRegister(result, count, -1);
+
+      /* update the `count' variable */
+      count ++;
+   }
+
+   /* return the list of free registers */
+   return result;
+}
+
+/*
+ * Return register regID to the free list in the given position
+ */
+t_list * addFreeRegister(t_list *registers, int regID, int position)
+{
+   int *element;
+
+   /* Allocate memory space for the reg id */
+   element = (int *) _AXE_ALLOC_FUNCTION(sizeof(int));
+   if (element == NULL)
+      notifyError(AXE_OUT_OF_MEMORY);
+
+   /* initialize element */
+   (* element) = regID;
+   
+   /* update the list of registers */
+   registers = addElement(registers, element, position);
+
+   /* return the list of free registers */
+   return registers;
+}
+
+/*
+ * Get a new register from the free list
+ */
+int assignRegister(t_reg_allocator *RA)
+{
+   int regID;
+
+   /* Check for list not empty*/
+   if (RA->freeRegisters == NULL)
+      return RA_SPILL_REQUIRED;
+
+   /* Get the name of the first free register */
+   regID = (* ((int *) LDATA(RA->freeRegisters)));
+   /* Free the space allocated to hold the register id */
+   _AXE_FREE_FUNCTION(LDATA(RA->freeRegisters));
+   /* Remove the structure from the free registers list */
+   RA->freeRegisters = removeFirst(RA->freeRegisters);
+
+   return regID;
+}
+
+/*
+ * Allocate and initialize the register allocator
+ */
+t_reg_allocator * initializeRegAlloc(t_cflow_Graph *graph)
+{
+   t_reg_allocator *result; /* the register allocator */
+   t_list *intervals;
+   t_list *current_elem;
+   t_list *current_cflow_var;
+   t_cflow_var *cflow_var;
+   int max_var_ID;
+   int counter;
+
+
+   /* Check preconditions: the cfg must exist */
+   if (graph == NULL)
+      notifyError(AXE_INVALID_CFLOW_GRAPH);
+
+   /* allocate memory for a new instance of `t_reg_allocator' */
+   result = (t_reg_allocator *) _AXE_ALLOC_FUNCTION(sizeof(t_reg_allocator));
+   if (result == NULL)
+      notifyError(AXE_OUT_OF_MEMORY);
+   
+   /* initialize the register allocator informations */
+   /* Reserve a few registers (RA_MIN_REG_NUM) to handle spills */
+   result->regNum = NUM_REGISTERS - RA_MIN_REG_NUM;
+   max_var_ID = getLength(graph->cflow_variables);
+
+   /* retrieve the max identifier from each live interval */
+   current_cflow_var = graph->cflow_variables;
+   while (current_cflow_var != NULL)
+   {
+      /* fetch the data informations about a variable */
+      cflow_var = (t_cflow_var *) LDATA(current_cflow_var);
+      assert(cflow_var != NULL);
+      
+      /* update the value of max_var_ID */
+      max_var_ID = (max_var_ID < cflow_var->ID)? cflow_var->ID : max_var_ID;
+
+      /* retrieve the next variable */
+      current_cflow_var = LNEXT(current_cflow_var);
+   }
+      
+   /* update the value of `result->varNum' with the correct var. identifier */
+   result->varNum = max_var_ID;
+   
+   current_elem = graph->cflow_variables;
+   
+   /* Assuming there are some variables to associate to regs,
+    * allocate space for the binding array, and initialize it */
+   
+   /*alloc memory for the array of bindings */
+   result->bindings = (int *) _AXE_ALLOC_FUNCTION
+         (sizeof(int) * (result->varNum + 1) );
+   
+   /* test if an error occurred */
+   if (result->bindings == NULL)
+      notifyError(AXE_OUT_OF_MEMORY);
+      
+   /* initialize the array of bindings */
+   for(counter = 0; counter <= result->varNum; counter++)
+      result->bindings[counter] = RA_REGISTER_INVALID;
+
+   /* Liveness analysis: compute the list of live intervals */
+   result->live_intervals = NULL;
+   intervals = getLiveIntervals(graph);
+
+   /* Copy the liveness info into the register allocator */
+   if (intervals != NULL)
+   {
+      if (insertListOfIntervals(result, intervals) != RA_OK)
+      {
+         finalizeRegAlloc(result);
+         notifyError(AXE_REG_ALLOC_ERROR);
+      }
+
+      /* deallocate memory used to hold the results of the
+       * liveness analysis */
+      freeList(intervals);
+   }
+
+   /* create a list of freeRegisters */
+   if (result->regNum > 0)
+      result->freeRegisters = allocFreeRegisters(result->regNum);
+   else
+      result->freeRegisters = NULL;
+   
+   /* return the new register allocator */
+   return result;
+}
+
+/*
+ * Deallocate the register allocator data structures
+ */
+void finalizeRegAlloc(t_reg_allocator *RA)
+{
+   if (RA == NULL)
+      return;
+
+   /* If the list of live intervals is not empty,
+    * deallocate its content */
+   if (RA->live_intervals != NULL)
+   {
+      t_list *current_element;
+      t_live_interval *current_interval;
+
+      /* finalize the memory blocks associated with all
+       * the live intervals */
+      for (current_element = RA->live_intervals
+            ;  current_element != NULL
+            ;  current_element = LNEXT(current_element))
+      {
+         /* fetch the current interval */
+         current_interval = (t_live_interval *) LDATA(current_element);
+         if (current_interval != NULL)
+         {
+            /* finalize the memory block associated with
+             * the current interval */
+            finalizeLiveInterval(current_interval);
+         }
+      }
+
+      /* deallocate the list of intervals */
+      freeList(RA->live_intervals);
+   }
+
+   /* Free memory used for the variable/register bindings */
+   if (RA->bindings != NULL)
+      _AXE_FREE_FUNCTION(RA->bindings);
+   if (RA->freeRegisters != NULL)
+   {
+      t_list *current_element;
+
+      current_element = RA->freeRegisters;
+      while (current_element != NULL)
+      {
+         _AXE_FREE_FUNCTION(LDATA(current_element));
+         current_element = LNEXT(current_element);
+      }
+
+      freeList(RA->freeRegisters);
+   }
+
+   _AXE_FREE_FUNCTION(RA);
+}
+
+/*
+ * Allocate and initialize a live interval data structure
+ * with a given varID, starting and ending points
+ */
+t_live_interval * allocLiveInterval
+               (int varID, int startPoint, int endPoint)
+{
+   t_live_interval *result;
+
+   /* create a new instance of `t_live_interval' */
+   result = _AXE_ALLOC_FUNCTION(sizeof(t_live_interval));
+   if (result == NULL)
+      notifyError(AXE_OUT_OF_MEMORY);
+
+   /* initialize the new instance */
+   result->varID = varID;
+   result->startPoint = startPoint;
+   result->endPoint = endPoint;
+
+   /* return the new `t_live_interval' */
+   return result;
+}
+
+/*
+ * Deallocate a live interval
+ */
+void finalizeLiveInterval (t_live_interval *interval)
+{
+   if (interval == NULL)
+      return;
+
+   /* finalize the current interval */
+   _AXE_FREE_FUNCTION(interval);
+}
+
+/*
+ * Insert all elements of the intervals list into
+ * the register allocator data structure
+ */
+int insertListOfIntervals(t_reg_allocator *RA, t_list *intervals)
+{
+   t_list *current_element;
+   t_live_interval *interval;
+   int ra_errorcode;
+   
+   /* preconditions */
+   if (RA == NULL)
+      return RA_INVALID_ALLOCATOR;
+   if (intervals == NULL)
+      return RA_OK;
+
+   for (current_element = intervals
+         ;  current_element != NULL
+         ;  current_element = LNEXT(current_element) )
+   {
+      /* Get the current live interval */
+      interval = (t_live_interval *) LDATA(current_element);
+      
+      if (interval == NULL)
+         return RA_INVALID_INTERVAL;
+
+      /* insert a new live interval */
+      ra_errorcode = insertLiveInterval(RA, interval);
+
+      /* test if an error occurred */
+      if (ra_errorcode != RA_OK)
+         return ra_errorcode;
+   }
+
+   return RA_OK;
+}
+
+/*
+ * Perform live intervals computation
+ */
+t_list * getLiveIntervals(t_cflow_Graph *graph)
+{
+   t_list *current_bb_element;
+   t_list *current_nd_element;
+   t_basic_block *current_block;
+   t_cflow_Node *current_node;
+   t_list *result;
+   int counter;
+
+   /* preconditions */
+   if (graph == NULL)
+      return NULL;
+
+   if (graph->blocks == NULL)
+      return NULL;
+
+   /* initialize the local variable `result' */
+   result = NULL;
+
+   /* intialize the instruction counter */
+   counter = 0;
+   
+   /* fetch the first basic block */
+   current_bb_element = graph->blocks;
+   while (current_bb_element != NULL)
+   {
+      current_block = (t_basic_block *) LDATA(current_bb_element);
+
+      /* fetch the first node of the basic block */
+      current_nd_element = current_block->nodes;
+      while(current_nd_element != NULL)
+      {
+         current_node = (t_cflow_Node *) LDATA(current_nd_element);
+
+         /* update the live intervals with the liveness informations */
+         result = updateListOfIntervals(result, current_node, counter);
+         
+         /* fetch the next node in the basic block */
+         counter++;
+         current_nd_element = LNEXT(current_nd_element);
+      }
+
+      /* fetch the next element in the list of basic blocks */
+      current_bb_element = LNEXT(current_bb_element);
+   }
+
+   return result;
+}
+
+/*
+ * Update the liveness interval for the variable 'id', used or defined
+ * at position 'counter'.
+ */
+t_list *updateVarInterval( int id, int counter, t_list *intervals )
+{
+    t_list *element_found;
+    t_live_interval *interval_found;
+    t_live_interval pattern;
+
+    if (id == RA_EXCLUDED_VARIABLE)
+        return;
+    
+    pattern.varID = id;
+    /* search for the current live interval */
+    element_found = CustomfindElement(intervals, &pattern, compareIntervalIDs);
+    if (element_found != NULL)
+    {
+        interval_found = (t_live_interval *) LDATA(element_found);
+        /* update the interval informations */
+        if (interval_found->startPoint > counter)
+            interval_found->startPoint = counter;
+        if (interval_found->endPoint < counter)
+            interval_found->endPoint = counter;
+    }
+    else
+    {
+        /* we have to add a new live interval */
+        interval_found = allocLiveInterval(id, counter, counter);
+        if (interval_found == NULL)
+            notifyError(AXE_OUT_OF_MEMORY);
+        intervals = addElement(intervals, interval_found, -1);
+    }
+    
+    return intervals;
+}
+
+/*
+ * Use liveness information to update the list of
+ * live intervals
+ */
+t_list * updateListOfIntervals(t_list *result
+         , t_cflow_Node *current_node, int counter)
+{
+   t_list *current_element;
+   t_cflow_var *current_var;
+   
+   if (current_node == NULL)
+      return result;
+
+   current_element = current_node->in;
+   while (current_element != NULL)
+   {
+      current_var = (t_cflow_var *) LDATA(current_element);
+
+      result = updateVarInterval(current_var->ID, counter, result);
+      
+      /* fetch the next element in the list of live variables */
+      current_element = LNEXT(current_element);
+   }
+   
+   current_element = current_node->out;
+   while (current_element != NULL)
+   {
+      current_var = (t_cflow_var *) LDATA(current_element);
+
+      result = updateVarInterval(current_var->ID, counter, result);
+      
+      /* fetch the next element in the list of live variables */
+      current_element = LNEXT(current_element);
+   }
+
+   if (current_node->def)
+       result = updateVarInterval(current_node->def->ID, counter, result);
+
+   return result;
+}
+
+/*
+ * Remove from active_intervals all the live intervals that end before the
+ * beginning of the current live interval
+ */
+t_list * expireOldIntervals(t_reg_allocator *RA, t_list *active_intervals
+               , t_live_interval *interval)
+{
+   t_list *current_element;
+   t_list *next_element;
+   t_live_interval *current_interval;
+
+   /* Check for valid register allocator and set of active intervals */
+   if (active_intervals == NULL)
+      return NULL;
+   if (RA == NULL)
+      return NULL;
+   if (interval == NULL)
+      return active_intervals;
+
+   /* Iterate over the set of active intervals */
+   current_element = active_intervals;
+   while(current_element != NULL)
+   {
+      /* Get the live interval */
+      current_interval = (t_live_interval *) LDATA(current_element);
+
+      /* If the considered interval ends before the beginning of 
+       * the current live interval, we don't need to keep track of
+       * it anymore; otherwise, this is the first interval we must
+       * still take into account when assigning registers */
+      if (current_interval->endPoint >= interval->startPoint)
+         return active_intervals;
+
+      /* Get the next live interval */
+      next_element = LNEXT(current_element);
+
+      /* Remove the current element from the list */
+      active_intervals = removeElement(active_intervals, current_interval);
+
+      /* Free all the registers associated with the removed interval */
+      RA->freeRegisters = addFreeRegister
+            (RA->freeRegisters, RA->bindings[current_interval->varID], 0);
+
+      /* Step to the next interval */
+      current_element = next_element;
+   }
+
+   /* Return the updated list of active intervals */
+   return active_intervals;
+}
+
+/*
+ * Main register allocation function
+ */
+int execute_linear_scan(t_reg_allocator *RA)
+{
+   t_list *current_element;
+   t_live_interval *current_interval;
+   t_list *active_intervals;
+   
+   /* test the preconditions */
+   if (RA == NULL)   /* Register allocator created? */
+      return RA_INVALID_ALLOCATOR;
+   if (RA->live_intervals == NULL) /* Liveness analysis ready? */
+      return RA_OK;
+
+   /* initialize the list of active intervals */
+   active_intervals = NULL;
+   
+   /* Iterate over the list of live intervals */   
+   for( current_element = RA->live_intervals
+        ;   current_element != NULL
+        ;   current_element = LNEXT(current_element) )
+   {
+      /* Get the live interval */
+      current_interval = (t_live_interval *) LDATA(current_element);
+
+      /* Check which intervals are ended and remove 
+       * them from the active set, thus freeing registers */
+      active_intervals = expireOldIntervals
+               (RA, active_intervals, current_interval);
+
+      /* If all registers are busy, perform a spill */
+      if (getLength(active_intervals) == RA->regNum)
+      {
+         /* perform a spill */
+         active_intervals = spillAtInterval
+               (RA, active_intervals, current_interval);
+      }
+      else /* Otherwise, assign a new register to the current live interval */
+      {
+         RA->bindings[current_interval->varID] = assignRegister(RA);
+
+         /* Add the current interval to the list of active intervals, in
+          * order of ending points (to allow easier expire management) */
+         active_intervals = addSorted(active_intervals
+            , current_interval, compareEndPoints);
+      }
+   }
+
+   /* free the list of active intervals */
+   freeList(active_intervals);
+   
+   return RA_OK;
+}

+ 49 - 0
acse/axe_reg_alloc.h

@@ -0,0 +1,49 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * axe_reg_alloc.h
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#ifndef _AXE_REG_ALLOC_H
+#define _AXE_REG_ALLOC_H
+
+#include "axe_struct.h"
+#include "axe_engine.h"
+#include "collections.h"
+#include "axe_cflow_graph.h"
+
+typedef struct t_live_interval
+{
+   int varID;     /* a variable identifier */
+   int startPoint;  /* the index of the first instruction
+                   * that make use of (or define) this variable */
+   int endPoint;   /* the index of the last instruction
+                   * that make use of (or define) this variable */
+}t_live_interval;
+
+typedef struct t_reg_allocator
+{
+   t_list *live_intervals;    /* an ordered list of live intervals */
+   int regNum;                /* the number of registers of the machine */
+   int varNum;                /* number of variables */
+   int *bindings;             /* an array of bindings of kind : varID-->register.
+                               * If a certain variable X need to be spilled
+                               * in memory, the value of `register' is set
+                               * to the value of the macro RA_SPILL_REQUIRED */
+   t_list *freeRegisters;     /* a list of free registers */
+}t_reg_allocator;
+
+
+/* Initialize the internal structure of the register allocator */
+extern t_reg_allocator * initializeRegAlloc(t_cflow_Graph *graph);
+
+/* finalize all the data structure associated with the given register allocator */
+extern void finalizeRegAlloc(t_reg_allocator *RA);
+
+/* execute the register allocation algorythm (Linear Scan) */
+extern int execute_linear_scan(t_reg_allocator *RA);
+
+#endif

+ 217 - 0
acse/axe_struct.c

@@ -0,0 +1,217 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * axe_struct.c
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#include "axe_struct.h"
+
+/* create an expression */
+t_axe_expression create_expression (int value, int type)
+{
+   t_axe_expression expression;
+
+   expression.value = value;
+   expression.expression_type = type;
+
+   return expression;
+}
+
+/* create and initialize an instance of `t_axe_register' */
+t_axe_register * alloc_register(int ID, int indirect)
+{
+   t_axe_register *result;
+
+   /* create an instance of `t_axe_register' */
+   result = (t_axe_register *)
+            _AXE_ALLOC_FUNCTION(sizeof(t_axe_register));
+   
+   /* check the postconditions */
+   if (result == NULL)
+      return NULL;
+
+   /* initialize the new label */
+   result->ID = ID;
+   result->indirect = indirect;
+
+   /* return the label */
+   return result;
+}
+
+/* create and initialize an instance of `t_axe_instruction' */
+t_axe_instruction * alloc_instruction(int opcode)
+{
+   t_axe_instruction *result;
+
+   /* create an instance of `t_axe_data' */
+   result = (t_axe_instruction *) _AXE_ALLOC_FUNCTION(sizeof(t_axe_instruction));
+   
+   /* check the postconditions */
+   if (result == NULL)
+      return NULL;
+
+   /* ininitialize the fields of `result' */
+   result->opcode = opcode;
+   result->reg_1 = NULL;
+   result->reg_2 = NULL;
+   result->reg_3 = NULL;
+   result->immediate = 0;
+   result->labelID = NULL;
+   result->address = NULL;
+   result->user_comment = NULL;
+
+   /* return `result' */
+   return result;
+}
+
+/* create and initialize an instance of `t_axe_data' */
+t_axe_data * alloc_data(int directiveType, int value, t_axe_label *label)
+{
+   t_axe_data *result;
+
+   /* create an instance of `t_axe_data' */
+   result = (t_axe_data *) _AXE_ALLOC_FUNCTION(sizeof(t_axe_data));
+   
+   /* check the postconditions */
+   if (result == NULL)
+      return NULL;
+
+   /* initialize the new directive */
+   result->directiveType = directiveType;
+   result->value = value;
+   result->labelID = label;
+
+   /* return the new data */
+   return result;
+}
+
+t_while_statement create_while_statement()
+{
+   t_while_statement statement;
+
+   /* initialize the WHILE informations */
+   statement.label_condition = NULL;
+   statement.label_end = NULL;
+
+   /* return a new instance of `t_while_statement' */
+   return statement;
+}
+
+t_axe_label * alloc_label(int value)
+{
+   t_axe_label *result;
+
+   /* create an instance of t_axe_label */
+   result = (t_axe_label *)
+         _AXE_ALLOC_FUNCTION(sizeof(t_axe_label));
+
+   /* initialize the internal value of `result' */
+   result->labelID = value;
+
+   /* return the just initialized new instance of `t_axe_label' */
+   return result;
+}
+
+t_axe_declaration * alloc_declaration
+      (char *ID, int isArray, int arraySize, int init_val)
+{
+   t_axe_declaration *result;
+
+   /* allocate memory for the new declaration */
+   result = (t_axe_declaration *)
+         _AXE_ALLOC_FUNCTION(sizeof(t_axe_declaration));
+
+   /* check the postconditions */
+   if (result == NULL)
+      return NULL;
+
+   /* initialize the content of `result' */
+   result->isArray = isArray;
+   result->arraySize = arraySize;
+   result->ID = ID;
+   result->init_val = init_val;
+
+   /* return the just created and initialized instance of t_axe_declaration */
+   return result;
+}
+
+/* finalize an instance of `t_axe_variable' */
+void free_variable (t_axe_variable *variable)
+{
+   _AXE_FREE_FUNCTION(variable);
+}
+
+/* create and initialize an instance of `t_axe_variable' */
+t_axe_variable * alloc_variable
+      (char *ID, int type, int isArray, int arraySize, int init_val)
+{
+   t_axe_variable *result;
+
+   /* allocate memory for the new variable */
+   result = (t_axe_variable *)
+         _AXE_ALLOC_FUNCTION(sizeof(t_axe_variable));
+
+   /* check the postconditions */
+   if (result == NULL)
+      return NULL;
+
+   /* initialize the content of `result' */
+   result->type = type;
+   result->isArray = isArray;
+   result->arraySize = arraySize;
+   result->ID = ID;
+   result->init_val = init_val;
+   result->labelID = NULL;
+
+   /* return the just created and initialized instance of t_axe_variable */
+   return result;
+}
+
+/* finalize an instruction info. */
+void free_Instruction(t_axe_instruction *inst)
+{
+   /* preconditions */
+   if (inst == NULL)
+      return;
+   
+   /* free memory */
+   if (inst->reg_1 != NULL)
+      _AXE_FREE_FUNCTION(inst->reg_1);
+   if (inst->reg_2 != NULL)
+      _AXE_FREE_FUNCTION(inst->reg_2);
+   if (inst->reg_3 != NULL)
+      _AXE_FREE_FUNCTION(inst->reg_3);
+   if (inst->address != NULL)
+      _AXE_FREE_FUNCTION(inst->address);
+
+   _AXE_FREE_FUNCTION(inst);
+}
+
+/* finalize a data info. */
+void free_Data(t_axe_data *data)
+{
+   if (data != NULL)
+      _AXE_FREE_FUNCTION(data);
+}
+
+t_axe_address * alloc_address(int type, int address, t_axe_label *label)
+{
+   t_axe_address *result;
+
+   result = (t_axe_address *)
+         _AXE_ALLOC_FUNCTION(sizeof(t_axe_address));
+
+   if (result == NULL)
+      return NULL;
+
+   /* initialize the new instance of `t_axe_address' */
+   result->type = type;
+   result->addr = address;
+   result->labelID = label;
+
+   /* return the new address */
+   return result;
+}

+ 155 - 0
acse/axe_struct.h

@@ -0,0 +1,155 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * axe_struct.h
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#ifndef _AXE_STRUCT_H
+#define _AXE_STRUCT_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include "axe_constants.h"
+
+#ifndef _AXE_ALLOC_FUNCTION
+#  define _AXE_ALLOC_FUNCTION malloc
+#endif
+#ifndef _AXE_FREE_FUNCTION
+#  define _AXE_FREE_FUNCTION free
+#endif
+
+typedef struct t_axe_label
+{
+   int labelID;      /* label identifier */
+} t_axe_label;
+
+typedef struct t_axe_register
+{
+   int ID;        /* an identifier of the register */
+   int indirect;  /* a boolean value: 1 if the register value is a pointer */
+}t_axe_register;
+
+typedef struct t_axe_address
+{
+   int addr;               /* a Program Counter */
+   t_axe_label *labelID;   /* a label identifier */
+   int type;               /* one of ADDRESS_TYPE or LABEL_TYPE */
+}t_axe_address;
+
+/* A structure that defines the internal data of a `Acse variable' */
+typedef struct t_axe_variable
+{
+   int type;      /* a valid data type @see `axe_constants.h' */
+   int isArray;   /* must be TRUE if the current variable is an array */
+   int arraySize; /* the size of the array. This information is useful only
+                   * if the field `isArray' is TRUE */
+   int init_val;  /* initial value of the current variable. Actually it is
+                   * implemented as a integer value. `int' is
+                   * the only supported type at the moment,
+                   * future developments could consist of a modification of
+                   * the supported type system. Thus, maybe init_val will be
+                   * modified in future. */
+   char *ID;               /* variable identifier (should never be a NULL
+                            * pointer or an empty string "") */
+   t_axe_label *labelID;   /* a label that refers to the location
+                            * of the variable inside the data segment */
+} t_axe_variable;
+
+/* a simbolic assembly instruction */
+typedef struct t_axe_instruction
+{
+   int opcode;                   /* instruction opcode (for example: AXE_ADD ) */
+   t_axe_register *reg_1;        /* destination register */
+   t_axe_register *reg_2;        /* first source register */
+   t_axe_register *reg_3;        /* second source register */
+   int immediate;                /* immediate value */
+   t_axe_address *address;       /* an address operand */
+   char *user_comment;           /* if defined it is set to the source code
+                                  * instruction that generated the current
+                                  * assembly. This string will be written
+                                  * into the output code as a comment */
+   t_axe_label *labelID;        /* a label associated with the current
+                                  * instruction */
+}t_axe_instruction;
+
+/* this structure is used in order to define assembler directives.
+ * Directives are used in many cases such the definition of variables
+ * inside the data segment. Every instance `t_axe_data' contains
+ * all the informations about a single directive.
+ * An example is the directive .word that is required when the assembler
+ * must reserve a word of data inside the data segment. */
+typedef struct t_axe_data
+{
+   int directiveType;      /* the type of the current directive
+                            * (for example: DIR_WORD) */
+   int value;              /* the value associated with the directive */
+   t_axe_label *labelID;   /* label associated with the current data */
+}t_axe_data;
+
+typedef struct t_axe_expression
+{
+   int value;           /* an immediate value or a register identifier */
+   int expression_type; /* actually only integer values are supported */
+} t_axe_expression;
+
+typedef struct t_axe_declaration
+{
+   int isArray;           /* must be TRUE if the current variable is an array */
+   int arraySize;         /* the size of the array. This information is useful only
+                           * if the field `isArray' is TRUE */
+   int init_val;          /* initial value of the current variable. */
+   char *ID;              /* variable identifier (should never be a NULL pointer
+                           * or an empty string "") */
+} t_axe_declaration;
+
+typedef struct t_while_statement
+{
+   t_axe_label *label_condition;   /* this label points to the expression
+                                    * that is used as loop condition */
+   t_axe_label *label_end;         /* this label points to the instruction
+                                    * that follows the while construct */
+} t_while_statement;
+
+/* create a label */
+extern t_axe_label * alloc_label(int value);
+
+/* create an expression */
+extern t_axe_expression create_expression (int value, int type);
+
+/* create an instance that will mantain infos about a while statement */
+extern t_while_statement create_while_statement();
+
+/* create an instance of `t_axe_register' */
+extern t_axe_register * alloc_register(int ID, int indirect);
+
+/* create an instance of `t_axe_instruction' */
+extern t_axe_instruction * alloc_instruction(int opcode);
+
+/* create an instance of `t_axe_address' */
+extern t_axe_address * alloc_address(int type, int address, t_axe_label *label);
+
+/* create an instance of `t_axe_data' */
+extern t_axe_data * alloc_data(int directiveType, int value, t_axe_label *label);
+
+/* create an instance of `t_axe_variable' */
+extern t_axe_variable * alloc_variable
+      (char *ID, int type, int isArray, int arraySize, int init_val);
+
+/* finalize an instance of `t_axe_variable' */
+extern void free_variable (t_axe_variable *variable);
+
+/* create an instance of `t_axe_variable' */
+extern t_axe_declaration * alloc_declaration
+      (char *ID, int isArray, int arraySize, int init_val);
+
+/* finalize an instruction info. */
+extern void free_Instruction(t_axe_instruction *inst);
+
+/* finalize a data info. */
+extern void free_Data(t_axe_data *data);
+
+#endif

+ 1061 - 0
acse/axe_transform.c

@@ -0,0 +1,1061 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * axe_transform.c
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#include "axe_transform.h"
+#include "symbol_table.h"
+#include "cflow_constants.h"
+#include "reg_alloc_constants.h"
+#include "axe_errors.h"
+#include "axe_debug.h"
+
+extern int errorcode;
+extern int cflow_errorcode;
+
+typedef struct t_tempLabel
+{
+   t_axe_label *labelID;
+   int regID;
+} t_tempLabel;
+
+
+static t_axe_instruction * _createUnary (t_program_infos *program
+            , int reg, t_axe_label *label, int opcode);
+static t_axe_instruction * createUnaryInstruction
+               (t_program_infos *program, int reg, int opcode);
+static t_tempLabel * allocTempLabel(t_axe_label *labelID, int regID);
+static void freeTempLabel(t_tempLabel *tempLabel);
+static void finalizeListOfTempLabels(t_list *tempLabels);
+static int compareTempLabels(void *valA, void *valB);
+
+/* create new locations into the data segment in order to manage correctly
+ * spilled variables */
+static void updateTheDataSegment
+            (t_program_infos *program, t_list *tempLabels);
+static void updateTheCodeSegment
+            (t_program_infos *program, t_cflow_Graph *graph);
+static t_list * _insertLoad(t_program_infos *program, t_cflow_Graph *graph
+      , t_basic_block *block, t_cflow_Node *current_node
+            , t_cflow_var *var, t_list *usedVars);
+static t_list * _insertStore(t_program_infos *program, t_cflow_Graph *graph
+      , t_basic_block *block, t_cflow_Node *current_node
+            , t_cflow_var *var, t_list *usedVars);
+            
+/* create a load instruction without assigning it to program */
+static t_axe_instruction * createLoadInstruction
+                  (t_program_infos *program, int reg);
+/* create a store instruction without assigning it to program */
+static t_axe_instruction * createStoreInstruction
+                  (t_program_infos *program, int reg);
+
+/* update the control flow informations by unsing the result
+ * of the register allocation process and a list of bindings
+ * between new assembly labels and spilled variables */
+static void updatCflowInfos(t_program_infos *program, t_cflow_Graph *graph
+            , t_reg_allocator *RA, t_list *label_bindings);
+
+/* this function returns a list of t_templabel containing binding
+ * informations between spilled variables and labels that will point
+ * to a memory block in the data segment */
+static t_list * retrieveLabelBindings(t_program_infos *program, t_reg_allocator *RA);
+      
+int _insertLoadSpill(t_program_infos *program, int temp_register, int selected_register
+            , t_cflow_Graph *graph, t_basic_block *current_block
+            , t_cflow_Node *current_node, t_list *labelBindings, int before);
+            
+int _insertStoreSpill(t_program_infos *program, int temp_register, int selected_register
+            , t_cflow_Graph *graph, t_basic_block *current_block
+            , t_cflow_Node *current_node, t_list *labelBindings, int before);
+
+      
+static t_list * _insertStore(t_program_infos *program, t_cflow_Graph *graph
+      , t_basic_block *current_block, t_cflow_Node *current_node
+            , t_cflow_var *var, t_list *usedVars)
+{
+   /* we have to insert a store instruction into the code */
+   t_axe_instruction *storeInstr;
+   t_cflow_Node *storeNode;
+
+   /* create a load instruction */
+   storeInstr = createStoreInstruction
+            (program, var->ID);
+
+   /* test if an error occurred */
+   if (errorcode != AXE_OK) {
+      free_Instruction(storeInstr);
+      notifyError(errorcode);
+   }
+               
+   if (storeInstr != NULL)
+   {
+      /* create a node for the store instruction */
+      storeNode = allocNode (graph, storeInstr);
+      if (cflow_errorcode != CFLOW_OK) {
+         finalizeNode(storeNode);
+         free_Instruction(storeInstr);
+         return usedVars;
+      }
+
+      /* insert the node `loadNode' before `current_node' */
+      insertNodeAfter(current_block, current_node, storeNode);
+   
+      /* update the list of usedVars */
+      usedVars = removeElement(usedVars, storeNode->uses[0]);
+   }
+
+   return usedVars;
+}
+
+t_list * _insertLoad(t_program_infos *program, t_cflow_Graph *graph
+      , t_basic_block *current_block, t_cflow_Node *current_node
+            , t_cflow_var *var, t_list *usedVars)
+{
+   /* we have to insert a load instruction into the code */
+   t_axe_instruction *current_instr;
+   t_axe_instruction *loadInstr;
+   t_cflow_Node *loadNode;
+
+   /* retrieve the current instruction from the current node */
+   current_instr = current_node->instr;
+
+   /* create a load instruction */
+   loadInstr = createLoadInstruction
+         (program, var->ID);
+
+   /* test if an error occurred */
+   if (errorcode != AXE_OK) {
+      free_Instruction(loadInstr);
+      notifyError(errorcode);
+   }
+
+   if (loadInstr != NULL)
+   {
+      /* create a node for the load instruction */
+      loadNode = allocNode (graph, loadInstr);
+
+      /* test if an error occurred */
+      if (cflow_errorcode != CFLOW_OK) {
+         finalizeNode(loadNode);
+         free_Instruction(loadInstr);
+         return usedVars;
+      }
+
+      /* update the label informations */
+      if (current_instr->labelID != NULL) {
+         loadInstr->labelID = current_instr->labelID;
+         current_instr->labelID = NULL;
+      }
+   
+      /* insert the node `loadNode' before `current_node' */
+      insertNodeBefore(current_block, current_node, loadNode);
+
+      /* update the list of usedVars */
+      usedVars = addElement(usedVars, loadNode->def, -1);
+   }
+
+   return usedVars;
+}
+
+void updateTheCodeSegment(t_program_infos *program, t_cflow_Graph *graph)
+{
+   t_list *current_bb_element;
+   t_list *current_nd_element;
+   t_basic_block *bblock;
+   t_cflow_Node *node;
+   
+   /* preconditions */
+   if (program == NULL)
+      notifyError(AXE_PROGRAM_NOT_INITIALIZED);
+
+   if (graph == NULL)
+      notifyError(AXE_INVALID_CFLOW_GRAPH);
+
+   current_bb_element = graph->blocks;
+   while(current_bb_element != NULL)
+   {
+      bblock = (t_basic_block *) LDATA(current_bb_element);
+
+      current_nd_element = bblock->nodes;
+      while(current_nd_element != NULL)
+      {
+         node = (t_cflow_Node *) LDATA(current_nd_element);
+
+         program->instructions =
+               addElement(program->instructions, node->instr, -1);
+         
+         current_nd_element = LNEXT(current_nd_element);
+      }
+
+      current_bb_element = LNEXT(current_bb_element);
+   }
+}
+
+void updateTheDataSegment(t_program_infos *program, t_list *labelBindings)
+{
+   t_list *current_element;
+   t_tempLabel *current_TL;
+   t_axe_data *new_data_info;
+
+   /* preconditions */
+   if (program == NULL) {
+      finalizeListOfTempLabels(labelBindings);
+      notifyError(AXE_PROGRAM_NOT_INITIALIZED);
+   }
+
+   /* initialize the value of `current_element' */
+   current_element = labelBindings;
+   while(current_element != NULL)
+   {
+      current_TL = (t_tempLabel *) LDATA(current_element);
+
+      new_data_info = alloc_data (DIR_WORD, 0, current_TL->labelID);
+         
+      if (new_data_info == NULL){
+         finalizeListOfTempLabels(labelBindings);
+         notifyError(AXE_OUT_OF_MEMORY);
+      }
+
+      /* update the list of directives */
+      program->data = addElement(program->data, new_data_info, -1);
+      
+      current_element = LNEXT(current_element);
+   }
+}
+
+t_axe_instruction * _createUnary (t_program_infos *program
+            , int reg, t_axe_label *label, int opcode)
+{
+   t_axe_instruction *result;
+   
+   /* preconditions */
+   if (program == NULL) {
+      errorcode = AXE_PROGRAM_NOT_INITIALIZED;
+      return NULL;
+   }
+   
+   if (label == NULL) {
+      errorcode = AXE_INVALID_LABEL;
+      return NULL;
+   }
+
+   /* create an instance of `t_axe_instruction' */
+   result = alloc_instruction(opcode);
+   if (result == NULL) {
+      errorcode = AXE_OUT_OF_MEMORY;
+      return NULL;
+   }
+
+   result->reg_1 = alloc_register(reg, 0);
+   if (result->reg_1 == NULL) {
+      errorcode = AXE_OUT_OF_MEMORY;
+      free_Instruction(result);
+      return NULL;
+   }
+
+   /* initialize an address info */
+   result->address = alloc_address(LABEL_TYPE, 0, label);
+   if (result->address == NULL) {
+      errorcode = AXE_OUT_OF_MEMORY;
+      free_Instruction(result);
+      return NULL;
+   }
+
+   return result;
+}
+
+int compareTempLabels(void *valA, void *valB)
+{
+   t_tempLabel *tlA;
+   t_tempLabel *tlB;
+   
+   if (valA == NULL)
+      return 0;
+   if (valB == NULL)
+      return 0;
+
+   tlA = (t_tempLabel *) valA;
+   tlB = (t_tempLabel *) valB;
+
+   return (tlA->regID == tlB->regID);
+}
+
+t_tempLabel * allocTempLabel(t_axe_label *labelID, int regID)
+{
+   t_tempLabel *result;
+
+   /* preconditions */
+   if (labelID == NULL) {
+      errorcode = AXE_INVALID_LABEL;
+      return NULL;
+   }
+
+   /* create a new temp-label */
+   result = _AXE_ALLOC_FUNCTION(sizeof(t_tempLabel));
+   if (result == NULL) {
+      errorcode = AXE_OUT_OF_MEMORY;
+      return NULL;
+   }
+   
+   /* initialize the temp label */
+   result->labelID = labelID;
+   result->regID = regID;
+
+   return result;
+}
+
+void freeTempLabel(t_tempLabel *tempLabel)
+{
+   if (tempLabel != NULL)
+      _AXE_FREE_FUNCTION(tempLabel);
+}
+
+void finalizeListOfTempLabels(t_list *tempLabels)
+{
+   t_list *current_element;
+   t_tempLabel *tempLabel;
+
+   /* test the preconditions */
+   if (tempLabels == NULL)
+      return;
+
+   /* assign to current_element the address of the first
+    * element of the list `tempLabels' */
+   current_element = tempLabels;
+   
+   while(current_element != NULL)
+   {
+      tempLabel = (t_tempLabel *) LDATA(current_element);
+      if (tempLabel != NULL)
+         freeTempLabel(tempLabel);
+      
+      current_element = LNEXT(current_element);
+   }
+
+   /* finalize the list of elements of type `t_tempLabel' */
+   freeList(tempLabels);
+}
+
+void updateProgramInfos(t_program_infos *program
+         , t_cflow_Graph *graph, t_reg_allocator *RA)
+{
+   t_list *label_bindings;
+
+   /* retrieve a list of t_templabels for the given RA infos.*/
+   label_bindings = retrieveLabelBindings(program, RA);
+
+   /* update the content of the data segment */
+   updateTheDataSegment(program, label_bindings);
+   
+   /* update the control flow graph with the reg-alloc infos. */
+   updatCflowInfos(program, graph, RA, label_bindings);
+
+   /* erase the old code segment */
+   freeList(program->instructions);
+   program->instructions = NULL;
+
+   /* update the code segment informations */
+   updateTheCodeSegment(program, graph);
+
+   /* finalize the list of tempLabels */
+   finalizeListOfTempLabels(label_bindings);
+}
+
+t_list * retrieveLabelBindings(t_program_infos *program, t_reg_allocator *RA)
+{
+   int counter;
+   t_list *result;
+   t_tempLabel *tlabel;
+   t_axe_label *axe_label;
+   
+   /* preconditions */
+   if (program == NULL)
+      notifyError(AXE_PROGRAM_NOT_INITIALIZED);
+   if (RA == NULL)
+      notifyError(AXE_INVALID_REG_ALLOC);
+
+   /* initialize the local variable `result' */
+   result = NULL;
+   tlabel = NULL;
+
+   for (counter = 0; counter <= RA->varNum; counter++)
+   {
+      if (RA->bindings[counter] == RA_SPILL_REQUIRED)
+      {
+         /* retrieve a new label */
+         axe_label = newLabel(program);
+         if (axe_label == NULL)
+            notifyError(AXE_INVALID_LABEL);
+
+         /* create a new tempLabel */
+         tlabel = allocTempLabel(axe_label, counter);
+
+         /* add the current tlabel to the list of labelbindings */
+         result = addElement(result, tlabel, -1);
+      }
+   }
+   
+   /* postcondition: return the list of bindings */
+   return result;
+}
+
+t_axe_instruction * createUnaryInstruction
+               (t_program_infos *program, int reg, int opcode)
+{
+   char *varID;
+   int sy_errorcode;
+   t_axe_variable *axe_var;
+
+   /* test the preconditions */
+   if ((reg == REG_INVALID) || (reg == REG_0)) {
+      errorcode = AXE_INVALID_REGISTER_INFO;
+      return NULL;
+   }
+
+   if (program == NULL || program->sy_table == NULL) {
+      errorcode = AXE_PROGRAM_NOT_INITIALIZED;
+      return NULL;
+   }
+
+   /* initialize the value of errorcode */
+   sy_errorcode = SY_TABLE_OK;
+   varID = getIDfromLocation(program->sy_table, reg, &sy_errorcode);
+   if (varID == NULL)
+      return NULL;
+
+   /* retrieve the variable associated with `varID' */
+   axe_var = getVariable (program, varID);
+
+   return _createUnary (program, reg, axe_var->labelID, opcode);
+}
+
+t_axe_instruction * createStoreInstruction
+                  (t_program_infos *program, int reg)
+{
+   return createUnaryInstruction(program, reg, STORE);
+}
+
+t_axe_instruction * createLoadInstruction
+                  (t_program_infos *program, int reg)
+{
+   return createUnaryInstruction(program, reg, LOAD);
+}
+
+t_cflow_Graph * insertLoadAndStoreInstr
+         (t_program_infos *program, t_cflow_Graph *graph)
+{
+   t_list *current_bb_element;
+   t_basic_block *current_block;
+   t_list *current_nd_element;
+   t_cflow_Node *current_node;
+   t_list *usedVars;
+
+   /* assertions */
+   assert(program != NULL);
+   assert(graph != NULL);
+   
+   /* initialize the list of variables used by this basic block */
+   usedVars = NULL;
+   current_bb_element = graph->blocks;
+   while (current_bb_element != NULL)
+   {
+      current_block = (t_basic_block *) LDATA(current_bb_element);
+
+      /* retrieve the list of nodes for the current basic block */
+      current_nd_element = current_block->nodes;
+      while(current_nd_element != NULL)
+      {
+         current_node = (t_cflow_Node *) LDATA(current_nd_element);
+
+         /* test if we have to insert a store */
+         if (  (current_node->def != NULL)
+               && ((current_node->def)->ID != REG_0) )
+         {
+            if (findElement(usedVars, current_node->def) == NULL)
+            {
+               usedVars = addElement(usedVars, current_node->def, -1);
+            }
+         }
+
+         /* test if we have to insert a load */
+         if (  (current_node->uses[0] != NULL)
+               && ((current_node->uses[0])->ID != REG_0) )
+         {
+            if (findElement(usedVars, current_node->uses[0]) == NULL)
+            {
+               usedVars = _insertLoad(program, graph, current_block
+                     , current_node, current_node->uses[0], usedVars);
+            }
+         }
+         if (  (current_node->uses[1] != NULL)
+               && ((current_node->uses[1])->ID != REG_0) )
+         {
+            if (findElement(usedVars, current_node->uses[1]) == NULL)
+            {
+               usedVars = _insertLoad(program, graph, current_block
+                     , current_node, current_node->uses[1], usedVars);
+            }
+         }
+         if (  (current_node->uses[2] != NULL)
+               && ((current_node->uses[2])->ID != REG_0) )
+         {
+            if (findElement(usedVars, current_node->uses[2]) == NULL)
+            {
+               usedVars = _insertLoad(program, graph, current_block
+                     , current_node, current_node->uses[2], usedVars);
+            }
+         }
+
+         /* retrieve the next element */
+         current_nd_element = LNEXT(current_nd_element);
+      }
+
+      current_nd_element = getLastElement(current_block->nodes);
+      while((current_nd_element != NULL) && (usedVars != NULL))
+      {
+         current_node = (t_cflow_Node *) LDATA(current_nd_element);
+
+         /* test if we have to insert a store */
+         if (  (current_node->uses[0] != NULL)
+               && ((current_node->uses[0])->ID != REG_0) )
+         {
+            if (findElement(usedVars, current_node->uses[0]) != NULL)
+            {
+               usedVars = _insertStore(program, graph, current_block
+                     , current_node, current_node->uses[0], usedVars);
+            }
+         }
+         /* test if we have to insert a store */
+         if (  (current_node->uses[1] != NULL)
+               && ((current_node->uses[1])->ID != REG_0) )
+         {
+            if (findElement(usedVars, current_node->uses[1]) != NULL)
+            {
+               usedVars = _insertStore(program, graph, current_block
+                     , current_node, current_node->uses[1], usedVars);
+            }
+         }
+         /* test if we have to insert a store */
+         if (  (current_node->uses[2] != NULL)
+               && ((current_node->uses[2])->ID != REG_0) )
+         {
+            if (findElement(usedVars, current_node->uses[2]) != NULL)
+            {
+               usedVars = _insertStore(program, graph, current_block
+                     , current_node, current_node->uses[2], usedVars);
+            }
+         }
+         /* test if we have to insert a store */
+         if (  (current_node->def != NULL)
+               && ((current_node->def)->ID != REG_0) )
+         {
+            if (findElement(usedVars, current_node->def) != NULL)
+            {
+               usedVars = _insertStore(program, graph, current_block
+                     , current_node, current_node->def, usedVars);
+            }
+         }
+         
+         /* retrieve the previous element */
+         current_nd_element = LPREV(current_nd_element);
+      }
+
+      current_bb_element = LNEXT(current_bb_element);
+   }
+
+   /* free the list `usedVars' */
+   freeList(usedVars);
+   
+   return graph;
+}
+
+void updatCflowInfos(t_program_infos *program, t_cflow_Graph *graph
+            , t_reg_allocator *RA, t_list *label_bindings)
+{
+   t_list *current_bb_element;
+   t_basic_block *current_block;
+   t_axe_instruction *current_instr;
+   t_list *current_nd_element;
+   t_cflow_Node *current_node;
+   int current_row;
+   int found;
+      
+   /* preconditions */
+   assert(program != NULL);
+   assert(graph != NULL);
+   assert(RA != NULL);
+   
+   /* initialize local variables */
+   current_row = 0;
+   found = 0;
+   
+   current_bb_element = graph->blocks;
+   while (current_bb_element != NULL)
+   {
+      int counter;
+      int assignedRegisters[RA_MIN_REG_NUM][3];
+
+      current_block = (t_basic_block *) LDATA(current_bb_element);
+      assert(current_block != NULL);
+
+      /* initialize used_Registers */
+      for (counter = 0; counter < RA_MIN_REG_NUM; counter ++)
+      {
+         assignedRegisters[counter][0] = REG_INVALID; /* invalid register */
+         assignedRegisters[counter][1] = 0;           /* need write back */
+         assignedRegisters[counter][2] = 0;           /* currently used */
+      }
+
+      /* retrieve the list of nodes for the current basic block */
+      current_nd_element = current_block->nodes;
+      while(current_nd_element != NULL)
+      {
+         int used_Registers[3] = {-1, -1, -1};
+
+         /* retrieve the data associated with the current node of the block */
+         current_node = (t_cflow_Node *) LDATA(current_nd_element);
+
+         /* fetch the current instruction */
+         current_instr = current_node->instr;
+
+         /* Test if a requested variable is already loaded into a register */
+         if (current_instr->reg_1  != NULL)
+         {
+            if (RA->bindings[(current_instr->reg_1)->ID]
+                  == RA_SPILL_REQUIRED)
+            {
+               int current_row = 0;
+               int found = 0;
+               
+               while ((current_row < RA_MIN_REG_NUM) && !found)
+               {
+                  if (assignedRegisters[current_row][0]
+                           == (current_instr->reg_1)->ID)
+                  {
+                     /* update the value of used_Register */
+                     used_Registers[0] = current_row;
+
+                     /* update the value of `assignedRegisters` */
+                     /* set currently used flag */
+                     assignedRegisters[current_row][2] = 1;
+
+                     /* test if a write back is needed */
+                     if (! (current_instr->reg_1)->indirect)
+                     {
+                        /* if the current instruction is a STORE we don't need
+                         * to write back the value of reg_1 again in memory. */
+                        /* Also if the current instruction is a WRITE instruction
+                         * we don't have to set the flag "dirty" for the
+                         * register assignedRegisters[current_row], since reg_1
+                         * is "used" but not "defined" */
+                        if (  (current_instr->opcode != STORE)
+                              && (current_instr->opcode != AXE_WRITE) )
+                        {
+                           assignedRegisters[current_row][1] = 1;
+                        }
+                        /* if the current instruction is a STORE we have to
+                         * notify that the write back is happened by
+                         * resetting the flag "dirty" */
+                        if (current_instr->opcode == STORE)
+                           assignedRegisters[current_row][1] = 0;
+                     }
+
+                     /* notify that the value was found */
+                     found = 1;
+                  }
+
+                  current_row ++;
+               }
+            }
+         }
+         if (current_instr->reg_2  != NULL)
+         {
+            if (RA->bindings[(current_instr->reg_2)->ID]
+                  == RA_SPILL_REQUIRED)
+            {
+               int current_row = 0;
+               int found = 0;
+               
+               while ((current_row < RA_MIN_REG_NUM) && !found)
+               {
+                  if (assignedRegisters[current_row][0]
+                           == (current_instr->reg_2)->ID)
+                  {
+                     /* update the value of used_Register */
+                     used_Registers[1] = current_row;
+
+                     /* update the value of `assignedRegisters` */
+                     /* set currently used flag */
+                     assignedRegisters[current_row][2] = 1;
+
+                     /* notify that the value was found */
+                     found = 1;
+                  }
+                  
+                  current_row ++;
+               }
+            }
+         }
+         if (current_instr->reg_3  != NULL)
+         {
+            if (RA->bindings[(current_instr->reg_3)->ID]
+                  == RA_SPILL_REQUIRED)
+            {
+               int current_row = 0;
+               int found = 0;
+               
+               while ((current_row < RA_MIN_REG_NUM) && !found)
+               {
+                  if (assignedRegisters[current_row][0]
+                           == (current_instr->reg_3)->ID)
+                  {
+                     /* update the value of used_Register */
+                     used_Registers[2] = current_row;
+
+                     /* update the value of `assignedRegisters` */
+                     /* set currently used flag */
+                     assignedRegisters[current_row][2] = 1;
+
+                     /* notify that the value was found */
+                     found = 1;
+                  }
+                  
+                  current_row ++;
+               }
+            }
+         }
+         /* phase two */
+         if (current_instr->reg_2  != NULL)
+         {
+            if ((RA->bindings[(current_instr->reg_2)->ID]
+                  == RA_SPILL_REQUIRED) && (used_Registers[1] == -1))
+            {
+               int current_row = 0;
+               int found = 0;
+               
+               while ((current_row < RA_MIN_REG_NUM) && !found)
+               {
+                  if (assignedRegisters[current_row][2] == 0)
+                  {
+                     int register_found = current_row + NUM_REGISTERS
+                           + 1 - RA_MIN_REG_NUM;
+                     
+                     if (assignedRegisters[current_row][1] == 1)
+                     {
+                        /* NEED WRITE BACK */
+                        _insertStoreSpill(program, assignedRegisters[current_row][0]
+                              , register_found, graph, current_block
+                                    , current_node, label_bindings, 1);
+                     }
+
+                     _insertLoadSpill(program, (current_instr->reg_2)->ID
+                           , register_found, graph, current_block
+                                , current_node, label_bindings, 1);
+
+                     /* update the control informations */
+                     assignedRegisters[current_row][0] = (current_instr->reg_2)->ID;
+                     assignedRegisters[current_row][1] = 0;
+                     assignedRegisters[current_row][2] = 1;
+                     used_Registers[1] = current_row;
+
+                     found = 1;
+                  }
+                  
+                  current_row ++;
+               }
+               assert(found != 0);
+            }
+         }
+         if (current_instr->reg_3  != NULL)
+         {
+            if ((RA->bindings[(current_instr->reg_3)->ID]
+                  == RA_SPILL_REQUIRED) && (used_Registers[2] == -1))
+            {
+               int current_row = 0;
+               int found = 0;
+
+               if ((current_instr->reg_3)->ID == (current_instr->reg_2)->ID)
+               {
+                  used_Registers[2] = used_Registers[1];
+                  found = 1;
+               }
+
+               while ((current_row < RA_MIN_REG_NUM) && !found)
+               {
+                  if (assignedRegisters[current_row][2] == 0)
+                  {
+                     int register_found = current_row + NUM_REGISTERS
+                           + 1 - RA_MIN_REG_NUM;
+                     
+                     if (assignedRegisters[current_row][1] == 1)
+                     {
+                        /* NEED WRITE BACK */
+                        _insertStoreSpill(program, assignedRegisters[current_row][0]
+                              , register_found, graph, current_block
+                                    , current_node, label_bindings, 1);
+                     }
+
+                     _insertLoadSpill(program, (current_instr->reg_3)->ID
+                           , register_found, graph, current_block
+                                , current_node, label_bindings, 1);
+
+                     /* update the control informations */
+                     assignedRegisters[current_row][0] = (current_instr->reg_3)->ID;
+                     assignedRegisters[current_row][1] = 0;
+                     assignedRegisters[current_row][2] = 1;
+                     used_Registers[2] = current_row;
+                     
+                     found = 1;
+                  }
+                  
+                  current_row ++;
+               }
+            }
+         }
+         if (current_instr->reg_1  != NULL)
+         {
+            if ((RA->bindings[(current_instr->reg_1)->ID]
+                  == RA_SPILL_REQUIRED) && (used_Registers[0] == -1))
+            {
+               int current_row = 0;
+               int found = 0;
+               
+               while ((current_row < RA_MIN_REG_NUM) && !found)
+               {
+                  if (assignedRegisters[current_row][2] == 0)
+                  {
+                     int register_found = current_row + NUM_REGISTERS
+                           + 1 - RA_MIN_REG_NUM;
+                     
+                     if (assignedRegisters[current_row][1] == 1)
+                     {
+                        /* NEED WRITE BACK */
+                        _insertStoreSpill(program, assignedRegisters[current_row][0]
+                              , register_found, graph, current_block
+                                    , current_node, label_bindings, 1);
+                     }
+
+                     /* test if we need to load the value from register */
+                     if (  (current_instr->reg_1)->indirect
+                           || (current_instr->opcode == AXE_WRITE))
+                     {
+                        _insertLoadSpill(program, (current_instr->reg_1)->ID
+                              , register_found, graph, current_block
+                                    , current_node, label_bindings, 1);
+                     }
+
+                     /* update the control informations */
+                     assignedRegisters[current_row][0] = (current_instr->reg_1)->ID;
+                     
+                     if (! (current_instr->reg_1)->indirect)
+                     {
+                        if (  (current_instr->opcode != STORE)
+                              && (current_instr->opcode != AXE_WRITE) )
+                        {
+                           assignedRegisters[current_row][1] = 1;
+                        }
+                        if (current_instr->opcode == STORE)
+                           assignedRegisters[current_row][1] = 0;
+                     }
+                     assignedRegisters[current_row][2] = 1;
+
+                     used_Registers[0] = current_row;
+                     
+                     found = 1;
+                  }
+                  
+                  current_row ++;
+               }
+               assert(found != 0);
+            }
+         }
+         
+         /* update the instruction informations */
+         if (current_instr->reg_1 != NULL)
+         {
+            if (used_Registers[0] != -1)
+            {
+               current_instr->reg_1->ID = used_Registers[0] + NUM_REGISTERS
+                           + 1 - RA_MIN_REG_NUM;
+
+               assignedRegisters[used_Registers[0]][2] = 0;
+            }
+            else
+               current_instr->reg_1->ID =
+                     RA->bindings[(current_instr->reg_1)->ID];
+         }
+         if (current_instr->reg_2 != NULL)
+         {
+            if (used_Registers[1] != -1)
+            {
+               current_instr->reg_2->ID = used_Registers[1] + NUM_REGISTERS
+                           + 1 - RA_MIN_REG_NUM;
+               assignedRegisters[used_Registers[1]][2] = 0;
+            }
+            else
+               current_instr->reg_2->ID =
+                     RA->bindings[(current_instr->reg_2)->ID];
+         }
+         if (current_instr->reg_3 != NULL)
+         {
+            if (used_Registers[2] != -1)
+            {
+               current_instr->reg_3->ID = used_Registers[2] + NUM_REGISTERS
+                           + 1 - RA_MIN_REG_NUM;
+               assignedRegisters[used_Registers[2]][2] = 0;
+            }
+            else
+               current_instr->reg_3->ID =
+                     RA->bindings[(current_instr->reg_3)->ID];
+         }
+
+
+         /* retrieve the previous element */
+         current_nd_element = LNEXT(current_nd_element);
+      }
+
+      /* initialize used_Registers */
+      for (counter = 0; counter < RA_MIN_REG_NUM; counter ++)
+      {
+         if (assignedRegisters[counter][1] == 1)
+         {
+            /* NEED WRITE BACK */
+            _insertStoreSpill(program, assignedRegisters[counter][0]
+                     , (counter + NUM_REGISTERS + 1 - RA_MIN_REG_NUM)
+                           , graph, current_block
+                              , current_node, label_bindings, 1);
+         }
+      }
+      
+      /* retrieve the next basic block element */
+      current_bb_element = LNEXT(current_bb_element);
+   }
+}
+
+int _insertStoreSpill(t_program_infos *program, int temp_register, int selected_register
+            , t_cflow_Graph *graph, t_basic_block *current_block
+            , t_cflow_Node *current_node, t_list *labelBindings, int before)
+{
+   t_axe_instruction *storeInstr;
+   t_axe_instruction *current_instr;
+   t_cflow_Node *storeNode;
+   t_list *elementFound;
+   t_tempLabel pattern;
+   t_tempLabel *tlabel;
+
+   /* initialize current_instr */
+   current_instr = current_node->instr;
+
+   pattern.regID = temp_register;
+   elementFound = CustomfindElement (labelBindings
+               , &pattern, compareTempLabels);
+
+   if (elementFound == NULL) {
+      finalizeNode(storeNode);
+      errorcode = AXE_TRANSFORM_ERROR;
+      return -1;
+   }
+
+   tlabel = (t_tempLabel *) LDATA(elementFound);
+   assert(tlabel != NULL);
+
+   /* create a store instruction */
+   storeInstr = _createUnary (program
+            , selected_register, tlabel->labelID, STORE);
+
+   /* test if an error occurred */
+   if (errorcode != AXE_OK) {
+      free_Instruction(storeInstr);
+      return -1;
+   }
+
+   /* create a node for the load instruction */
+   storeNode = allocNode (graph, storeInstr);
+   if (cflow_errorcode != CFLOW_OK) {
+      finalizeNode(storeNode);
+      free_Instruction(storeInstr);
+      errorcode = AXE_TRANSFORM_ERROR;
+      return -1;
+   }
+
+   /* test if we have to insert the node `storeNode' before `current_node'
+    * inside the basic block */
+   if (before == 0)
+      insertNodeAfter(current_block, current_node, storeNode);
+   else
+      insertNodeBefore(current_block, current_node, storeNode);
+   
+   return 0;
+}
+
+int _insertLoadSpill(t_program_infos *program, int temp_register, int selected_register
+            , t_cflow_Graph *graph, t_basic_block *block
+            , t_cflow_Node *current_node, t_list *labelBindings, int before)
+{
+   t_axe_instruction *loadInstr;
+   t_axe_instruction *current_instr;
+   t_cflow_Node *loadNode;
+   t_list *elementFound;
+   t_tempLabel pattern;
+   t_tempLabel *tlabel;
+
+   /* initialize current_instr */
+   current_instr = current_node->instr;
+
+   pattern.regID = temp_register;
+   elementFound = CustomfindElement (labelBindings
+               , &pattern, compareTempLabels);
+
+   if (elementFound == NULL) {
+      finalizeNode(loadNode);
+      errorcode = AXE_TRANSFORM_ERROR;
+      return -1;
+   }
+
+   tlabel = (t_tempLabel *) LDATA(elementFound);
+   assert(tlabel != NULL);
+      
+   /* create a load instruction */
+   loadInstr = _createUnary (program
+            , selected_register, tlabel->labelID, LOAD);
+
+   /* test if an error occurred */
+   if (errorcode != AXE_OK) {
+      free_Instruction(loadInstr);
+      finalizeNode(loadNode);
+      return -1;
+   }
+
+   /* update the value of storeInstr and instr */
+   (loadInstr->reg_1)->ID = selected_register;
+
+   /* create a node for the load instruction */
+   loadNode = allocNode (graph, loadInstr);
+
+   /* test if an error occurred */
+   if (cflow_errorcode != CFLOW_OK) {
+      finalizeNode(loadNode);
+      free_Instruction(loadInstr);
+      errorcode = AXE_TRANSFORM_ERROR;
+      return -1;
+   }
+
+   if ((current_node->instr)->labelID != NULL)
+   {
+      /* modify the label informations */
+      loadInstr->labelID = (current_node->instr)->labelID;
+      (current_node->instr)->labelID = NULL;
+   }
+                  
+   if (before == 1)
+      /* insert the node `loadNode' before `current_node' */
+      insertNodeBefore(block, current_node, loadNode);
+   else
+      insertNodeAfter(block, current_node, loadNode);
+
+   return 0;
+}

+ 28 - 0
acse/axe_transform.h

@@ -0,0 +1,28 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * axe_transform.h
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#ifndef _AXE_TRANSFORM_H
+#define _AXE_TRANSFORM_H
+
+#include "axe_engine.h"
+#include "axe_cflow_graph.h"
+#include "axe_reg_alloc.h"
+
+/* once executed the liveness analysis, by calling this function
+ * we will obtain a graph with the correct load and store
+ * instructions */
+extern t_cflow_Graph * insertLoadAndStoreInstr
+         (t_program_infos *program, t_cflow_Graph *graph);
+
+/* update the instructions within the control flow graph with the
+ * informations retrieved from the register allocation */
+extern void updateProgramInfos(t_program_infos *program
+         , t_cflow_Graph *graph, t_reg_allocator *RA);
+         
+#endif

+ 297 - 0
acse/axe_utils.c

@@ -0,0 +1,297 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * axe_utils.c
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#include <stdio.h>
+#include "axe_utils.h"
+#include "axe_gencode.h"
+#include "symbol_table.h"
+#include "axe_labels.h"
+#include "axe_cflow_graph.h"
+#include "axe_reg_alloc.h"
+#include "axe_io_manager.h"
+#include "axe_errors.h"
+
+extern int errorcode;
+extern int line_num;
+extern int num_error;
+extern int num_warning;
+extern t_program_infos *program;
+extern t_cflow_Graph *graph;
+extern t_reg_allocator *RA;
+extern t_io_infos *file_infos;
+
+static void free_new_variables(t_list *variables)
+{
+   t_list *current_element;
+   t_axe_declaration *current_decl;
+
+   /* preconditions */
+   assert(variables != NULL);
+
+   /* initialize the value of `current_element' */
+   current_element = variables;
+   while(current_element != NULL)
+   {
+      current_decl = (t_axe_declaration *) LDATA(current_element);
+      if (current_decl != NULL)
+         _AXE_FREE_FUNCTION(current_decl);
+
+      current_element = LNEXT(current_element);
+   }
+
+   /* free the memory associated with the list `variables' */
+   freeList(variables);
+}
+
+void set_new_variables(t_program_infos *program
+            , int varType, t_list *variables)
+{
+   t_list *current_element;
+   t_axe_declaration *current_decl;
+   int counter;
+
+   /* preconditions */
+   if (program == NULL){
+      free_new_variables(variables);
+      notifyError(AXE_PROGRAM_NOT_INITIALIZED);
+   }
+   
+   /* initialize `current_element' */
+   current_element = variables;
+   counter = 1;
+
+   while (current_element != NULL)
+   {
+      /* retrieve the current declaration infos */
+      current_decl = (t_axe_declaration *) LDATA(current_element);
+      if (current_decl == NULL) {
+         free_new_variables(variables);
+         notifyError(AXE_NULL_DECLARATION);
+      }
+
+      /* create and assign a new variable to program */
+      createVariable(program, current_decl->ID, varType, current_decl->isArray
+            , current_decl->arraySize, current_decl->init_val);
+
+      /* update the value of `current_element' */
+      current_element = LNEXT(current_element);
+   }
+
+   /* free the linked list */
+   /* initialize `current_element' */
+   current_element = variables;
+
+   while (current_element != NULL)
+   {
+      /* retrieve the current declaration infos */
+      current_decl = (t_axe_declaration *) LDATA(current_element);
+
+      /* assertion -- must always be verified */
+      assert(current_decl != NULL);
+
+      /* add a load instruction for each declared variable
+       * that is not an array type */
+      if (!(current_decl->isArray))
+         get_symbol_location(program, current_decl->ID, 0);
+
+      /* free the memory associated with the current declaration */
+      _AXE_FREE_FUNCTION(current_decl);
+
+      /* update the value of `current_element' */
+      current_element = LNEXT(current_element);
+   }
+
+   freeList(variables);
+}
+
+int get_symbol_location(t_program_infos *program, char *ID, int genLoad)
+{
+   int sy_error;
+   int location;
+
+   /* preconditions: ID and program shouldn't be NULL pointer */
+   if (ID == NULL)
+      notifyError(AXE_VARIABLE_ID_UNSPECIFIED);
+
+   if (program == NULL)
+      notifyError(AXE_PROGRAM_NOT_INITIALIZED);
+   
+   /* get the location of the symbol with the given ID */
+   location = getLocation(program->sy_table, ID, &sy_error);
+   if (sy_error != SY_TABLE_OK)
+      notifyError(AXE_INVALID_VARIABLE);
+
+   /* verify if the variable was previously loaded into
+   * a register. This check is made by looking to the
+   * value of `location'.*/
+   if (location == REG_INVALID)
+   {
+      /* we have to load the variable with the given
+      * identifier (ID) */
+      t_axe_label *label;
+      int sy_errorcode;
+
+      /* retrieve the label associated with ID */
+      label = getLabelFromVariableID(program, ID);
+
+      /* fetch an unused register where to store the
+       * result of the load instruction */
+      location = getNewRegister(program);
+
+      /* assertions */
+      assert(location != REG_INVALID);
+      assert(  (label != NULL)
+               && (label->labelID != LABEL_UNSPECIFIED) );
+      
+      /* load the value of IDENTIFIER from the
+       * given label to a register */
+      if (genLoad)
+         gen_load_instruction(program, location, label, 0);
+
+      /* update the symbol table */
+      sy_errorcode = setLocation(program->sy_table, ID, location);
+
+      if (sy_errorcode != SY_TABLE_OK)
+         notifyError(AXE_SY_TABLE_ERROR);
+
+#ifndef NDEBUG
+      /* get the location of the symbol with the given ID */
+      location = getLocation(program->sy_table, ID, &sy_error);
+#endif
+   }
+
+   /* test the postconditions */
+   assert(location != REG_INVALID);
+
+   return location;
+}
+
+int is_int16(int immediate) {
+  return immediate < (1 << 15) && immediate >= -(1 << 15);
+}
+
+int is_int20(int immediate) {
+  return immediate < (1 << 19) && immediate >= -(1 << 19);
+}
+
+void gen_move_immediate(t_program_infos *program, int dest, int immediate)
+{
+   if (is_int20(immediate)) {
+     /* immediate fits in a a 20-bit signed integer */
+     gen_mova_instruction(program, dest, NULL, immediate);
+   } else {
+     /* immediate does not fit in a 20-bit signed integer */
+     int lo = (immediate << 16) >> 16;
+     int hi = (immediate - lo) >> 16;
+
+     gen_addi_instruction(program, dest, REG_0, hi);
+     gen_shli_instruction(program, dest, dest, 16);
+     gen_addi_instruction(program, dest, dest, lo);
+   }
+}
+
+int gen_load_immediate(t_program_infos *program, int immediate)
+{
+   int imm_register;
+
+   imm_register = getNewRegister(program);
+
+   gen_move_immediate(program, imm_register, immediate);
+
+   return imm_register;
+}
+
+void set_end_Program(t_program_infos *program)
+{
+   if (program == NULL)
+      notifyError(AXE_PROGRAM_NOT_INITIALIZED);
+      
+   if (isAssignedLabel(program->lmanager))
+   {
+      gen_halt_instruction(program);
+      return;
+   }
+
+   if (program->instructions != NULL)
+   {
+      t_axe_instruction *last_instr;
+      t_list *last_element;
+
+      /* get the last element of the list */
+      last_element = getLastElement(program->instructions);
+      assert(last_element != NULL);
+
+      /* retrieve the last instruction */
+      last_instr = (t_axe_instruction *) LDATA(last_element);
+      assert(last_instr != NULL);
+
+      if (last_instr->opcode == HALT)
+         return;
+   }
+
+   gen_halt_instruction(program);
+   return;
+}
+
+void shutdownCompiler(int exitStatus)
+{
+#ifndef NDEBUG
+   fprintf(stdout, "Finalizing the compiler data structures.. \n");
+#endif
+   
+   /* shutdown the asm engine */
+   finalizeProgramInfos(program);
+   /* finalize the control flow graph informations */
+   finalizeGraph(graph);
+   /* finalize the register allocator */
+   finalizeRegAlloc(RA);
+   /* close all the files used by the compiler */
+   finalizeOutputInfos(file_infos);
+   
+#ifndef NDEBUG
+   fprintf(stdout, "Done. \n");
+#endif
+   
+   exit(exitStatus);
+}
+
+void init_compiler(int argc, char **argv)
+{
+
+#ifndef NDEBUG
+   fprintf(stdout, "Starting the compilation process. \n\n");
+#endif
+
+   /* initialize all the global variables */
+   errorcode = AXE_OK;
+   line_num = -1;
+   num_error = 0;
+   num_warning = 0;
+   program = NULL;
+   graph = NULL;
+   RA = NULL;
+   file_infos = NULL;
+
+#ifndef NDEBUG
+   fprintf(stdout, "Initialize the compiler internal data structures. \n");
+#endif
+   
+   /* initialize all the files used by the compiler */
+   file_infos = initializeOutputInfos(argc, argv);
+   if (file_infos == NULL)
+      errorcode = AXE_OUT_OF_MEMORY;
+
+   /* initialize the translation infos */
+   program = allocProgramInfos(&errorcode);
+   
+   /* initialize the line number */
+   line_num = 1;
+
+   checkConsistency();
+}

+ 70 - 0
acse/axe_utils.h

@@ -0,0 +1,70 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * axe_utils.h
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#ifndef _AXE_UTILS_H
+#define _AXE_UTILS_H
+
+#include "axe_engine.h"
+#include "axe_struct.h"
+#include "axe_constants.h"
+#include "collections.h"
+
+/* create a variable for each `t_axe_declaration' inside
+ * the list `variables'. Each new variable will be of type
+ * `varType'. */
+extern void set_new_variables(t_program_infos *program
+      , int varType, t_list *variables);
+
+/* Given a variable/symbol identifier (ID) this function
+ * returns a register location where the value is stored
+ * (the value of the variable identified by `ID').
+ * If the variable/symbol has never been loaded from memory
+ * to a register, first this function searches
+ * for a free register, then it assign the variable with the given
+ * ID to the register just found.
+ * Once computed, the location (a register identifier) is returned
+ * as output to the caller.
+ * This function generates a LOAD instruction
+ * only if the flag `genLoad' is set to 1; otherwise it simply reserve
+ * a register location for a new variable in the symbol table.
+ * If an error occurs, get_symbol_location returns a REG_INVALID errorcode */
+extern int get_symbol_location(t_program_infos *program
+         , char *ID, int genLoad);
+
+/* Generate the instruction to load an `immediate' value into a new register.
+ * It returns the new register identifier or REG_INVALID if an error occurs */
+extern int gen_load_immediate(t_program_infos *program, int immediate);
+
+/* Generate the instruction to move an `immediate' value into a register. */
+extern void gen_move_immediate(t_program_infos *program, int dest, int imm);
+
+/* Notify the end of the program. This function is directly called
+ * from the parser when the parsing process is ended */
+extern void set_end_Program(t_program_infos *program);
+
+/* Once called, this function destroys all the data structures
+ * associated with the compiler (program, RA, etc.). This function
+ * is typically automatically called before exiting from the main
+ * or when the compiler encounters some error. */
+extern void shutdownCompiler();
+
+/* Once called, this function initialize all the data structures
+ * associated with the compiler (program, RA etc..) and all the
+ * global variables in the system. This function
+ * is typically automatically called at the beginning of the main
+ * and should NEVER be called from the user code */
+extern void init_compiler(int argc, char **argv);
+
+/* Check whether an immediate is representable as a 16-bit signed integer. */
+extern int is_int16(int immediate);
+
+/* Check whether an immediate is representable as a 20-bit signed integer. */
+extern int is_int20(int immediate);
+
+#endif

+ 35 - 0
acse/cflow_constants.h

@@ -0,0 +1,35 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * cflow_constants.h
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#ifndef _CFLOW_CONSTANTS_H
+#define _CFLOW_CONSTANTS_H
+
+#define VAR_UNDEFINED -1
+
+/* if this macro is set to 1, the control flow analysis will consider
+ * R0 always as a LIVE IN temporary register (i.e. variable) */
+#define CFLOW_ALWAYS_LIVEIN_R0 1
+
+/* errorcodes */
+#define CFLOW_OK 0
+#define CFLOW_GRAPH_UNDEFINED 1
+#define CFLOW_INVALID_INSTRUCTION 2
+#define CFLOW_INVALID_NODE 3
+#define CFLOW_BBLOCK_UNDEFINED 4
+#define CFLOW_INVALID_BBLOCK 5
+#define CFLOW_INVALID_LABEL_FOUND 6
+#define CFLOW_NODE_UNDEFINED 7
+#define CFLOW_NODE_ALREADY_INSERTED 8
+#define CFLOW_BBLOCK_ALREADY_INSERTED 9
+#define CFLOW_INVALID_OPERATION 10
+#define CFLOW_INVALID_PROGRAM_INFO 11
+#define CFLOW_OUT_OF_MEMORY 12
+#define CFLOW_UNKNOWN ERROR -1
+
+#endif

+ 548 - 0
acse/collections.c

@@ -0,0 +1,548 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * collections.c
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include "collections.h"
+
+/* function prototypes */
+static t_list * newElement(void *data);
+
+
+/* remove the first element of the list. Returns the new
+ * head of the list */
+t_list * removeFirst(t_list *list)
+{
+   t_list *first_elem;
+   
+   if (list == NULL)
+      return NULL;
+
+   first_elem = list;
+   list = LNEXT(list);
+   if (list != NULL)
+      SET_PREV(list, NULL);
+   
+   _FREE_FUNCTION(first_elem);
+
+   /* postconditions: return the new head of the list */
+   return list;
+}
+
+/* add an element `data' to the list `list' at position `pos'. If pos is negative
+ * , or is larger than the number of elements in the list, the new element is
+ * added on to the end of the list. Function `addElement' returns a pointer
+ * to the new head of the list */
+t_list * addElement(t_list *list, void * data, int pos)
+{
+	t_list *result;
+	t_list *current_elem;
+	t_list *last_elem;
+	int	current_pos;
+	
+	/* initialize the value of `result' */
+	result = newElement(data);
+
+	if (list == NULL)
+		return result;
+	
+	if (pos == 0)
+	{
+		/* update the control informations */
+		SET_NEXT(result, list);
+		SET_PREV(list, result);
+		
+		/* return the new head of the list */
+		return result;
+	}
+	
+	/* retrieve the last element of the list */
+	last_elem = getLastElement(list);
+	assert(last_elem != NULL);
+	
+	if (pos < 0)
+	{
+		/* update the control informations */
+		SET_NEXT(last_elem, result);
+		SET_PREV(result, last_elem);
+		
+		/* update the value of result */
+		return list;
+	}
+	
+	/* `pos' is a positive integer */
+	current_pos = 0;
+	current_elem = list;
+	
+	while(current_pos < pos)
+	{
+		if (current_elem == last_elem)
+		{
+			/* update the control informations */
+			SET_NEXT(last_elem, result);
+			SET_PREV(result, last_elem);
+			
+			/* update the value of result */
+			return list;
+		}
+		
+		/* update the loop informations */
+		current_elem = LNEXT(current_elem);
+		current_pos++;
+	}
+
+	/* assertions */
+	assert(current_elem != NULL);
+	
+	/* update the control informations */
+	SET_NEXT(result, current_elem);
+	SET_PREV(result, LPREV(current_elem));
+	SET_NEXT(LPREV(current_elem), result);
+	SET_PREV(current_elem, result);
+	
+	/* return the new head of the list */
+	return list;
+}
+
+/* add an element at the beginning of the list */
+t_list * addFirst(t_list *list, void * data)
+{
+	t_list *result;
+	
+	/* initialize the value of `result' */
+	result = newElement(data);
+	
+	if (list == NULL)
+		return result;
+	
+	/* postconditions */
+	SET_PREV(list, result);
+	SET_NEXT(result, list);
+	
+	/* return the new head of the list */
+	return result;
+}
+
+/* add an element to the end of the list */
+t_list * addLast(t_list *list, void * data)
+{
+	/* call the `addElement' */
+	return addElement(list, data, -1);
+}
+
+/* remove an element from the list */
+t_list * removeElement(t_list *list, void * data)
+{
+	t_list *current_elem;
+	
+	/* preconditions: the list shouldn't be empty */
+	if (list == NULL)
+		return NULL;
+	
+	/* intialize the value of `current_elem' */
+	current_elem = list;
+	while (  (current_elem != NULL)
+			   && (LDATA(current_elem) != data))
+	{
+		current_elem = LNEXT(current_elem);
+	}
+	
+	/* the value hasn't been found */
+	if (current_elem == NULL)
+		return list;
+	
+	/* the value is found */
+	if (LPREV(current_elem) != NULL)
+	{
+		SET_NEXT(LPREV(current_elem), LNEXT(current_elem));
+		if (LNEXT(current_elem) != NULL)
+			SET_PREV(LNEXT(current_elem), LPREV(current_elem));
+		
+		_FREE_FUNCTION(current_elem);
+	}
+	else
+	{
+		/* check the preconditions */
+		assert(list == current_elem);
+		
+		if (LNEXT(current_elem) != NULL)
+      {
+			SET_PREV(LNEXT(current_elem), NULL);
+			
+         /* update the new head of the list */
+		   list = LNEXT(current_elem);
+      }
+      else
+         list = NULL;
+		
+		_FREE_FUNCTION(current_elem);
+	}
+	
+	/* postconditions: return the new head of the list */
+	return list;
+}
+
+/* remove all the elements of a list */
+void freeList(t_list *list)
+{
+	/* verify the preconditions */
+	if (list == NULL)
+		return;
+
+	/* recursively call the freeList */
+	freeList(LNEXT(list));
+	
+	/* deallocate memory for the current element of the list */
+	_FREE_FUNCTION(list);
+}
+
+t_list * newElement(void *data)
+{
+	t_list * result;
+	
+	/* create an instance of t_list in memory */
+	result = (t_list *) _ALLOC_FUNCTION(sizeof(t_list));
+
+   /* verify the out of memory condition */
+   if (result == NULL)
+   {
+      fprintf(stderr, "COLLECTIONS.C:: _ALLOC_FUNCTION returned a NULL pointer \n");
+      abort();
+   }
+
+	/* set the internal value of the just created t_list element */
+	SET_DATA(result, data);
+	SET_PREV(result, NULL);
+	SET_NEXT(result, NULL);
+	
+	/* postconditions : return the element */
+	return result;
+}
+
+t_list * getLastElement(t_list *list)
+{
+	/* preconditions */
+	if (list == NULL)
+		return NULL;
+	
+	/* test if the current element is the last element of the list */
+	if (LNEXT(list) == NULL)
+		return list;
+	
+	/* recursively call the getLastElement on the next item of the list */
+	return getLastElement(LNEXT(list));
+}
+
+/* remove a link from the list `list' */
+extern t_list * removeElementLink(t_list *list, t_list *element)
+{
+	t_list *current_elem;
+	
+	/* preconditions */
+	if (list == NULL || element == NULL)
+		return list;
+	
+	if ((LPREV(element) == NULL) && (element != list))
+		return list;
+	
+	/* intialize the value of `current_elem' */
+	current_elem = list;
+	while(	(LDATA(current_elem) != LDATA(element))
+			|| (LPREV(current_elem) != LPREV(element))
+			|| (LNEXT(current_elem) != LNEXT(element)) )
+	{
+		/* retrieve the next element from the list */
+		current_elem = LNEXT(current_elem);
+		
+		/* test if we reached the end of the list */
+		if (current_elem == NULL)
+			return list;
+	}
+
+   if (LPREV(element) == NULL)
+   {
+      assert(list == element);
+      
+      if (LNEXT(element) != NULL)
+      {
+         list = LNEXT(element);
+         SET_PREV(LNEXT(element), NULL);
+      }
+      else
+         list = NULL;
+
+      /* remove the allocated memory of element */
+      _FREE_FUNCTION(element);
+      return list;
+   }
+   
+	/* we found the element */
+	if (LPREV(element) != NULL)
+	{
+		/* we found the element, and it is the top of the list */
+		SET_NEXT(LPREV(element), LNEXT(element));
+	}
+	
+	if (LNEXT(element) != NULL)
+		SET_PREV(LNEXT(element), LPREV(element));
+	
+	/* remove the allocated memory of element */
+	_FREE_FUNCTION(element);
+	
+	/* return the new top of the list */
+	return list;
+}
+
+/* find an element inside the list `list'. The current implementation calls the
+ * CustomfindElement' passing a NULL reference as `func' */
+t_list * findElement(t_list *list, void *data)
+{
+	t_list *current_elem;
+	
+	/* if the list is empty returns a NULL pointer */
+	if (list == NULL)
+		return NULL;
+
+	/* intialize the value of `current_elem' */
+	current_elem = list;
+	while (	(current_elem != NULL)
+			&& (	LDATA(current_elem) != data) )
+	{
+		current_elem = LNEXT(current_elem);
+	}
+	
+	/* postconditions */
+	return current_elem;
+}
+
+/* find an element inside the list `list'. */
+t_list * CustomfindElement(t_list *list, void *data
+		, int (*compareFunc)(void *a, void *b))
+{
+	t_list *current_elem;	
+	
+	/* preconditions */
+	if (compareFunc == NULL)
+		return findElement(list, data);
+	
+	if (list == NULL)
+		return NULL;
+	
+	/* intialize the value of `current_elem' */
+	current_elem = list;
+	while (current_elem != NULL)
+	{
+      void *other_Data;
+
+      other_Data = LDATA(current_elem);
+
+      if (compareFunc(other_Data, data))
+         break;
+      
+		current_elem = LNEXT(current_elem);
+	}	
+
+	/* postconditions */
+	return current_elem;
+}
+
+int getPosition(t_list *list, t_list *element)
+{
+	int counter;
+	
+	/* preconditions */
+	if (list == NULL || element == NULL)
+		return -1;
+	
+	/* initialize the local variable `counter' */
+	counter = 0;
+	
+	if (list == element)
+		return counter;
+	
+	/* update values */
+	counter++;
+	list = LNEXT(list);
+	
+	while (list != NULL)
+	{
+		if (list == element)
+			return counter;
+		
+		counter++;
+		list = LNEXT(list);
+	}
+	
+	return -1;
+}
+
+int getLength(t_list *list)
+{
+	int counter;
+	
+   /* initialize the local variable `counter' */
+   counter = 0;
+
+   /* precondition */
+	if (list == NULL)
+		return counter;
+	
+	while (list != NULL)
+	{
+		counter++;
+		list = LNEXT(list);
+	}
+	
+	/* postconditions: return the length of the list */
+	return counter;
+}
+
+t_list * cloneList(t_list *list)
+{
+   t_list *result;
+   t_list *current_element;
+
+   /* initialize the local variables */
+   result = NULL;
+   current_element = list;
+
+   /* preconditions */
+   if (current_element == NULL)
+      return result;
+
+   while(current_element != NULL)
+   {
+      /* add an element to the new list */
+      result = addElement(result, LDATA(current_element), -1);
+
+      /* retrieve the next element of the list */
+      current_element = LNEXT(current_element);
+   }
+
+   /* return the new list */
+   return result;
+}
+
+t_list * getElementAt(t_list *list, unsigned int position)
+{
+   t_list *result;
+   t_list *current_element;
+   unsigned int current_pos;
+   
+   if (list == NULL)
+      return NULL;
+
+   /* initialize the local variables */
+   result = NULL;
+   current_element = list;
+   current_pos = 0;
+   while((current_element != NULL) && (current_pos < position))
+   {
+      current_element = LNEXT(current_element);
+      current_pos++;
+   }
+
+   /* return the element at the requested position */
+   return current_element;
+}
+
+t_list * addList(t_list *list, t_list *elements)
+{
+   t_list *current_element;
+   void *current_data;
+
+   /* if the list of elements is null, this function
+    * will return `list' unmodified */
+   if (elements == NULL)
+      return list;
+
+   /* initialize the value of `current_element' */
+   current_element = elements;
+   while (current_element != NULL)
+   {
+      /* retrieve the data associated with the current element */
+      current_data = LDATA(current_element);
+      list = addElement(list, current_data, -1);
+
+      /* retrieve the next element in the list */
+      current_element = LNEXT(current_element);
+   }
+
+   /* return the new list */
+   return list;
+}
+
+t_list * addListToSet(t_list *list, t_list *elements
+      , int (*compareFunc)(void *a, void *b), int *modified)
+{
+   t_list *current_element;
+   void *current_data;
+
+   /* if the list of elements is NULL returns the current list */
+   if (elements == NULL)
+      return list;
+
+   /* initialize the value of `current_element' */
+   current_element = elements;
+   while (current_element != NULL)
+   {
+      /* retrieve the data associated with the current element */
+      current_data = LDATA(current_element);
+
+      /* Test if the element was already inserted. */
+      if (CustomfindElement(list, current_data, compareFunc) == NULL)
+      {
+         list = addElement(list, current_data, -1);
+         if (modified != NULL)
+            (* modified) = 1;
+      }
+
+      /* retrieve the next element in the list */
+      current_element = LNEXT(current_element);
+   }
+
+   /* return the new list */
+   return list;
+}
+
+/* add sorted */
+t_list * addSorted(t_list *list, void * data
+            , int (*compareFunc)(void *a, void *b))
+{
+   t_list *current_element;
+   void *current_data;
+   int counter;
+   
+   /* preconditions */
+   if (list == NULL)
+      return addFirst(list, data);
+
+   counter = 0;
+   current_element = list;
+   while(current_element != NULL)
+   {
+      /* get the current interval informations */
+      current_data = LDATA(current_element);
+      assert(current_data != NULL);
+
+      if (compareFunc(current_data, data) >= 0)
+      {
+         list = addElement(list, data, counter);
+         return list;
+      }
+         
+      /* retrieve the next element */
+      current_element = LNEXT(current_element);
+
+      /* update the value of counter */
+      counter++;
+   }
+
+   return addElement(list, data, -1);
+}

+ 102 - 0
acse/collections.h

@@ -0,0 +1,102 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * collections.h
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#ifndef _COLLECTIONS_H
+#define _COLLECTIONS_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+/* macros */
+#define LNEXT(item) ((item)->next)
+#define LPREV(item) ((item)->prev)
+#define LDATA(item) ((item)->data)
+#define SET_DATA(item, _data) ((item)->data = (_data))
+#define SET_NEXT(item, _next) ((item)->next = (_next))
+#define SET_PREV(item, _prev) ((item)->prev = (_prev))
+#ifndef _ALLOC_FUNCTION
+#	define _ALLOC_FUNCTION malloc
+#endif
+#ifndef _FREE_FUNCTION
+#	define _FREE_FUNCTION free
+#endif
+
+/* a list element */
+typedef struct t_list
+{
+	void	*data;
+	struct t_list *next;
+	struct t_list *prev;
+}t_list;
+
+
+/* add an element `data' to the list `list' at position `pos'. If pos is negative
+ * , or is larger than the number of elements in the list, the new element is
+ * added on to the end of the list. Function `addElement' returns a pointer
+ * to the new head of the list */
+extern t_list * addElement(t_list *list, void * data, int pos);
+
+/* add sorted */
+extern t_list * addSorted(t_list *list, void * data
+            , int (*compareFunc)(void *a, void *b));
+
+/* add an element to the end of the list */
+extern t_list * addLast(t_list *list, void * data);
+
+/* add an element at the beginning of the list */
+extern t_list * addFirst(t_list *list, void * data);
+
+/* remove an element at the beginning of the list */
+extern t_list * removeFirst(t_list *list);
+
+/* remove an element from the list */
+extern t_list * removeElement(t_list *list, void * data);
+
+/* remove a link from the list `list' */
+extern t_list * removeElementLink(t_list *list, t_list *element);
+
+/* find an element inside the list `list'. The current implementation calls the
+ * CustomfindElement' passing a NULL reference as `func' */
+extern t_list * findElement(t_list *list, void *data);
+
+/* find an element inside the list `list'. */
+extern t_list * CustomfindElement(t_list *list, void *data
+            , int (*compareFunc)(void *a, void *b));
+
+/* find the position of an `element' inside the `list'. -1 if not found */
+extern int getPosition(t_list *list, t_list *element);
+
+/* find the length of `list' */
+extern int getLength(t_list *list);
+
+/* remove all the elements of a list */
+extern void freeList(t_list *list);
+
+/* get the last element of the list. Returns NULL if the list is empty
+ * or list is a NULL pointer */
+extern t_list * getLastElement(t_list *list);
+
+/* retrieve the list element at position `position' inside the `list'.
+ * Returns NULL if: the list is empty, the list is a NULL pointer or
+ * the list holds less than `position' elements. */
+extern t_list * getElementAt(t_list *list, unsigned int position);
+
+/* create a new list with the same elements */
+extern t_list * cloneList(t_list *list);
+
+/* add a list of elements to another list */
+extern t_list * addList(t_list *list, t_list *elements);
+
+/* add a list of elements to a set */
+extern t_list * addListToSet(t_list *list, t_list *elements
+      , int (*compareFunc)(void *a, void *b), int *modified);
+
+
+#endif

+ 28 - 0
acse/reg_alloc_constants.h

@@ -0,0 +1,28 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * reg_alloc_constants.h
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#ifndef _REG_ALLOC_CONSTANTS_H
+#define _REG_ALLOC_CONSTANTS_H
+
+/* minimum number of registers of the target machine */
+#define RA_MIN_REG_NUM 3
+
+/* constants */
+#define RA_SPILL_REQUIRED -1
+#define RA_REGISTER_INVALID 0
+#define RA_EXCLUDED_VARIABLE 0
+
+/* errorcodes */
+#define RA_OK 0
+#define RA_INVALID_ALLOCATOR 1
+#define RA_INVALID_INTERVAL 2
+#define RA_INTERVAL_ALREADY_INSERTED 3
+#define RA_INVALID_NUMBER_OF_REGISTERS 4
+
+#endif

+ 24 - 0
acse/sy_table_constants.h

@@ -0,0 +1,24 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * sy_table_constants.h
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#ifndef _SY_TABLE_CONSTANTS_H
+#define _SY_TABLE_CONSTANTS_H
+
+/* invalid location info */
+#define SY_LOCATION_UNSPECIFIED -1
+
+/* errorcodes */
+#define SY_TABLE_OK 0
+#define SY_ALREADY_DEFINED -1
+#define SY_UNDEFINED -2
+#define SY_TABLE_NOT_INITIALIZED -3
+#define SY_MEMALLOC_ERROR -4
+#define SY_INVALID_REQUEST -5
+
+#endif

+ 368 - 0
acse/symbol_table.c

@@ -0,0 +1,368 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * symbol_table.c
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include "symbol_table.h"
+#include "axe_debug.h"
+#include "collections.h"
+#include "axe_labels.h"
+
+/* symbol table */
+
+struct t_symbol_table
+{
+   t_list *symbols;
+};
+
+static int symCompare (void *symA, void *symB);
+static int regCompare (void *symA, void *symB);
+static t_symbol * getSymFromID(t_symbol_table *table, char *ID);
+static t_symbol * getSymFromLocation(t_symbol_table *table, int location);
+
+
+char * getIDfromLocation(t_symbol_table *table, int location, int *errorcode)
+{
+   t_symbol *sym;
+
+   /* preconditions */
+   if (table == NULL) {
+      if (errorcode != NULL)
+         (* errorcode) =  SY_TABLE_NOT_INITIALIZED;
+      return NULL;
+   }
+
+   if (location == REG_INVALID) {
+      if (errorcode != NULL)
+         (* errorcode) =  SY_INVALID_REQUEST;
+      return NULL;
+   }
+
+   /* retrieve the symbol from the location info. */
+   sym = getSymFromLocation(table, location);
+   if (sym == NULL)
+      return NULL;
+
+   /* postconditions */
+   assert(sym->ID != NULL);
+
+   return sym->ID;
+}
+
+int getTypeFromID(t_symbol_table *table, char *ID, int type)
+{
+   t_symbol *found;
+   
+   /* test the preconditions */
+   if (ID == NULL)
+      return SY_LOCATION_UNSPECIFIED;
+
+   /* search for the symbol with the given ID */
+   found = getSymFromID(table, ID);
+
+   /* test the postconditions */
+   if (found == NULL)
+      return SY_LOCATION_UNSPECIFIED;
+
+   /* return the value of the `reg_location' field for the found symbol */
+   return found->reg_location;
+}
+
+int getLocation(t_symbol_table *table, char *ID, int *errorcode)
+{
+   t_symbol *found;
+   
+   /* test the preconditions */
+   if (ID == NULL)
+   {
+      if (errorcode != NULL)
+      {
+         (* errorcode) = SY_INVALID_REQUEST;
+         return SY_LOCATION_UNSPECIFIED;
+      }
+   }
+
+   /* search for the symbol with the given ID */
+   found = getSymFromID(table, ID);
+
+   /* test the postconditions */
+   if (found == NULL)
+   {
+      if (errorcode != NULL)
+      {
+         (* errorcode) = SY_UNDEFINED;
+         return SY_LOCATION_UNSPECIFIED;
+      }
+   }
+
+   if (errorcode != NULL)
+      (* errorcode) = SY_TABLE_OK;
+   
+   /* return the value of the `reg_location' field for the found symbol */
+   return found->reg_location;
+}
+
+int setLocation(t_symbol_table *table, char *ID, int reg)
+{
+   t_symbol *found;
+   
+   /* test the preconditions */
+   if (ID == NULL)
+      return SY_INVALID_REQUEST;
+
+   /* search for the symbol with the given ID */
+   found = getSymFromID(table, ID);
+
+   /* test the postconditions */
+   if (found == NULL)
+      return SY_UNDEFINED;
+
+   /* set the `reg_location' field for the found symbol */
+   found->reg_location = reg;
+
+   return SY_TABLE_OK;
+}
+
+/* initialize the symbol table */
+t_symbol_table * initialize_sy_table()
+{
+   t_symbol_table *result;
+
+   /* create an instance of `t_symbol_tabel' */
+   result = (t_symbol_table *) malloc(sizeof(t_symbol_table));
+   if (result == NULL)
+      return NULL;
+
+   /* initialize the internal data associated with the symbol table */
+   result->symbols = NULL;
+
+   /* return the symbol table */
+   return result;
+}
+
+int finalize_sy_table(t_symbol_table *table)
+{
+   t_list   *current_symbol;
+   
+   if (table == NULL)
+      return SY_TABLE_NOT_INITIALIZED;
+
+   /* initialize the value of current_symbol */
+   current_symbol = table->symbols;
+
+   while (current_symbol != NULL)
+   {
+      /* free the symbol */
+      free(LDATA(current_symbol));
+
+      /* select the new symbol */
+      current_symbol = LNEXT(current_symbol);
+   }
+   
+   /* deallocate memory for the sy_table */
+   freeList(table->symbols);
+
+   /* update the global variable sy_table */
+   table->symbols = NULL;
+
+   /* free the memory slot associated with the symbol table */
+   free(table);
+   
+   return SY_TABLE_OK;
+}
+
+static int regCompare (void *symA, void *symB)
+{
+   t_symbol *sA;
+   t_symbol *sB;
+         
+   /* preconditions */
+   if (symA == NULL)
+   {
+      if (symB == NULL)
+         return 1;
+      return 0;
+   }
+
+   if (symB == NULL)
+      return 0;
+
+   sA = (t_symbol *) symA;
+   sB = (t_symbol *) symB;
+
+   return (sA->reg_location == sB->reg_location);
+}
+
+/* Function used when a compare is needed between two labels */
+int symCompare (void *symA, void *symB)
+{
+   t_symbol *sA;
+   t_symbol *sB;
+         
+   /* preconditions */
+   if (symA == NULL)
+   {
+      if (symB == NULL)
+         return 1;
+      return 0;
+   }
+
+   if (symB == NULL)
+      return 0;
+
+   sA = (t_symbol *) symA;
+   sB = (t_symbol *) symB;
+
+   assert(sA->ID != NULL);
+   assert(sB->ID != NULL);
+
+   return (!strcmp(sA->ID, sB->ID));
+}
+
+/* put a symbol into the symbol table */
+int putSym(t_symbol_table *table, char *ID, int type)
+{
+   t_symbol pattern;
+   t_symbol *new_symbol;
+   
+   if (table == NULL)
+      return SY_TABLE_NOT_INITIALIZED;
+
+   if (table->symbols == NULL)
+   {
+      /* initialize pattern */
+      pattern.ID = ID;
+
+      /* verify if the symbol is valid */
+      if (  CustomfindElement(table->symbols
+                  , &pattern, symCompare) != NULL)
+      {
+         /* symbol already defined */
+         return SY_ALREADY_DEFINED;
+      }
+   }
+   
+   /* add the new symbol to the symbol table */
+   new_symbol = (t_symbol *) malloc(sizeof(t_symbol));
+
+   /* verify if new_symbol is a valid pointer */
+   if (new_symbol == NULL)
+   {
+      /* out of memory error */
+      return SY_MEMALLOC_ERROR;
+   }
+   
+   /* initialize the new symbol */
+   new_symbol->ID = ID;
+   new_symbol->type = type;
+   new_symbol->reg_location = SY_LOCATION_UNSPECIFIED;
+
+   /* add the new symbol to the symbol table */
+   table->symbols = addElement(table->symbols, new_symbol, -1);
+
+   return SY_TABLE_OK;
+}
+
+t_symbol * getSymFromLocation(t_symbol_table *table, int location)
+{
+   t_symbol pattern;
+   t_symbol *symbol_found;
+   t_list   *l_element;
+   
+   /* preconditions */
+   if (table == NULL)
+      return NULL;
+
+   /* initialize pattern */
+   pattern.reg_location = location;
+
+   /* search for a symbol with the given ID */
+   l_element = CustomfindElement(table->symbols, &pattern, regCompare);
+
+   /* postconditions */
+   if (l_element == NULL)
+      return NULL;
+
+   /* retrieve the symbol information */
+   symbol_found = (t_symbol *) LDATA(l_element);
+
+   /* return the symbol */
+   return symbol_found;
+}
+
+/* retrieve informations about a symbol */
+t_symbol * getSymFromID(t_symbol_table *table, char *ID)
+{
+   t_symbol pattern;
+   t_symbol *symbol_found;
+   t_list   *l_element;
+   
+   /* preconditions */
+   if (table == NULL)
+      return NULL;
+
+   /* initialize pattern */
+   pattern.ID = ID;
+
+   /* search for a symbol with the given ID */
+   l_element = CustomfindElement(table->symbols, &pattern, symCompare);
+
+   /* postconditions */
+   if (l_element == NULL)
+      return NULL;
+
+   /* retrieve the symbol information */
+   symbol_found = (t_symbol *) LDATA(l_element);
+
+   /* return the symbol */
+   return symbol_found;
+}
+
+#ifndef NDEBUG
+/* This function print out to the file `fout' the content of the
+ * symbol table given as input. The resulting text is formatted in
+ * the following way: <ID> -- <TYPE> -- <REGISTER> */
+void printSymbolTable(t_symbol_table *table, FILE *fout)
+{
+   t_list *current_element;
+   t_symbol *current_symbol;
+   
+   /* preconditions */
+   if (table == NULL)
+      return;
+
+   if (fout == NULL)
+      fout = stdin;
+
+   fprintf(fout, "--------------------------------\n");
+   fprintf(fout, "          SYMBOL TABLE\n");
+   fprintf(fout, "--------------------------------\n");
+   fprintf(fout, "NUMBER OF SYMBOLS : %d \n"
+            , getLength(table->symbols));
+   fprintf(fout, "--------------------------------\n\n");
+
+   /* initialize the value of current_symbol */
+   current_element = table->symbols;
+
+   while (current_element != NULL)
+   {
+      current_symbol = (t_symbol *) LDATA(current_element);
+
+      fprintf(fout, "ID : %s\t;; TYPE : %s\t;;", current_symbol->ID
+         , dataTypeToString(current_symbol->type) );
+      if (current_symbol->reg_location == SY_LOCATION_UNSPECIFIED)
+         fprintf(fout, " LOCATION : [UNSPECIFIED] \n");
+      else
+         fprintf(fout, " LOCATION : R%d \n", current_symbol->reg_location);
+      
+      /* select the new symbol */
+      current_element = LNEXT(current_element);
+   }
+}
+#endif

+ 67 - 0
acse/symbol_table.h

@@ -0,0 +1,67 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * symbol_table.h
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#ifndef _SYMBOL_TABLE_H
+#define _SYMBOL_TABLE_H
+
+#include <stdio.h>
+#include "sy_table_constants.h"
+
+struct t_symbol_table;
+
+/* Typedef for the struct t_symbol_table */
+typedef struct t_symbol_table t_symbol_table;
+
+/* a symbol inside the sy_table. An element of the symbol table is composed by
+ * three fields: <ID>, <type> and <Location>.
+ * `ID' is a not-NULL string that is used as key identifier for a symbol
+ * inside the table.
+ * `type' is an integer value that is used to determine the correct type
+ * of a symbol. Valid values for `type' are defined into "sy_table_constants.h".
+ * `reg_location' refers to a register location (i.e. which register contains
+ * the value of `ID'). */
+typedef struct
+{
+   char *ID;            /* symbol identifier */
+   int type;            /* type associated with the symbol */
+   int reg_location;    /* a register location */
+}t_symbol;
+
+/* put a symbol into the symbol table */
+extern int putSym(t_symbol_table *table, char *ID, int type);
+
+/* set the location of the symbol with ID as identifier */
+extern int setLocation(t_symbol_table *table, char *ID, int reg);
+
+/* get the location of the symbol with the given ID */
+extern int getLocation(t_symbol_table *table, char *ID, int *errorcode);
+
+/* get the type associated with the symbol with ID as identifier */
+extern int getTypeFromID(t_symbol_table *table, char *ID, int type);
+
+/* initialize the symbol table */
+extern t_symbol_table * initialize_sy_table();
+
+/* finalize the symbol table */
+extern int finalize_sy_table(t_symbol_table *table);
+
+/* given a register identifier (location), it returns the ID of the variable
+ * stored inside the register `location'. This function returns NULL
+ * if the location is an invalid location. */
+extern char * getIDfromLocation(t_symbol_table *table
+            , int location, int *errorcode);
+
+#ifndef NDEBUG
+/* This function print out to the file `fout' the content of the
+ * symbol table given as input. The resulting text is formatted in
+ * the following way: <ID> -- <TYPE> -- <REGISTER> */
+extern void printSymbolTable(t_symbol_table *table, FILE *fout);
+#endif
+
+#endif

+ 25 - 0
assembler/Makefile

@@ -0,0 +1,25 @@
+project = ../bin/asm
+objects = assembler.tab.c lex.yy.c
+hfiles = $(wildcard *.h)
+cfiles = $(filter-out $(objects), $(wildcard *.c))
+
+.PHONY: all clean
+
+all: $(project)
+
+$(project) : $(objects) $(cfiles) $(hfiles)
+	gcc -o $@ $(objects) $(cfiles)
+
+assembler.tab.c : assembler.y 
+	bison -d $<
+
+lex.yy.c : assembler.lex assembler.tab.h
+	flex $<
+
+clean :
+	rm -f assembler.tab.c assembler.tab.h lex.yy.c $(project) $(project:=.exe)
+
+# This rule keeps Make happy, while the %.tab.h file is generated by
+#  the bison rule above
+%.tab.h: %.tab.c
+	if [ -a $@ ]; then touch $@; else false; fi

+ 118 - 0
assembler/asm_constants.h

@@ -0,0 +1,118 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * asm_constants.h
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#ifndef _ASM_CONSTANTS
+#define _ASM_CONSTANTS
+
+/* the size of an instruction (in bytes) */
+#define ASM_INSTRUCTION_SIZE 4
+
+/* the size of a word (in bytes) */
+#define ASM_WORD_SIZE 4
+
+/* alignment information */
+#define ASM_ALIGMENT_SIZE 4
+
+/* invalid memory offset */
+#define ASM_INVALID_MEMORY_OFFSET -1
+
+/* opcodes pseudo-M68000 */
+#define ADD_OP	0
+#define SUB_OP 1
+#define ANDL_OP 2	
+#define ORL_OP 3	
+#define XORL_OP 4
+#define ANDB_OP 5
+#define ORB_OP 6
+#define XORB_OP 7
+#define MUL_OP 8
+#define DIV_OP 9
+#define SHL_OP 10
+#define SHR_OP 11
+#define ROTL_OP 12
+#define ROTR_OP 13
+#define NEG_OP 14
+#define SPCL_OP 15
+#define ADDI_OP 16
+#define SUBI_OP 17
+#define ANDLI_OP 18
+#define ORLI_OP 19
+#define XORLI_OP 20
+#define ANDBI_OP 21
+#define ORBI_OP 22
+#define XORBI_OP 23
+#define MULI_OP 24
+#define DIVI_OP 25
+#define SHLI_OP 26
+#define SHRI_OP 27
+#define ROTLI_OP 28
+#define ROTRI_OP 29
+#define NOTL_OP 30
+#define NOTB_OP 31
+#define NOP_OP 32
+#define MOVA_OP 33
+#define JSR_OP 34
+#define RET_OP 35
+#define HALT_OP 36
+#define BT_OP 37
+#define BF_OP 38
+#define BHI_OP 39
+#define BLS_OP 40
+#define BCC_OP 41
+#define BCS_OP 42
+#define BNE_OP 43
+#define BEQ_OP 44
+#define BVC_OP 45
+#define BVS_OP 46
+#define BPL_OP 47
+#define BMI_OP 48
+#define BGE_OP 49
+#define BLT_OP 50
+#define BGT_OP 51
+#define BLE_OP 52
+#define SEQ_OP 53
+#define SGE_OP 54
+#define SGT_OP 55
+#define SLE_OP 56
+#define SLT_OP 57
+#define SNE_OP 58
+#define LOAD_OP 59
+#define STORE_OP 60
+#define READ_OP 61
+#define WRITE_OP 62
+#define INVALID_OPCODE -1
+
+/* error codes */
+#define ASM_OK 0
+#define ASM_NOT_INITIALIZED_INFO 1
+#define ASM_UNDEFINED_INSTRUCTION 2
+#define ASM_INVALID_LABEL_FOUND 3
+#define ASM_LABEL_ALREADY_PRESENT 4
+#define ASM_UNDEFINED_DATA 5
+#define ASM_INVALID_DATA_FORMAT 6
+#define ASM_FOPEN_ERROR 7
+#define ASM_INVALID_INPUT_FILE 8
+#define ASM_FWRITE_ERROR 9
+#define ASM_FCLOSE_ERROR 10
+#define ASM_CODE_NOT_PRESENT 11
+#define ASM_OUT_OF_MEMORY 12
+#define ASM_INVALID_OPCODE 13
+#define ASM_UNKNOWN_ERROR 14
+
+/* instruction formats */
+#define ASM_FORMAT_TER	0
+#define ASM_FORMAT_BIN	1
+#define ASM_FORMAT_UNR	2
+#define ASM_FORMAT_JMP	3
+#define ASM_FORMAT_NULL	4
+
+/* data formats */
+#define ASM_WORD	0
+#define ASM_SPACE 1
+#endif

+ 107 - 0
assembler/asm_debug.c

@@ -0,0 +1,107 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * asm_debug.c
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#include "asm_debug.h"
+
+/* convert the integer code of `dataType' into a string */
+char * dataType_toString(int dataType)
+{
+   if (dataType == ASM_WORD)
+      return ".WORD";
+   if (dataType == ASM_SPACE)
+      return ".SPACE";
+   return "<UNKNOWN>";
+}
+
+char * dataFormat_toString(int dataFormat)
+{
+   if (dataFormat == ASM_FORMAT_TER)
+      return "TERNARY";
+   if (dataFormat == ASM_FORMAT_BIN)
+      return "BINARY";
+   if (dataFormat == ASM_FORMAT_UNR)
+      return "UNARY";
+   if (dataFormat == ASM_FORMAT_JMP)
+      return "JUMP";
+   if (dataFormat == ASM_FORMAT_NULL)
+      return "NULL";
+   return "<UNKNOWN_FORMAT>";
+}
+
+char * opcode_toString(int opcode)
+{
+   switch(opcode)
+   {
+      case ADD_OP : return "ADD";
+      case SUB_OP : return "SUB";
+      case ANDL_OP : return "ANDL";
+      case ORL_OP : return "ORL";
+      case XORL_OP : return "XORL";
+      case ANDB_OP : return "ANDB";
+      case ORB_OP : return "ORB";
+      case XORB_OP : return "XORB";
+      case MUL_OP : return "MUL";
+      case DIV_OP : return "DIV";
+      case SHL_OP : return "SHL";
+      case SHR_OP : return "SHR";
+      case ROTL_OP : return "ROTL";
+      case ROTR_OP : return "ROTR";
+      case NEG_OP : return "NEG";
+      case SPCL_OP : return "SPCL";
+      case ADDI_OP : return "ADDI";
+      case SUBI_OP : return "SUBI";
+      case ANDLI_OP : return "ANDLI";
+      case ORLI_OP : return "ORLI";
+      case XORLI_OP : return "XORLI";
+      case ANDBI_OP : return "ANDBI";
+      case ORBI_OP : return "ORBI";
+      case XORBI_OP : return "XORBI";
+      case MULI_OP : return "MULI";
+      case DIVI_OP : return "DIVI";
+      case SHLI_OP : return "SHLI";
+      case SHRI_OP : return "SHRI";
+      case ROTLI_OP : return "ROTLI";
+      case ROTRI_OP : return "ROTRI";
+      case NOTL_OP : return "NOTL";
+      case NOTB_OP : return "NOTB";
+      case NOP_OP : return "NOP";
+      case MOVA_OP : return "MOVA";
+      case JSR_OP : return "JSR";
+      case RET_OP : return "RET";
+      case HALT_OP : return "HALT";
+      case BT_OP : return "BT";
+      case BF_OP : return "BF";
+      case BHI_OP : return "BHI";
+      case BLS_OP : return "BLS";
+      case BCC_OP : return "BCC";
+      case BCS_OP : return "BCS";
+      case BNE_OP : return "BNE";
+      case BEQ_OP : return "BEQ";
+      case BVC_OP : return "BVC";
+      case BVS_OP : return "BVS";
+      case BPL_OP : return "BPL";
+      case BMI_OP : return "BMI";
+      case BGE_OP : return "BGE";
+      case BLT_OP : return "BLT";
+      case BGT_OP : return "BGT";
+      case BLE_OP : return "BLE";
+      case SEQ_OP : return "SEQ";
+      case SGE_OP : return "SGE";
+      case SGT_OP : return "SGT";
+      case SLE_OP : return "SLE";
+      case SLT_OP : return "SLT";
+      case SNE_OP : return "SNE";
+      case LOAD_OP : return "LOAD";
+      case STORE_OP : return "STORE";
+      case READ_OP : return "READ";
+      case WRITE_OP : return "WRITE";
+      default : return "<INVALID_OPCODE>";
+      
+   }
+}

+ 19 - 0
assembler/asm_debug.h

@@ -0,0 +1,19 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * asm_debug.h
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#ifndef _ASM_DEBUG_H
+#define _ASM_DEBUG_H
+
+#include "asm_constants.h"
+
+extern char * dataType_toString(int dataType);
+extern char * dataFormat_toString(int dataFormat);
+extern char * opcode_toString(int opcode);
+
+#endif

+ 788 - 0
assembler/asm_engine.c

@@ -0,0 +1,788 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * asm_engine.c
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "asm_engine.h"
+#include "asm_debug.h"
+
+/* Function used when a compare is needed between two labels */
+static int compareLabels (void *labelA, void *labelB);
+
+/* Function used to produce the header of an object file.
+* This function returns ASM_OK if everything went good*/
+static int print_header_infos(FILE *fp);
+
+/* Function that translates every code and data segment.
+* This function returns ASM_OK if everything went good */
+static int translateCode(t_translation_infos *infos, FILE *fp);
+
+/* This function translates a single instruction found into the
+* code segment. Returns ASM_OK if everything went good */
+static int translateInstruction(t_translation_infos *infos
+      , t_asm_instruction *inst, FILE *fp);
+
+/* This function translates a single block of data found into a
+* data segment. Returns ASM_OK if everything went good */
+static int translateData(t_translation_infos *infos
+      , t_asm_data *inst, FILE *fp);
+
+/* The function `getBinaryOpcode' returns the coded opcode that will
+* be stored into the object file */
+static int getBinaryOpcode(int opcode);
+
+/* This function returns the index of the given instruction/data
+* that is stored inside the macro block of code plus data  */
+static int getInstructionOrDataIndex(t_translation_infos *infos, void *target);
+
+/* this function is directly called from `finalizeStructures'. The main
+ * goal of this function is: free all the memory associated with the
+ * labels */
+static void finalizeLabels(t_list *labels);
+
+
+/* This function returns the index of the given instruction/data
+* that is stored inside the macro block of code plus data  */
+int getInstructionOrDataIndex(t_translation_infos *infos
+      , void *target)
+{
+   t_list	*target_element;
+   int position;
+
+   /* the list is empty */
+   if (infos->code == NULL)
+      return ASM_INVALID_MEMORY_OFFSET;
+   
+   /* preconditions: infos and inst MUST NOT be NULL references! */
+   target_element = findElement(infos->code, target);
+   if (target_element == NULL)
+      return ASM_INVALID_MEMORY_OFFSET;
+
+   /* retrieve the position of the statement */
+   position = getPosition(infos->code, target_element);
+
+   /* the code list doesn't hold target_element */
+   if (position == -1)
+      return ASM_INVALID_MEMORY_OFFSET;
+
+   /* return the displacement in bytes from the beginning
+    * of the instruction segment */
+   if (position < infos->codesize)
+      return ( ((position * ASM_INSTRUCTION_SIZE) / ASM_ALIGMENT_SIZE)
+            + ((((position *ASM_INSTRUCTION_SIZE)
+                     % ASM_ALIGMENT_SIZE) > 0)? 1:0) );
+   else
+   {
+      t_list *current_elem;
+      t_asm_data *current_data;
+      
+      int counter = 0;
+
+      current_elem = getElementAt(infos->code, infos->codesize);
+      assert(current_elem != NULL);
+
+      counter = ( ((infos->codesize * ASM_INSTRUCTION_SIZE) / ASM_ALIGMENT_SIZE)
+            + ((((infos->codesize * ASM_INSTRUCTION_SIZE)
+                     % ASM_ALIGMENT_SIZE) > 0)? 1:0) );
+
+      while (current_elem != NULL && LDATA(current_elem) != target)
+      {
+         current_data = LDATA(current_elem);
+
+         if (current_data->dataType == ASM_WORD)
+         {
+            counter += (ASM_WORD_SIZE / ASM_ALIGMENT_SIZE)
+                  + (((ASM_WORD_SIZE % ASM_ALIGMENT_SIZE) > 0)? 1 : 0);
+         }
+         else if (current_data->dataType == ASM_SPACE)
+         {
+            /* precondition always verified */
+            assert(current_data->value > 0);
+            counter += (current_data->value / ASM_ALIGMENT_SIZE)
+                  + (((current_data->value % ASM_ALIGMENT_SIZE) > 0)? 1: 0);
+         }
+
+         current_elem = LNEXT(current_elem);
+      }
+
+      return counter;
+   }
+
+   return -1;
+}
+
+/* this function translates a single block of data found into a
+* data segment. Returns ASM_OK if everything went good */
+int translateData(t_translation_infos *infos
+      , t_asm_data *data, FILE *fp)
+{
+   if (data == NULL)
+      return ASM_UNDEFINED_DATA;
+   
+   if (data->dataType == ASM_WORD)
+   {
+      /* postcondition: print on file the coded data */
+      if (fwrite(&(data->value), ASM_WORD_SIZE, 1, fp) != 1)
+         return ASM_FWRITE_ERROR;
+      return ASM_OK;
+   }
+   else if (data->dataType == ASM_SPACE)
+   {
+      char *zero_val;
+
+      /* preconditions: data->value must be >= 0 */
+      if (data->value < 0)
+         return ASM_INVALID_DATA_FORMAT;
+
+      /* force alignment to 4 bytes */
+      if (data->value % ASM_WORD_SIZE != 0)
+         data->value = data->value + (data->value % ASM_WORD_SIZE);
+
+      /* initialize the value `zero_val' */
+      zero_val = _ASM_ALLOC_FUNCTION(sizeof(char) * data->value);
+      if (zero_val == NULL)
+         return ASM_OUT_OF_MEMORY;
+
+      /* set the block of memory to zero */
+      memset(zero_val, 0, data->value);
+      
+      /* postcondition: print on file the coded data */
+      if (fwrite(zero_val, data->value, 1, fp) != 1)
+      {
+         _ASM_FREE_FUNCTION(zero_val);
+         return ASM_FWRITE_ERROR;
+      }
+
+      _ASM_FREE_FUNCTION(zero_val);
+      return ASM_OK;
+   }
+   
+   /* default: the data format in unknown */
+   return ASM_INVALID_DATA_FORMAT;
+}
+
+/* This function translates a single instruction found into the
+* code segment. Returns ASM_OK if everything went good */
+int translateInstruction(t_translation_infos *infos
+      , t_asm_instruction *inst, FILE *fp)
+{
+   int instruction;
+   int pattern;
+   int func;
+   
+   /* preconditions */
+   if (inst == NULL)
+      return ASM_UNDEFINED_INSTRUCTION;
+   
+   if (fp == NULL)
+      return ASM_INVALID_INPUT_FILE;
+   
+#ifndef NDEBUG
+   fprintf(stderr, "Coding instruction: [opcode == %s, format == %s] --> "
+                  , opcode_toString(inst->opcode)
+                           , dataFormat_toString(inst->format) );
+#endif
+   
+   /* initialize the instruction */
+   instruction = 0;
+
+   /* set the format of instruction */
+   if (inst->format == ASM_FORMAT_TER)
+   {
+      pattern = 0;
+   }
+   else if (inst->format == ASM_FORMAT_BIN)
+   {
+      pattern = (1 << 30);
+   }
+   else if  (   (inst->format == ASM_FORMAT_UNR)
+            || (inst->format == ASM_FORMAT_NULL) )
+   {
+      pattern = (1 << 31);
+   }
+   else
+   {
+      assert(inst->format == ASM_FORMAT_JMP);
+      pattern = (3 << 30);
+   }
+   
+   /* update the instruction format value */
+   instruction = pattern;
+   
+   /* initialize the opcode information */
+   pattern = getBinaryOpcode(inst->opcode);
+
+   /* test if the opcode is valid */
+   if (pattern == INVALID_OPCODE)
+      return ASM_INVALID_OPCODE;
+   
+   /* update the instruction format value */
+   instruction = instruction + (pattern << 26);
+   
+   /* initialize the value of `func' */
+   func = 0;
+   
+   if (inst->format == ASM_FORMAT_TER)
+   {
+      if ((inst->reg_1)->indirect)
+         func = 4;
+      if ((inst->reg_3)->indirect)
+         func = func + 8;
+      
+      instruction = instruction + ( ((inst->reg_1)->ID) << 21);
+      instruction = instruction + ( ((inst->reg_2)->ID) << 16);
+      instruction = instruction + ( ((inst->reg_3)->ID) << 11);
+      instruction = instruction + func;
+   }
+   else if (inst->format == ASM_FORMAT_BIN)
+   {
+      instruction = instruction + ( ((inst->reg_1)->ID) << 21);
+      instruction = instruction + ( ((inst->reg_2)->ID) << 16);
+      instruction = instruction + ( inst->immediate & 0x0000FFFF);
+   }
+   else if (inst->format == ASM_FORMAT_UNR)
+   {
+      instruction = instruction + ( ((inst->reg_1)->ID) << 21);
+      if ((inst->address)->label != NULL)
+      {
+         int destinationIndex;
+         
+         /* we have to retrieve the position of the requested data */
+         destinationIndex = getInstructionOrDataIndex
+                  (infos, ((inst->address)->label)->data);
+
+         /* test if the destinationIndex is a valid destination */
+         if (destinationIndex == ASM_INVALID_MEMORY_OFFSET)
+            return ASM_INVALID_LABEL_FOUND;
+         
+         /* update the displacement information */
+         instruction = instruction
+               + ( destinationIndex & 0x000FFFFF);
+      }
+      else
+      {
+         instruction = instruction + ( (inst->address)->addr & 0x000FFFFF);
+      }
+   }
+   else if (inst->format == ASM_FORMAT_NULL)
+   {
+      /* DOES NOTHING */
+   }
+   else
+   {
+      /* test a precondition */
+      assert(inst->format == ASM_FORMAT_JMP);
+      
+      if ((inst->address)->label != NULL)
+      {
+         int currentIndex;
+         int destinationIndex;
+         
+         /* we have to retrieve the displacement between this
+         * instruction and the instruction referred by the
+         * label */
+         currentIndex = getInstructionOrDataIndex(infos, inst);
+         destinationIndex = getInstructionOrDataIndex
+                  (infos, ((inst->address)->label)->data);
+         
+         /* test if the destinationIndex is a valid destination */
+         if (destinationIndex == ASM_INVALID_MEMORY_OFFSET)
+            return ASM_INVALID_LABEL_FOUND;
+         
+         /* postcondition that MUST be always verified */
+         assert(destinationIndex < infos->codesize);
+         
+         /* update the displacement information */
+         instruction = instruction
+               + ( (destinationIndex - currentIndex) & 0x000FFFFF);
+      }
+      else
+      {
+         instruction = instruction + ( (inst->address)->addr & 0x000FFFFF);
+      }
+   }
+   
+   /* postcondition: print on file the coded instruction */
+   if (fwrite(&instruction, 4, 1, fp) != 1)
+      return ASM_FWRITE_ERROR;
+
+#ifndef NDEBUG
+   fprintf(stderr, "Coded Instruction:\t[0x%08x] \n", instruction);
+#endif
+   return ASM_OK;
+}
+
+/* function used when a compare is needed between two labels */
+int compareLabels (void *labelA, void *labelB)
+{
+   t_asm_label *asm_labelA;
+   t_asm_label *asm_labelB;
+   
+   /* preconditions */
+   if (labelA == NULL)
+   {
+      if (labelB == NULL)
+         return 1;
+      return 0;
+   }
+   
+   if (labelB == NULL)
+      return 0;
+   
+   /* initialize labels */
+   asm_labelA = (t_asm_label *) labelA;
+   asm_labelB = (t_asm_label *) labelB;
+   
+   /* verify the consistency of this operation */
+   assert(asm_labelA->ID != NULL);
+   assert(asm_labelB->ID != NULL);
+
+   /* postcondition */
+   return (!strcmp(asm_labelA->ID, asm_labelB->ID));
+}
+
+/* create an instance of `t_translation_info' initializing the internal data
+* of every field of the structure */
+t_translation_infos * initStructures(int *errorcode)
+{
+   t_translation_infos *result;
+   
+   /* allocate memory for an instance of `t_translation_infos' */
+   result = _ASM_ALLOC_FUNCTION(sizeof(t_translation_infos));
+   
+   /* test the out of memory condition */
+   if (result == NULL)
+   {
+      /* update the value of `errorcode' */
+      (*errorcode) = ASM_OUT_OF_MEMORY;
+      return NULL;
+   }
+
+   /* no errors encountered so far */
+   (*errorcode) = ASM_OK;
+   
+   /* initialize the content of `result' */
+   result->code = NULL;
+   result->labels = NULL;
+   result->codesize = 0;
+   
+   /* return a new instance of `t_translation_infos' */
+   return result;
+}
+
+/* Insert an instruction inside the `code' list of `infos' */
+int addInstruction(t_translation_infos *infos
+      , t_asm_instruction *instruction)
+{
+   /* preconditions */
+   if (infos == NULL)
+      return ASM_NOT_INITIALIZED_INFO;
+   
+   if (instruction == NULL)
+      return ASM_UNDEFINED_INSTRUCTION;
+
+   /* update the list of instructions */
+   infos->code = addElement(infos->code, instruction, infos->codesize);
+   
+   /* update the codesize */
+   infos->codesize++;
+
+   /* notify that everything went correctly */
+   return ASM_OK;
+}
+
+/* Insert a new label. The label must be initialized externally */
+int insertLabel(t_translation_infos *infos, t_asm_label *label)
+{
+   /* preconditions */
+   if (infos == NULL)
+      return ASM_NOT_INITIALIZED_INFO;
+   
+   if (label == NULL)
+      return ASM_INVALID_LABEL_FOUND;
+   
+   /* update the list of labels */
+   infos->labels = addFirst(infos->labels, label);
+   
+   /* notify that everything went correctly */
+   return ASM_OK;
+}
+
+/* find a label with a given `ID' */
+t_asm_label * findLabel(t_translation_infos *infos, char *ID, int *asm_errorcode)
+{
+   t_asm_label pattern;
+   t_list *label_element;
+   
+   /* preconditions */
+   if (infos == NULL && asm_errorcode != NULL)
+      (*asm_errorcode) = ASM_NOT_INITIALIZED_INFO;
+   
+   if (ID == NULL && asm_errorcode != NULL)
+      (*asm_errorcode) = ASM_INVALID_LABEL_FOUND;
+   
+   /* initialize the value of `asm_errorcode' */
+   (*asm_errorcode) = ASM_OK;
+   
+   /* initialize `pattern' */
+   pattern.ID = ID;
+   pattern.data = NULL;
+
+   /* search the label */
+   label_element = CustomfindElement(infos->labels, &pattern, compareLabels);
+
+   /* if not found return a NULL pointer */
+   if (label_element == NULL)
+      return NULL;
+
+   /* return the label found */
+   return (t_asm_label *) LDATA(label_element);
+}
+
+/* remove a label */
+int removeLabel(t_translation_infos *infos, char *ID)
+{
+   t_asm_label *result;
+   int asm_errorcode;
+   
+   /* initialize the value of `asm_errorcode' */
+   asm_errorcode = ASM_OK;
+   
+   /* initialize the value of `result' */
+   result = findLabel(infos, ID, &asm_errorcode);
+   
+   /* postconditions */
+   if (result == NULL)
+      return asm_errorcode;
+   
+   /* remove the label from the list */
+   infos->labels = removeElement(infos->labels, result);
+   
+   return asm_errorcode;
+}
+
+/* add a block of data into the data segment */
+int addData(t_translation_infos *infos, t_asm_data *data)
+{
+   /* preconditions */
+   if (infos == NULL)
+      return ASM_NOT_INITIALIZED_INFO;
+   
+   if (data == NULL)
+      return ASM_UNDEFINED_DATA;
+   
+   /* update the list of instructions */
+   infos->code = addElement(infos->code, data, -1);
+
+   return ASM_OK;
+}
+
+/* finalization of the `infos' structure */
+int finalizeStructures(t_translation_infos *infos)
+{
+   if (infos == NULL)
+      return ASM_NOT_INITIALIZED_INFO;
+   
+   if (infos->code != NULL)
+   {
+      t_list *current_element;
+      t_asm_instruction *current_instr;
+
+      /* initialize `data' */
+      current_element = infos->code;
+      
+      while ((current_element != NULL) && (infos->codesize > 0) )
+      {
+         current_instr = (t_asm_instruction *) LDATA(current_element);
+         
+         /* free memory associated with the current instruction */
+         freeInstruction(current_instr);
+
+         /* update the value of `current_element' */
+         current_element = LNEXT(current_element);
+         infos->codesize --;
+      }
+
+      while (current_element != NULL)
+      {
+         /* free memory associated with the current data info. */
+         freeData((t_asm_data *) LDATA(current_element));
+         
+         /* update the value of `current_element' */
+         current_element = LNEXT(current_element);
+      }
+
+      /* free the code and data segment infos */
+      freeList(infos->code);
+   }
+   
+   /* remove labels */
+   finalizeLabels(infos->labels);
+   
+   /* free the memory block associated with `infos' */
+   _ASM_FREE_FUNCTION(infos);
+   
+   return ASM_OK;
+}
+
+/* begin the translation process */
+int asm_writeObjectFile(t_translation_infos *infos, char *output_file)
+{
+   FILE *fp;
+   int errorcode;
+
+   if (output_file == NULL)
+   {
+      /* set "output.o" as output file name */
+      output_file = "output.o";
+   }
+
+#ifndef NDEBUG
+   fprintf(stdout, "\n\n*******************************************\n");
+   fprintf(stdout, "INITIALIZE OUTPUT FILE: %s. \n", output_file);
+   fprintf(stdout, "CODE SEGMENT has a size of %d instructions \n", infos->codesize);
+   fprintf(stdout, "DATA SEGMENT has a size of %d elements \n"
+         , (getLength(infos->code) - infos->codesize) );
+   fprintf(stdout, "NUMBER OF LABELS : %d. \n", getLength(infos->labels));
+   fprintf(stdout, "*******************************************\n\n");
+#endif
+   
+   /* open a new file */
+   fp = fopen(output_file, "w");
+   if (fp == NULL)
+      return ASM_FOPEN_ERROR;
+   
+   /* print the header of the object file */
+   errorcode = print_header_infos(fp);
+   
+   if (errorcode != ASM_OK)
+   {
+      if (fclose(fp) == EOF)
+         return ASM_FCLOSE_ERROR;
+      return errorcode;
+   }
+   
+   /* print the code and data segment */
+   errorcode = translateCode(infos, fp);
+   if (errorcode != ASM_OK)
+   {
+      if (fclose(fp) == EOF)
+         return ASM_FCLOSE_ERROR;
+      return errorcode;
+   }
+
+   /* print the trailer informations */
+   //DOES NOTHING
+
+   /* close the file and return */
+   errorcode = fclose(fp);
+   if (errorcode == EOF)
+      return ASM_FCLOSE_ERROR;
+   
+   return ASM_OK;
+}
+
+/* Function that translates every code and data segment.
+* This function returns ASM_OK if everything went good */
+int translateCode(t_translation_infos *infos, FILE *fp)
+{
+   int instruction_counter;
+   t_list *current_instruction;
+   void *instruction_or_data;
+   int errorcode;
+   
+   /* unchecked preconditions: pf and infos are different from NULL */
+   
+   if (infos->code == NULL)
+      return ASM_CODE_NOT_PRESENT;
+   
+   /* initialize the instruction_counter */
+   instruction_counter = 0;
+   current_instruction = infos->code;
+   errorcode = ASM_OK;
+   
+   /* translate the instruction segment */
+   while (instruction_counter < infos->codesize)
+   {
+      instruction_or_data = LDATA(current_instruction);
+      assert(instruction_or_data != NULL);
+      
+      /* translate every single instruction */
+      errorcode = translateInstruction
+            (infos, (t_asm_instruction *) instruction_or_data, fp);
+
+      /* verify the errorcode */
+      if (errorcode != ASM_OK)
+         return errorcode;
+      
+      /* update the instruction counter and the current instruction data */
+      instruction_counter++;
+      current_instruction = LNEXT(current_instruction);
+   }
+
+#ifndef NDEBUG
+   fprintf(stderr, "\n");
+#endif
+   
+   /* translate the data segment */
+   while (current_instruction != NULL)
+   {
+      instruction_or_data = LDATA(current_instruction);
+      assert(instruction_or_data != NULL);
+      
+      /* translate every single element of data */
+#ifndef NDEBUG
+      fprintf(stderr, "Adding data into the data segment [datatype == %s \t; "
+            , dataType_toString(((t_asm_data *)instruction_or_data)->dataType) );
+      fprintf(stderr, "value == 0x%08x] \n"
+            , ((t_asm_data *)instruction_or_data)->value);
+#endif
+      
+      errorcode = translateData(infos, (t_asm_data *) instruction_or_data, fp);
+      
+      /* verify the errorcode */
+      if (errorcode != ASM_OK)
+         return errorcode;
+      
+      current_instruction = LNEXT(current_instruction);
+   }
+   
+#ifndef NDEBUG
+   fprintf(stderr, "\n");
+#endif
+
+   return ASM_OK;
+}
+
+/* Function used to produce the header of an object file.
+* This function returns ASM_OK if everything went good*/
+int print_header_infos(FILE *fp)
+{
+   char begin_header[4] = {'L', 'F', 'C', 'M'};
+   char other_data[16];
+
+   /* preconditions */
+   if (fp == NULL)
+      return ASM_INVALID_INPUT_FILE;
+   
+   /* write the starting string `LFCM' without the end of string '\0' */
+   fputc(begin_header[0], fp);
+   fputc(begin_header[1], fp);
+   fputc(begin_header[2], fp);
+   fputc(begin_header[3], fp);
+   
+   /* set `other_data' */
+   memset(other_data, 0, 16);
+   
+   /* write the other_data infos */
+   if (fwrite(other_data, 1, 16, fp) != 16)
+      return ASM_FWRITE_ERROR;
+   
+   return ASM_OK;
+}
+
+/* The function `getBinaryOpcode' returns the coded opcode that will
+* be stored into the object file */
+int getBinaryOpcode(int opcode)
+{
+   switch(opcode)
+   {
+      case ADD_OP: return 0;
+      case SUB_OP:  return 1;
+      case ANDL_OP: return 2;
+      case ORL_OP: return 3;
+      case XORL_OP: return 4;
+      case ANDB_OP: return 5;
+      case ORB_OP: return 6;
+      case XORB_OP: return 7;
+      case MUL_OP: return 8;
+      case DIV_OP: return 9;
+      case SHL_OP: return 10;
+      case SHR_OP: return 11;
+      case ROTL_OP: return 12;
+      case ROTR_OP: return 13;
+      case NEG_OP: return 14;
+      case SPCL_OP: return 15;
+      case ADDI_OP: return 0;
+      case SUBI_OP:  return 1;
+      case ANDLI_OP: return 2;
+      case ORLI_OP: return 3;
+      case XORLI_OP: return 4;
+      case ANDBI_OP: return 5;
+      case ORBI_OP: return 6;
+      case XORBI_OP: return 7;
+      case MULI_OP: return 8;
+      case DIVI_OP: return 9;
+      case SHLI_OP: return 10;
+      case SHRI_OP: return 11;
+      case ROTLI_OP: return 12;
+      case ROTRI_OP: return 13;
+      case NOTL_OP: return 14;
+      case NOTB_OP: return 15;
+      case NOP_OP: return 0;
+      case MOVA_OP: return 1;
+      case LOAD_OP: return 4;
+      case STORE_OP: return 5;
+      case JSR_OP: return 2;
+      case RET_OP: return 3;
+      case HALT_OP: return 6;
+      case SEQ_OP: return 7;
+      case SGE_OP: return 8;
+      case SGT_OP: return 9;
+      case SLE_OP: return 10;
+      case SLT_OP: return 11;
+      case SNE_OP: return 12;
+      case READ_OP: return 13;
+      case WRITE_OP: return 14;
+      case BT_OP: return 0;
+      case BF_OP: return 1;
+      case BHI_OP: return 2;
+      case BLS_OP: return 3;
+      case BCC_OP: return 4;
+      case BCS_OP: return 5;
+      case BNE_OP: return 6;
+      case BEQ_OP: return 7;
+      case BVC_OP: return 8;
+      case BVS_OP: return 9;
+      case BPL_OP: return 10;
+      case BMI_OP: return 11;
+      case BGE_OP: return 12;
+      case BLT_OP: return 13;
+      case BGT_OP: return 14;
+      case BLE_OP: return 15;
+      default: return INVALID_OPCODE;
+   }
+}
+
+void finalizeLabels(t_list *labels)
+{
+   t_list *current_element;
+   t_asm_label *current_label;
+   
+   if (labels == NULL)
+      return;
+
+   current_element = labels;
+   while(current_element != NULL)
+   {
+      current_label = (t_asm_label *) LDATA(current_element);
+      if (current_label != NULL)
+      {
+         if (current_label->ID != NULL)
+            free(current_label->ID);
+         _ASM_FREE_FUNCTION(current_label);
+      }
+      
+      current_element = LNEXT(current_element);
+   }
+
+   freeList(labels);
+}

+ 49 - 0
assembler/asm_engine.h

@@ -0,0 +1,49 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * asm_engine.h
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#ifndef _ASM_TRANSLATION
+#define _ASM_TRANSLATION
+
+#include "collections.h"
+#include "asm_struct.h"
+
+typedef struct
+{
+	t_list *code; /* the instruction+data segment */
+	t_list *labels; /* a set of asm_labels */
+	int codesize; /* the size of the instruction segment */
+}t_translation_infos;
+
+/* create an instance of `t_translation_info' initializing the internal data
+ * of every field of the structure */
+extern t_translation_infos * initStructures(int *errorcode);
+
+/* Insert an instruction inside the `code' list of `infos' */
+extern int addInstruction(t_translation_infos *infos
+		, t_asm_instruction *instruction);
+
+/* Insert a new label. The label must be initialized externally */
+extern int insertLabel(t_translation_infos *infos, t_asm_label *label);
+
+/* find a label with a given `ID' */
+extern t_asm_label * findLabel(t_translation_infos *infos, char *ID, int *asm_errorcode);
+
+/* remove a label */
+extern int removeLabel(t_translation_infos *infos, char *ID);
+
+/* add a block of data into the data segment */
+extern int addData(t_translation_infos *infos, t_asm_data *data);
+
+/* finalization of the `infos' structure */
+extern int finalizeStructures(t_translation_infos *infos);
+
+/* begin the translation process */
+extern int asm_writeObjectFile(t_translation_infos *infos, char *output_file);
+
+#endif

+ 262 - 0
assembler/asm_struct.c

@@ -0,0 +1,262 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * asm_struct.c
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#include "asm_struct.h"
+
+t_asm_register * allocRegister(int ID, int indirect)
+{
+	t_asm_register *result;
+	
+	result = _ASM_ALLOC_FUNCTION(sizeof(t_asm_register));
+   
+   /* test the out of memory condition */
+   if (result == NULL)
+      return NULL;
+	
+	/* set the fields of the instance of `t_asm_register' */
+	result->ID = ID;
+	result->indirect = indirect;
+	
+	/* postconditions */
+	return result;
+}
+
+t_asm_address * allocAddress(int displacement, t_asm_label *label)
+{
+	t_asm_address *result;
+	
+	result = _ASM_ALLOC_FUNCTION(sizeof(t_asm_address));
+	
+   /* test the out of memory condition */
+   if (result == NULL)
+      return NULL;
+   
+	/* set the fields of the instance of `t_asm_address' */
+	if (label == NULL)
+		result->addr = displacement;
+	else
+		result->addr = 0;
+	result->label = label;
+	
+	/* postconditions */
+	return result;
+}
+
+t_asm_label * allocLabel(char *ID, void *data)
+{
+	t_asm_label *result;
+	
+   result = _ASM_ALLOC_FUNCTION(sizeof(t_asm_label));
+	
+   /* test the out of memory condition */
+   if (result == NULL)
+      return NULL;
+
+	/* set the fields of the instance of `t_asm_label' */
+	result->data = data;
+	result->ID = ID;
+	
+	/* postconditions */
+	return result;
+}
+
+t_asm_instruction * allocInstruction(int opcode)
+{
+	t_asm_instruction *result;
+	
+	result = _ASM_ALLOC_FUNCTION(sizeof(t_asm_instruction));
+	
+   /* test the out of memory condition */
+   if (result == NULL)
+      return NULL;
+
+	/* set the fields of the instance of `t_asm_instruction' */
+	result->opcode = opcode;
+	result->reg_1 = NULL;
+	result->reg_2 = NULL;
+	result->reg_3 = NULL;
+	result->immediate = 0;
+	result->format = 0;
+	result->address = NULL;
+	result->user_comment = NULL;
+	
+	/* postconditions */
+	return result;
+}
+
+t_asm_instruction * init_opcode3(int opcode, t_asm_register *reg_1
+		, t_asm_register *reg_2, t_asm_register *reg_3)
+{
+	t_asm_instruction *result;
+	
+	/* create an instance of `t_asm_instruction' */
+	result = allocInstruction(opcode);
+
+   /* test `out of memory' */
+   if (result == NULL)
+      return NULL;
+
+	/* store the correct values for the instruction */
+	result->format = ASM_FORMAT_TER;
+	result->reg_1 = reg_1;
+	result->reg_2 = reg_2;
+	result->reg_3 = reg_3;
+	
+	/* postcondition: return the just created and initialized instance
+	 * of `t_asm_instruction' */
+	return result;
+}
+
+t_asm_instruction * init_opcode2(int opcode, t_asm_register *reg_1
+		, t_asm_register *reg_2, int immediate)
+{
+	t_asm_instruction *result;
+	
+	/* create an instance of `t_asm_instruction' */
+	result = allocInstruction(opcode);
+	
+   /* test `out of memory' */
+   if (result == NULL)
+      return NULL;
+
+	/* store the correct values for the instruction */
+	result->format = ASM_FORMAT_BIN;
+	result->reg_1 = reg_1;
+	result->reg_2 = reg_2;
+	result->immediate = immediate;
+	
+	/* postcondition: return the just created and initialized instance
+	 * of `t_asm_instruction' */
+	return result;
+}
+
+t_asm_instruction * init_opcodeI(int opcode, t_asm_register *reg_1
+		, t_asm_address *addr)
+{
+	t_asm_instruction *result;
+	
+	/* create an instance of `t_asm_instruction' */
+	result = allocInstruction(opcode);
+
+   /* test `out of memory' */
+   if (result == NULL)
+      return NULL;
+
+	/* store the correct values for the instruction */
+	result->format = ASM_FORMAT_UNR;
+	result->reg_1 = reg_1;
+	result->address = addr;
+	
+	/* postcondition: return the just created and initialized instance
+	 * of `t_asm_instruction' */
+	return result;
+}
+
+t_asm_instruction * init_ccode(int opcode, t_asm_address *addr)
+{
+	t_asm_instruction *result;
+	
+	/* create an instance of `t_asm_instruction' */
+	result = allocInstruction(opcode);
+	
+   /* test `out of memory' */
+   if (result == NULL)
+      return NULL;
+
+	/* store the correct values for the instruction */
+	result->format = ASM_FORMAT_JMP;
+	result->address = addr;
+	
+	/* postcondition: return the just created and initialized instance
+	 * of `t_asm_instruction' */
+	return result;
+}
+
+t_asm_instruction * init_halt()
+{
+	t_asm_instruction *result;
+	
+	/* create an instance of `t_asm_instruction' */
+	result = allocInstruction(HALT_OP);
+
+   /* test `out of memory' */
+   if (result == NULL)
+      return NULL;
+
+	/* store the correct values for the instruction */
+	result->format = ASM_FORMAT_NULL;
+	
+	/* postcondition: return the just created and initialized instance
+	 * of `t_asm_instruction' */
+	return result;
+}
+
+t_asm_instruction * init_nop()
+{
+   t_asm_instruction *result;
+   
+   /* create an instance of `t_asm_instruction' */
+   result = allocInstruction(NOP_OP);
+
+   /* test `out of memory' */
+   if (result == NULL)
+      return NULL;
+
+   /* store the correct values for the instruction */
+   result->format = ASM_FORMAT_NULL;
+   
+   /* postcondition: return the just created and initialized instance
+    * of `t_asm_instruction' */
+   return result;
+}
+
+
+t_asm_data * allocData(int dataType, int value)
+{
+	t_asm_data *result;
+	
+	result = _ASM_ALLOC_FUNCTION(sizeof(t_asm_data));
+
+   /* test the out of memory condition */
+   if (result == NULL)
+      return NULL;
+
+	/* initialize the fields of `result' */
+	result->dataType = dataType;
+	result->value = value;
+	
+	/* postconditions: return result */
+	return result;
+}
+
+void freeInstruction(t_asm_instruction *inst)
+{
+	/* preconditions */
+	if (inst == NULL)
+		return;
+	
+	/* free memory */
+	if (inst->reg_1 != NULL)
+		_ASM_FREE_FUNCTION(inst->reg_1);
+	if (inst->reg_2 != NULL)
+		_ASM_FREE_FUNCTION(inst->reg_2);
+	if (inst->reg_3 != NULL)
+		_ASM_FREE_FUNCTION(inst->reg_3);
+	if (inst->address != NULL)
+		_ASM_FREE_FUNCTION(inst->address);
+   
+	_ASM_FREE_FUNCTION(inst);
+}
+
+/* finalize a data info. */
+void freeData(t_asm_data *data)
+{
+	if (data != NULL)
+		_ASM_FREE_FUNCTION(data);
+}

+ 106 - 0
assembler/asm_struct.h

@@ -0,0 +1,106 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * asm_struct.h
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#ifndef _ASM_STRUCT_H
+#define _ASM_STRUCT_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include "asm_constants.h"
+
+#ifndef _ASM_ALLOC_FUNCTION
+#	define _ASM_ALLOC_FUNCTION malloc
+#endif
+#ifndef _ASM_FREE_FUNCTION
+#	define _ASM_FREE_FUNCTION free
+#endif
+
+#define t_asm_comment char
+
+typedef struct t_asm_register
+{
+	int	ID;
+	int	indirect;
+}t_asm_register;
+
+typedef struct t_asm_label
+{
+	char *ID;		/* identifier */
+	void *data;	   /* a memory word referenced by this label */
+}t_asm_label;
+
+typedef struct t_asm_address
+{
+	int addr;
+	t_asm_label *label;
+}t_asm_address;
+
+typedef struct t_asm_instruction
+{
+	int opcode;
+	int format;
+	t_asm_register *reg_1;
+	t_asm_register *reg_2;
+	t_asm_register *reg_3;
+	int immediate;
+	t_asm_address *address;
+	t_asm_comment *user_comment;
+}t_asm_instruction;
+
+typedef struct t_asm_data
+{
+	int dataType;
+	int value;
+}t_asm_data;
+
+/* create an instance of `t_asm_register' */
+extern t_asm_register * allocRegister(int ID, int indirect);
+
+/* create an instance of `t_asm_address' */
+extern t_asm_address * allocAddress(int displacement, t_asm_label *label);
+
+/* create an instance of `t_asm_label' */
+extern t_asm_label * allocLabel(char *ID, void *data);
+
+/* create an instance of `t_asm_instruction' */
+extern t_asm_instruction * allocInstruction(int opcode);
+
+/* create an instance of `t_asm_data' */
+extern t_asm_data * allocData(int dataType, int value);
+
+/* initialize an instruction with three operands' */
+extern t_asm_instruction * init_opcode3(int opcode, t_asm_register *reg_1
+		, t_asm_register *reg_2, t_asm_register *reg_3);
+
+/* initialize an instruction with two operands' */
+extern t_asm_instruction * init_opcode2(int opcode, t_asm_register *reg_1
+		, t_asm_register *reg_2, int immediate);
+
+/* initialize an instruction with a single operand' */
+extern t_asm_instruction * init_opcodeI(int opcode, t_asm_register *reg_1
+		, t_asm_address *addr);
+
+/* initialize a branch instruction */
+extern t_asm_instruction * init_ccode(int opcode, t_asm_address *addr);
+
+/* initialize a HALT instruction */
+extern t_asm_instruction * init_halt();
+
+/* initialize a NOP instruction */
+extern t_asm_instruction * init_nop();
+
+/* finalize an instruction info. */
+extern void freeInstruction(t_asm_instruction *inst);
+
+/* finalize a data info. */
+extern void freeData(t_asm_data *data);
+
+#endif

+ 122 - 0
assembler/assembler.lex

@@ -0,0 +1,122 @@
+
+%{
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * assembler.lex
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include "asm_struct.h"
+#include "collections.h"
+#include "assembler.tab.h"
+
+extern int line_num;
+extern int num_error;
+
+%}
+
+%x comment
+%s DATA
+%option noyywrap
+
+DIGIT	[0-9]
+ID	[a-zA-Z_][a-zA-Z0-9_]*
+
+%%
+[ \t\f\v]+		{ /* Ignore whitespace. */ }
+"/*"                    {  BEGIN(comment); return BEGIN_COMMENT; }
+<comment>[^*]*          { yylval.svalue = strdup(yytext); return COMMENT; }
+<comment>"*"+[^*/]*     { yylval.svalue = strdup(yytext); return COMMENT; }
+<comment>"*"+"/"        {  BEGIN(INITIAL); return END_COMMENT; }
+
+
+"("		{ return LPAR; }
+")"		{ return RPAR; }
+":"		{ return COLON; }
+"#"		{ return BEGIN_IMMEDIATE; }
+"-"      { return MINUS; }
+
+"add"|"ADD"		{yylval.opcode = ADD_OP; return OPCODE3; }
+"sub"|"SUB"		{yylval.opcode = SUB_OP; return OPCODE3; }
+"andl"|"ANDL"	{yylval.opcode = ANDL_OP; return OPCODE3; }
+"orl"|"ORL"		{yylval.opcode = ORL_OP; return OPCODE3; }
+"xorl"|"XORL"	{yylval.opcode = XORL_OP; return OPCODE3; }
+"andb"|"ANDB"	{yylval.opcode = ANDB_OP; return OPCODE3; }
+"orb"|"ORB"		{yylval.opcode = ORB_OP; return OPCODE3; }
+"xorb"|"XORB"	{yylval.opcode = XORB_OP; return OPCODE3; }
+"mul"|"MUL"		{yylval.opcode = MUL_OP; return OPCODE3; }
+"div"|"DIV"		{yylval.opcode = DIV_OP; return OPCODE3; }
+"shl"|"SHL"		{yylval.opcode = SHL_OP; return OPCODE3; }
+"shr"|"SHR"		{yylval.opcode = SHR_OP; return OPCODE3; }
+"rotl"|"ROTL"	{yylval.opcode = ROTL_OP; return OPCODE3; }
+"rotr"|"ROTR"	{yylval.opcode = ROTR_OP; return OPCODE3; }
+"neg"|"NEG"		{yylval.opcode = NEG_OP; return OPCODE3; }
+"spcl"|"SPCL"		{yylval.opcode = SPCL_OP; return OPCODE3; }
+"addi"|"ADDI"		{yylval.opcode = ADDI_OP; return OPCODE2; }
+"subi"|"SUBI"		{yylval.opcode = SUBI_OP; return OPCODE2; }
+"andli"|"ANDLI"	{yylval.opcode = ANDLI_OP; return OPCODE2; }
+"orli"|"ORLI"		{yylval.opcode = ORLI_OP; return OPCODE2; }
+"xorli"|"XORLI"	{yylval.opcode = XORLI_OP; return OPCODE2; }
+"andbi"|"ANDBI"	{yylval.opcode = ANDBI_OP; return OPCODE2; }
+"orbi"|"ORBI"		{yylval.opcode = ORBI_OP; return OPCODE2; }
+"xorbi"|"XORBI"	{yylval.opcode = XORBI_OP; return OPCODE2; }
+"muli"|"MULI"		{yylval.opcode = MULI_OP; return OPCODE2; }
+"divi"|"DIVI"		{yylval.opcode = DIVI_OP; return OPCODE2; }
+"shli"|"SHLI"		{yylval.opcode = SHLI_OP; return OPCODE2; }
+"shri"|"SHRI"		{yylval.opcode = SHRI_OP; return OPCODE2; }
+"rotli"|"ROTLI"	{yylval.opcode = ROTLI_OP; return OPCODE2; }
+"rotri"|"ROTRI"	{yylval.opcode = ROTRI_OP; return OPCODE2; }
+"notl"|"NOTL"		{yylval.opcode = NOTL_OP; return OPCODE2; }
+"notb"|"NOTB"		{yylval.opcode = NOTB_OP; return OPCODE2; }
+"nop"|"NOP"		   {yylval.opcode = NOP_OP; return NOP; }
+"mova"|"MOVA"		{yylval.opcode = MOVA_OP; return OPCODEI; }
+"load"|"LOAD"     {yylval.opcode = LOAD_OP; return OPCODEI; }
+"store"|"STORE"   {yylval.opcode = STORE_OP; return OPCODEI; }
+"jsr"|"JSR"		   {yylval.opcode = JSR_OP; return OPCODEI; }
+"ret"|"RET"		   {yylval.opcode = RET_OP; return OPCODEI; }
+"seq"|"SEQ"       {yylval.opcode = SEQ_OP; return OPCODEI; }
+"sge"|"SGE"       {yylval.opcode = SGE_OP; return OPCODEI; }
+"sgt"|"SGT"       {yylval.opcode = SGT_OP; return OPCODEI; }
+"sle"|"SLE"       {yylval.opcode = SLE_OP; return OPCODEI; }
+"slt"|"SLT"       {yylval.opcode = SLT_OP; return OPCODEI; }
+"sne"|"SNE"       {yylval.opcode = SNE_OP; return OPCODEI; }
+"read"|"READ"     {yylval.opcode = READ_OP; return OPCODEI; }
+"write"|"WRITE"   {yylval.opcode = WRITE_OP; return OPCODEI; }
+"halt"|"HALT"	   {yylval.opcode = HALT_OP; return HALT; }
+"bt"|"BT"		   {yylval.opcode = BT_OP; return CCODE; }
+"bf"|"BF"		   {yylval.opcode = BF_OP; return CCODE; }
+"bhi"|"BHI"		   {yylval.opcode = BHI_OP; return CCODE; }
+"bls"|"BLS"		   {yylval.opcode = BLS_OP; return CCODE; }
+"bcc"|"BCC"		   {yylval.opcode = BCC_OP; return CCODE; }
+"bcs"|"BCS"		   {yylval.opcode = BCS_OP; return CCODE; }
+"bne"|"BNE"		   {yylval.opcode = BNE_OP; return CCODE; }
+"beq"|"BEQ"		   {yylval.opcode = BEQ_OP; return CCODE; }
+"bvc"|"BVC"		   {yylval.opcode = BVC_OP; return CCODE; }
+"bvs"|"BVS"		   {yylval.opcode = BVS_OP; return CCODE; }
+"bpl"|"BPL"		   {yylval.opcode = BPL_OP; return CCODE; }
+"bmi"|"BMI"		   {yylval.opcode = BMI_OP; return CCODE; }
+"bge"|"BGE"		   {yylval.opcode = BGE_OP; return CCODE; }
+"blt"|"BLT"		   {yylval.opcode = BLT_OP; return CCODE; }
+"bgt"|"BGT"		   {yylval.opcode = BGT_OP; return CCODE; }
+"ble"|"BLE"		   {yylval.opcode = BLE_OP; return CCODE; }
+
+".data"|".DATA"            BEGIN(DATA); {line_num++; }
+".text"|".TEXT"            BEGIN(INITIAL); {line_num++; }
+<DATA>".word"|".WORD"		{return _WORD;}
+<DATA>".space"|".SPACE"    {return _SPACE;}
+
+["R"|"r"]{DIGIT}+    { yylval.immediate = atoi(&yytext[1]); return REG; }
+
+\n						{ /* DOES NOTHING */ }
+{DIGIT}+          { yylval.immediate = atoi(yytext); return IMM; };
+{ID}              { yylval.svalue = strdup(yytext); return ETI; };
+.						{ return(yytext[0]); num_error++; }
+%%

+ 651 - 0
assembler/assembler.output

@@ -0,0 +1,651 @@
+State 11 conflicts: 1 shift/reduce
+State 36 conflicts: 1 shift/reduce
+State 45 conflicts: 1 shift/reduce
+
+
+Grammar
+
+    0 $accept: asm $end
+
+    1 asm: asm data_segm instruction_segm
+    2    | data_segm instruction_segm
+    3    | instruction_segm
+
+    4 instruction_segm: instruction_segm instruction
+    5                 | instruction
+
+    6 instruction: instr comment
+    7            | label_decl instr comment
+    8            | instr
+    9            | label_decl instr
+
+   10 instr: OPCODE3 register REG register
+   11      | OPCODE2 REG REG immediate
+   12      | OPCODEI REG address
+   13      | CCODE address
+   14      | HALT
+   15      | NOP
+
+   16 data_segm: data_segm data_def
+   17          | data_def comment
+   18          | data_def
+
+   19 data_def: label_decl data_value
+   20         | data_value
+
+   21 label_decl: ETI COLON
+
+   22 data_value: _WORD IMM
+   23           | _SPACE IMM
+
+   24 register: REG
+   25         | LPAR REG RPAR
+
+   26 immediate: BEGIN_IMMEDIATE IMM
+   27          | BEGIN_IMMEDIATE MINUS IMM
+
+   28 address: ETI
+   29        | IMM
+
+   30 comment: BEGIN_COMMENT COMMENT END_COMMENT
+
+
+Terminals, with rules where they appear
+
+$end (0) 0
+error (256)
+OPCODE3 (258) 10
+OPCODE2 (259) 11
+OPCODEI (260) 12
+CCODE (261) 13
+HALT (262) 14
+NOP (263) 15
+_WORD (264) 22
+_SPACE (265) 23
+REG (266) 10 11 12 24 25
+LPAR (267) 25
+RPAR (268) 25
+COLON (269) 21
+MINUS (270) 27
+BEGIN_IMMEDIATE (271) 26 27
+BEGIN_COMMENT (272) 30
+END_COMMENT (273) 30
+COMMENT (274) 30
+ETI (275) 21 28
+IMM (276) 22 23 26 27 29
+
+
+Nonterminals, with rules where they appear
+
+$accept (22)
+    on left: 0
+asm (23)
+    on left: 1 2 3, on right: 0 1
+instruction_segm (24)
+    on left: 4 5, on right: 1 2 3 4
+instruction (25)
+    on left: 6 7 8 9, on right: 4 5
+instr (26)
+    on left: 10 11 12 13 14 15, on right: 6 7 8 9
+data_segm (27)
+    on left: 16 17 18, on right: 1 2 16
+data_def (28)
+    on left: 19 20, on right: 16 17 18
+label_decl (29)
+    on left: 21, on right: 7 9 19
+data_value (30)
+    on left: 22 23, on right: 19 20
+register (31)
+    on left: 24 25, on right: 10
+immediate (32)
+    on left: 26 27, on right: 11
+address (33)
+    on left: 28 29, on right: 12 13
+comment (34)
+    on left: 30, on right: 6 7 17
+
+
+state 0
+
+    0 $accept: . asm $end
+
+    OPCODE3  shift, and go to state 1
+    OPCODE2  shift, and go to state 2
+    OPCODEI  shift, and go to state 3
+    CCODE    shift, and go to state 4
+    HALT     shift, and go to state 5
+    NOP      shift, and go to state 6
+    _WORD    shift, and go to state 7
+    _SPACE   shift, and go to state 8
+    ETI      shift, and go to state 9
+
+    asm               go to state 10
+    instruction_segm  go to state 11
+    instruction       go to state 12
+    instr             go to state 13
+    data_segm         go to state 14
+    data_def          go to state 15
+    label_decl        go to state 16
+    data_value        go to state 17
+
+
+state 1
+
+   10 instr: OPCODE3 . register REG register
+
+    REG   shift, and go to state 18
+    LPAR  shift, and go to state 19
+
+    register  go to state 20
+
+
+state 2
+
+   11 instr: OPCODE2 . REG REG immediate
+
+    REG  shift, and go to state 21
+
+
+state 3
+
+   12 instr: OPCODEI . REG address
+
+    REG  shift, and go to state 22
+
+
+state 4
+
+   13 instr: CCODE . address
+
+    ETI  shift, and go to state 23
+    IMM  shift, and go to state 24
+
+    address  go to state 25
+
+
+state 5
+
+   14 instr: HALT .
+
+    $default  reduce using rule 14 (instr)
+
+
+state 6
+
+   15 instr: NOP .
+
+    $default  reduce using rule 15 (instr)
+
+
+state 7
+
+   22 data_value: _WORD . IMM
+
+    IMM  shift, and go to state 26
+
+
+state 8
+
+   23 data_value: _SPACE . IMM
+
+    IMM  shift, and go to state 27
+
+
+state 9
+
+   21 label_decl: ETI . COLON
+
+    COLON  shift, and go to state 28
+
+
+state 10
+
+    0 $accept: asm . $end
+    1 asm: asm . data_segm instruction_segm
+
+    $end    shift, and go to state 29
+    _WORD   shift, and go to state 7
+    _SPACE  shift, and go to state 8
+    ETI     shift, and go to state 9
+
+    data_segm   go to state 30
+    data_def    go to state 15
+    label_decl  go to state 31
+    data_value  go to state 17
+
+
+state 11
+
+    3 asm: instruction_segm .
+    4 instruction_segm: instruction_segm . instruction
+
+    OPCODE3  shift, and go to state 1
+    OPCODE2  shift, and go to state 2
+    OPCODEI  shift, and go to state 3
+    CCODE    shift, and go to state 4
+    HALT     shift, and go to state 5
+    NOP      shift, and go to state 6
+    ETI      shift, and go to state 9
+
+    ETI       [reduce using rule 3 (asm)]
+    $default  reduce using rule 3 (asm)
+
+    instruction  go to state 32
+    instr        go to state 13
+    label_decl   go to state 33
+
+
+state 12
+
+    5 instruction_segm: instruction .
+
+    $default  reduce using rule 5 (instruction_segm)
+
+
+state 13
+
+    6 instruction: instr . comment
+    8            | instr .
+
+    BEGIN_COMMENT  shift, and go to state 34
+
+    $default  reduce using rule 8 (instruction)
+
+    comment  go to state 35
+
+
+state 14
+
+    2 asm: data_segm . instruction_segm
+   16 data_segm: data_segm . data_def
+
+    OPCODE3  shift, and go to state 1
+    OPCODE2  shift, and go to state 2
+    OPCODEI  shift, and go to state 3
+    CCODE    shift, and go to state 4
+    HALT     shift, and go to state 5
+    NOP      shift, and go to state 6
+    _WORD    shift, and go to state 7
+    _SPACE   shift, and go to state 8
+    ETI      shift, and go to state 9
+
+    instruction_segm  go to state 36
+    instruction       go to state 12
+    instr             go to state 13
+    data_def          go to state 37
+    label_decl        go to state 16
+    data_value        go to state 17
+
+
+state 15
+
+   17 data_segm: data_def . comment
+   18          | data_def .
+
+    BEGIN_COMMENT  shift, and go to state 34
+
+    $default  reduce using rule 18 (data_segm)
+
+    comment  go to state 38
+
+
+state 16
+
+    7 instruction: label_decl . instr comment
+    9            | label_decl . instr
+   19 data_def: label_decl . data_value
+
+    OPCODE3  shift, and go to state 1
+    OPCODE2  shift, and go to state 2
+    OPCODEI  shift, and go to state 3
+    CCODE    shift, and go to state 4
+    HALT     shift, and go to state 5
+    NOP      shift, and go to state 6
+    _WORD    shift, and go to state 7
+    _SPACE   shift, and go to state 8
+
+    instr       go to state 39
+    data_value  go to state 40
+
+
+state 17
+
+   20 data_def: data_value .
+
+    $default  reduce using rule 20 (data_def)
+
+
+state 18
+
+   24 register: REG .
+
+    $default  reduce using rule 24 (register)
+
+
+state 19
+
+   25 register: LPAR . REG RPAR
+
+    REG  shift, and go to state 41
+
+
+state 20
+
+   10 instr: OPCODE3 register . REG register
+
+    REG  shift, and go to state 42
+
+
+state 21
+
+   11 instr: OPCODE2 REG . REG immediate
+
+    REG  shift, and go to state 43
+
+
+state 22
+
+   12 instr: OPCODEI REG . address
+
+    ETI  shift, and go to state 23
+    IMM  shift, and go to state 24
+
+    address  go to state 44
+
+
+state 23
+
+   28 address: ETI .
+
+    $default  reduce using rule 28 (address)
+
+
+state 24
+
+   29 address: IMM .
+
+    $default  reduce using rule 29 (address)
+
+
+state 25
+
+   13 instr: CCODE address .
+
+    $default  reduce using rule 13 (instr)
+
+
+state 26
+
+   22 data_value: _WORD IMM .
+
+    $default  reduce using rule 22 (data_value)
+
+
+state 27
+
+   23 data_value: _SPACE IMM .
+
+    $default  reduce using rule 23 (data_value)
+
+
+state 28
+
+   21 label_decl: ETI COLON .
+
+    $default  reduce using rule 21 (label_decl)
+
+
+state 29
+
+    0 $accept: asm $end .
+
+    $default  accept
+
+
+state 30
+
+    1 asm: asm data_segm . instruction_segm
+   16 data_segm: data_segm . data_def
+
+    OPCODE3  shift, and go to state 1
+    OPCODE2  shift, and go to state 2
+    OPCODEI  shift, and go to state 3
+    CCODE    shift, and go to state 4
+    HALT     shift, and go to state 5
+    NOP      shift, and go to state 6
+    _WORD    shift, and go to state 7
+    _SPACE   shift, and go to state 8
+    ETI      shift, and go to state 9
+
+    instruction_segm  go to state 45
+    instruction       go to state 12
+    instr             go to state 13
+    data_def          go to state 37
+    label_decl        go to state 16
+    data_value        go to state 17
+
+
+state 31
+
+   19 data_def: label_decl . data_value
+
+    _WORD   shift, and go to state 7
+    _SPACE  shift, and go to state 8
+
+    data_value  go to state 40
+
+
+state 32
+
+    4 instruction_segm: instruction_segm instruction .
+
+    $default  reduce using rule 4 (instruction_segm)
+
+
+state 33
+
+    7 instruction: label_decl . instr comment
+    9            | label_decl . instr
+
+    OPCODE3  shift, and go to state 1
+    OPCODE2  shift, and go to state 2
+    OPCODEI  shift, and go to state 3
+    CCODE    shift, and go to state 4
+    HALT     shift, and go to state 5
+    NOP      shift, and go to state 6
+
+    instr  go to state 39
+
+
+state 34
+
+   30 comment: BEGIN_COMMENT . COMMENT END_COMMENT
+
+    COMMENT  shift, and go to state 46
+
+
+state 35
+
+    6 instruction: instr comment .
+
+    $default  reduce using rule 6 (instruction)
+
+
+state 36
+
+    2 asm: data_segm instruction_segm .
+    4 instruction_segm: instruction_segm . instruction
+
+    OPCODE3  shift, and go to state 1
+    OPCODE2  shift, and go to state 2
+    OPCODEI  shift, and go to state 3
+    CCODE    shift, and go to state 4
+    HALT     shift, and go to state 5
+    NOP      shift, and go to state 6
+    ETI      shift, and go to state 9
+
+    ETI       [reduce using rule 2 (asm)]
+    $default  reduce using rule 2 (asm)
+
+    instruction  go to state 32
+    instr        go to state 13
+    label_decl   go to state 33
+
+
+state 37
+
+   16 data_segm: data_segm data_def .
+
+    $default  reduce using rule 16 (data_segm)
+
+
+state 38
+
+   17 data_segm: data_def comment .
+
+    $default  reduce using rule 17 (data_segm)
+
+
+state 39
+
+    7 instruction: label_decl instr . comment
+    9            | label_decl instr .
+
+    BEGIN_COMMENT  shift, and go to state 34
+
+    $default  reduce using rule 9 (instruction)
+
+    comment  go to state 47
+
+
+state 40
+
+   19 data_def: label_decl data_value .
+
+    $default  reduce using rule 19 (data_def)
+
+
+state 41
+
+   25 register: LPAR REG . RPAR
+
+    RPAR  shift, and go to state 48
+
+
+state 42
+
+   10 instr: OPCODE3 register REG . register
+
+    REG   shift, and go to state 18
+    LPAR  shift, and go to state 19
+
+    register  go to state 49
+
+
+state 43
+
+   11 instr: OPCODE2 REG REG . immediate
+
+    BEGIN_IMMEDIATE  shift, and go to state 50
+
+    immediate  go to state 51
+
+
+state 44
+
+   12 instr: OPCODEI REG address .
+
+    $default  reduce using rule 12 (instr)
+
+
+state 45
+
+    1 asm: asm data_segm instruction_segm .
+    4 instruction_segm: instruction_segm . instruction
+
+    OPCODE3  shift, and go to state 1
+    OPCODE2  shift, and go to state 2
+    OPCODEI  shift, and go to state 3
+    CCODE    shift, and go to state 4
+    HALT     shift, and go to state 5
+    NOP      shift, and go to state 6
+    ETI      shift, and go to state 9
+
+    ETI       [reduce using rule 1 (asm)]
+    $default  reduce using rule 1 (asm)
+
+    instruction  go to state 32
+    instr        go to state 13
+    label_decl   go to state 33
+
+
+state 46
+
+   30 comment: BEGIN_COMMENT COMMENT . END_COMMENT
+
+    END_COMMENT  shift, and go to state 52
+
+
+state 47
+
+    7 instruction: label_decl instr comment .
+
+    $default  reduce using rule 7 (instruction)
+
+
+state 48
+
+   25 register: LPAR REG RPAR .
+
+    $default  reduce using rule 25 (register)
+
+
+state 49
+
+   10 instr: OPCODE3 register REG register .
+
+    $default  reduce using rule 10 (instr)
+
+
+state 50
+
+   26 immediate: BEGIN_IMMEDIATE . IMM
+   27          | BEGIN_IMMEDIATE . MINUS IMM
+
+    MINUS  shift, and go to state 53
+    IMM    shift, and go to state 54
+
+
+state 51
+
+   11 instr: OPCODE2 REG REG immediate .
+
+    $default  reduce using rule 11 (instr)
+
+
+state 52
+
+   30 comment: BEGIN_COMMENT COMMENT END_COMMENT .
+
+    $default  reduce using rule 30 (comment)
+
+
+state 53
+
+   27 immediate: BEGIN_IMMEDIATE MINUS . IMM
+
+    IMM  shift, and go to state 55
+
+
+state 54
+
+   26 immediate: BEGIN_IMMEDIATE IMM .
+
+    $default  reduce using rule 26 (immediate)
+
+
+state 55
+
+   27 immediate: BEGIN_IMMEDIATE MINUS IMM .
+
+    $default  reduce using rule 27 (immediate)

+ 625 - 0
assembler/assembler.y

@@ -0,0 +1,625 @@
+%{
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * assembler.y
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "asm_struct.h"
+#include "asm_engine.h"
+
+/* Variables declared for error tracking */
+int line_num;
+int num_error;
+
+/* other global variables */
+t_translation_infos *infos;
+
+/* functions declared into assembler.y */
+char * AsmErrorToString(int errorcode);
+
+%}
+
+%expect 3
+      
+%union{
+	char *svalue;
+	int immediate;
+	int opcode;
+	t_asm_address *address;
+	t_asm_data *dataVal;
+   t_asm_instruction *instr;
+   t_asm_label *label;
+   t_asm_register *reg;
+}
+
+%start asm
+
+/* definitions */
+%token <opcode> OPCODE3
+%token <opcode> OPCODE2
+%token <opcode> OPCODEI
+%token <opcode> CCODE
+%token <opcode> HALT
+%token <opcode> NOP
+%token _WORD
+%token _SPACE
+%token <immediate>REG
+%token LPAR
+%token RPAR
+%token COLON
+%token MINUS
+%token BEGIN_IMMEDIATE
+%token BEGIN_COMMENT
+%token END_COMMENT
+%token <svalue> COMMENT
+%token <svalue> ETI
+%token <immediate> IMM
+
+%type <dataVal> data_value
+%type <reg> register
+%type <immediate> immediate
+%type <address> address
+%type <svalue> comment
+%type <label> label_decl
+%type <instr> instr
+
+%%
+
+asm :       asm data_segm instruction_segm { /* DOES NOTHING */}
+            | data_segm instruction_segm     { /* DOES NOTHING */}
+            | instruction_segm               { /* DOES NOTHING */}
+;
+
+instruction_segm :   instruction_segm instruction   { line_num++; }
+                     | instruction                  { line_num++; }
+;
+
+instruction :  instr comment           { /* DOES NOTHING */}
+            | label_decl instr comment {
+               /* assign the label to the current instruction */
+               $1->data = (void *) $2;
+            }
+            | instr            { /* DOES NOTHING */}
+            | label_decl instr {
+               /* assign the label to the current instruction */
+               $1->data = (void *) $2;
+            }
+;
+
+instr : OPCODE3 register REG register  {
+         t_asm_register *reg;
+         int asm_errorcode;
+         
+         /* alloc memory for a register info. */
+         reg = allocRegister($3, 0);
+   
+         /* register shouldn't be a NULL pointer */
+         if (reg == NULL)
+         {
+            /* an out of memory occurred */
+            yyerror(AsmErrorToString(ASM_OUT_OF_MEMORY));
+               
+            /* stop the parser */
+            YYABORT;
+         }
+
+         /* initialize an instruction with three operands' */
+         $$ = init_opcode3($1, $2, reg, $4);
+         
+         /* $$ shouldn't be a NULL pointer */
+         if ($$ == NULL)
+         {
+            /* an out of memory occurred */
+            yyerror(AsmErrorToString(ASM_OUT_OF_MEMORY));
+               
+            /* stop the parser */
+            YYABORT;
+         }
+
+         /* add the newly created instruction to the code segment */
+         asm_errorcode = addInstruction(infos, $$);
+         if (asm_errorcode != ASM_OK)
+         {
+               /* an error occurred */
+               yyerror(AsmErrorToString(asm_errorcode));
+         }
+      }
+      | OPCODE2 REG REG immediate {
+         t_asm_register *register_1;
+         t_asm_register *register_2;
+         int asm_errorcode;
+         
+         /* alloc memory for a register info. */
+         register_1 = allocRegister($2, 0);
+         register_2 = allocRegister($3, 0);
+   
+         /* registers shouldn't be a NULL pointer */
+         if (register_1 == NULL || register_2 == NULL)
+         {
+            /* an out of memory occurred */
+            yyerror(AsmErrorToString(ASM_OUT_OF_MEMORY));
+               
+            /* stop the parser */
+            YYABORT;
+         }
+
+         /* initialize an instruction with two operands' */
+         $$ = init_opcode2($1, register_1, register_2, $4);
+         
+         /* $$ shouldn't be a NULL pointer */
+         if ($$ == NULL)
+         {
+            /* an out of memory occurred */
+            yyerror(AsmErrorToString(ASM_OUT_OF_MEMORY));
+               
+            /* stop the parser */
+            YYABORT;
+         }
+
+         /* add the newly created instruction to the code segment */
+         asm_errorcode = addInstruction(infos, $$);
+         if (asm_errorcode != ASM_OK)
+         {
+               /* an error occurred */
+               yyerror(AsmErrorToString(asm_errorcode));
+         }
+      }
+      | OPCODEI REG address {
+         t_asm_register *reg;
+         int asm_errorcode;
+         
+         /* alloc memory for a register info. */
+         reg = allocRegister($2, 0);
+   
+         /* register shouldn't be a NULL pointer */
+         if (reg == NULL)
+         {
+            /* an out of memory occurred */
+            yyerror(AsmErrorToString(ASM_OUT_OF_MEMORY));
+               
+            /* stop the parser */
+            YYABORT;
+         }
+
+         /* initialize an instruction with a single operand' */
+         $$ = init_opcodeI($1, reg, $3);
+         
+         /* $$ shouldn't be a NULL pointer */
+         if ($$ == NULL)
+         {
+            /* an out of memory occurred */
+            yyerror(AsmErrorToString(ASM_OUT_OF_MEMORY));
+               
+            /* stop the parser */
+            YYABORT;
+         }
+
+         /* add the newly created instruction to the code segment */
+         asm_errorcode = addInstruction(infos, $$);
+         if (asm_errorcode != ASM_OK)
+         {
+               /* an error occurred */
+               yyerror(AsmErrorToString(asm_errorcode));
+         }
+      }
+      | CCODE address {
+         int asm_errorcode;
+         
+         /* initialize a branch instruction */
+         $$ = init_ccode($1, $2);
+         
+         /* $$ shouldn't be a NULL pointer */
+         if ($$ == NULL)
+         {
+            /* an out of memory occurred */
+            yyerror(AsmErrorToString(ASM_OUT_OF_MEMORY));
+               
+            /* stop the parser */
+            YYABORT;
+         }
+
+         /* add the newly created instruction to the code segment */
+         asm_errorcode = addInstruction(infos, $$);
+         if (asm_errorcode != ASM_OK)
+         {
+               /* an error occurred */
+               yyerror(AsmErrorToString(asm_errorcode));
+         }
+      }
+      | HALT {
+         int asm_errorcode;
+         
+         /* initialize a HALT instruction */
+         $$ = init_halt();
+
+         /* $$ shouldn't be a NULL pointer */
+         if ($$ == NULL)
+         {
+            /* an out of memory occurred */
+            yyerror(AsmErrorToString(ASM_OUT_OF_MEMORY));
+               
+            /* stop the parser */
+            YYABORT;
+         }
+
+         /* add the newly created instruction to the code segment */
+         asm_errorcode = addInstruction(infos, $$);
+         if (asm_errorcode != ASM_OK)
+         {
+               /* an error occurred */
+               yyerror(AsmErrorToString(asm_errorcode));
+         }
+      }
+      | NOP {
+         int asm_errorcode;
+         
+         /* initialize a NOP instruction */
+         $$ = init_nop();
+
+         /* $$ shouldn't be a NULL pointer */
+         if ($$ == NULL)
+         {
+            /* an out of memory occurred */
+            yyerror(AsmErrorToString(ASM_OUT_OF_MEMORY));
+               
+            /* stop the parser */
+            YYABORT;
+         }
+
+         /* add the newly created instruction to the code segment */
+         asm_errorcode = addInstruction(infos, $$);
+         if (asm_errorcode != ASM_OK)
+         {
+               /* an error occurred */
+               yyerror(AsmErrorToString(asm_errorcode));
+         }
+      }
+;
+
+data_segm : data_segm data_def   { line_num++; }
+            | data_def comment   { line_num++; }
+            | data_def           { line_num++; }
+;
+
+data_def : label_decl data_value {
+                  int asm_errorcode;
+
+                  /* insert data into the data segment */
+                  asm_errorcode = addData(infos, $2);
+                  if (asm_errorcode != ASM_OK)
+                  {
+                     /* an error occurred */
+                     yyerror(AsmErrorToString(asm_errorcode));
+                  }
+
+                  /* assign the label to the current block of data */
+                  $1->data = (void *) $2;
+         }
+         | data_value {
+                  int asm_errorcode;
+
+                  /* insert data into the data segment */
+                  asm_errorcode = addData(infos, $1);
+                  if (asm_errorcode != ASM_OK)
+                  {
+                     /* an error occurred */
+                     yyerror(AsmErrorToString(asm_errorcode));
+                  }
+         }
+;
+
+label_decl : ETI COLON {
+            int asm_errorcode;
+            
+            /* look for the requested label */
+            $$ = findLabel(infos, $1, &asm_errorcode);
+            if (asm_errorcode != ASM_OK)
+            {
+               /* an error occurred */
+               yyerror(AsmErrorToString(asm_errorcode));
+            }
+            
+            if ($$ == NULL)
+            {
+               t_asm_label *label;
+            
+               /* label was never defined before */
+               label = allocLabel($1, NULL);
+
+               /* label shouldn't be a NULL pointer */
+               if (label == NULL)
+               {
+                  /* an out of memory occurred */
+                  yyerror(AsmErrorToString(ASM_OUT_OF_MEMORY));
+               
+                  /* stop the parser */
+                  YYABORT;
+               }
+
+               /* insert the new label */
+               asm_errorcode = insertLabel(infos, label);
+
+               /* set the $$ value */
+               $$ = label;
+            }
+            else
+               free($1);
+
+            /* notify if an error occurred */
+            if (asm_errorcode != ASM_OK)
+               yyerror(AsmErrorToString(asm_errorcode));
+         }
+;
+
+data_value : _WORD IMM {
+               /* create an instance of `t_asm_data' */
+               $$ = allocData(ASM_WORD, $2);
+
+               /* $$ shouldn't be a NULL pointer */
+               if ($$ == NULL)
+               {
+                  /* an out of memory occurred */
+                  yyerror(AsmErrorToString(ASM_OUT_OF_MEMORY));
+               
+                  /* stop the parser */
+                  YYABORT;
+               }
+           }
+           | _SPACE IMM {
+               /* create an instance of `t_asm_data' */
+               $$ = allocData(ASM_SPACE, $2);
+
+               /* $$ shouldn't be a NULL pointer */
+               if ($$ == NULL)
+               {
+                  /* an out of memory occurred */
+                  yyerror(AsmErrorToString(ASM_OUT_OF_MEMORY));
+               
+                  /* stop the parser */
+                  YYABORT;
+               }
+           }
+;
+		
+register : REG {
+               /* alloc memory for a register info. */
+               $$ = allocRegister($1, 0);
+   
+               /* $$ shouldn't be a NULL pointer */
+               if ($$ == NULL)
+               {
+                  /* an out of memory occurred */
+                  yyerror(AsmErrorToString(ASM_OUT_OF_MEMORY));
+               
+                  /* stop the parser */
+                  YYABORT;
+               }
+         }
+         | LPAR REG RPAR {
+               /* alloc memory for a register info. */
+               $$ = allocRegister($2, 1);
+   
+               /* label shouldn't be a NULL pointer */
+               if ($$ == NULL)
+               {
+                  /* an out of memory occurred */
+                  yyerror(AsmErrorToString(ASM_OUT_OF_MEMORY));
+               
+                  /* stop the parser */
+                  YYABORT;
+               }
+         }
+;
+
+immediate : BEGIN_IMMEDIATE IMM { $$ = $2; }
+          | BEGIN_IMMEDIATE MINUS IMM {$$ = - $3; }
+;
+
+address  : ETI {
+            int asm_errorcode;
+            t_asm_label *label_found;
+            
+            /* look for the requested label */
+            label_found = findLabel(infos, $1, &asm_errorcode);
+            if (asm_errorcode != ASM_OK)
+            {
+               /* an error occurred */
+               yyerror(AsmErrorToString(asm_errorcode));
+            }
+            
+            if (label_found == NULL)
+            {
+               /* label was never defined before */
+               label_found = allocLabel($1, NULL);
+
+               /* label shouldn't be a NULL pointer */
+               if (label_found == NULL)
+               {
+                  /* an out of memory occurred */
+                  yyerror(AsmErrorToString(ASM_OUT_OF_MEMORY));
+               
+                  /* stop the parser */
+                  YYABORT;
+               }
+
+               /* insert the new label */
+               asm_errorcode = insertLabel(infos, label_found);
+
+               /* notify if an error occurred */
+               if (asm_errorcode != ASM_OK)
+                  yyerror(AsmErrorToString(asm_errorcode));
+            }
+            else
+               free($1);
+
+            /* set the $$ value */
+            $$ = allocAddress(0, label_found);
+            if ($$ == NULL)
+            {
+                  /* an out of memory occurred */
+                  yyerror(AsmErrorToString(ASM_OUT_OF_MEMORY));
+               
+                  /* stop the parser */
+                  YYABORT;
+            }
+         }
+         | IMM {
+            $$ = allocAddress($1, NULL);
+            if ($$ == NULL)
+            {
+                  /* an out of memory occurred */
+                  yyerror(AsmErrorToString(ASM_OUT_OF_MEMORY));
+               
+                  /* stop the parser */
+                  YYABORT;
+            }
+         }
+;
+
+comment  : BEGIN_COMMENT COMMENT END_COMMENT { $$ = $2; }
+;
+
+
+%%
+		 
+int yyerror(const char* errmsg)
+{
+	fprintf(stdout, "line %d , error: %s \n", line_num, errmsg);
+	num_error++;
+	return 0;
+}
+
+int main (int argc, char **argv)
+{
+   int errorcode;
+   char *filename;
+   FILE *input_file;
+	extern FILE *yyin;
+
+   argc--;
+   argv++;
+	
+   if (argc > 0)
+   {
+      input_file = fopen(argv[0], "r");
+      if (input_file == NULL)
+      {
+         fprintf( stdout, "File not found : %s.\n", argv[0]);
+         exit(-1);
+      }
+      yyin = input_file;
+   }
+   else
+      yyin = stdin;
+	
+   if (argc <= 1)
+      filename = "output.o";
+   else
+      filename = argv[1];
+	
+#ifndef NDEBUG
+   fprintf(stdout, "Initializing the assembler data structures.\n");
+#endif
+   /* initialize the translation infos */
+   infos = initStructures(&errorcode);
+
+   /* test if an error occurred */
+   if (errorcode != ASM_OK)
+   {
+         fprintf( stdout, "An error occurred while initializing the assembler.\n"
+                  "%s. \n", AsmErrorToString(errorcode));
+
+         /* we can't start the parsing procedure since a critical error occurred */
+         abort();
+   }
+
+   /* initialize the global variables */
+   line_num = 1;
+   num_error = 0;
+   
+#ifndef NDEBUG
+   if (argc > 0)
+      fprintf(stdout, "Starting the parsing process. "
+                        "Input file : %s.\n", argv[0]);
+   else
+      fprintf(stdout, "Starting the parsing process. "
+                        "Input file : standard input.\n");
+#endif
+   /* start the parsing procedure */
+   yyparse();
+
+#ifndef NDEBUG
+   fprintf(stdout, "Parsing complete. \n");
+#endif
+	
+   /* test if the parsing job found some errors */
+   if (num_error == 0)
+   {
+#ifndef NDEBUG
+      fprintf(stdout, "Output will be written on file : %s. \n", filename);
+#endif
+      errorcode = asm_writeObjectFile(infos, filename);
+      if (errorcode != ASM_OK)
+      {
+         fprintf( stdout, "An error occurred while writing the object file.\n"
+                  "%s. \n", AsmErrorToString(errorcode));
+      }
+#ifndef NDEBUG
+      else
+         fprintf(stdout, "Output written on file \"%s\".\n", filename);
+#endif
+   }
+   else {
+      fprintf(stdout, "\nInput file contains some error(s). No object file written\n");
+      fprintf(stdout, "**%d errors found \n\n", num_error);
+   }
+
+#ifndef NDEBUG
+   fprintf(stdout, "Finalizing the data structures. \n");
+#endif
+
+   /* shutdown the asm engine */
+   if (infos != NULL)
+   {
+         errorcode = finalizeStructures(infos);
+         if (errorcode != ASM_OK)
+         {
+            fprintf(stdout, "SHUTDOWN:: error while finalizing "
+                  "the data structures. \n%s. \n", AsmErrorToString(errorcode));
+         }
+   }
+
+#ifndef NDEBUG
+   fprintf(stdout, "Done. \n");
+#endif
+   
+   return 0;
+}
+
+char * AsmErrorToString(int errorcode)
+{
+   switch(errorcode)
+   {
+      case ASM_NOT_INITIALIZED_INFO : return "global infos not initialized";
+      case ASM_UNDEFINED_INSTRUCTION : return "invalid instruction found";
+      case ASM_INVALID_LABEL_FOUND : return "invalid label found";
+      case ASM_LABEL_ALREADY_PRESENT : return "label already defined";
+      case ASM_UNDEFINED_DATA : return "invalid data found";
+      case ASM_INVALID_DATA_FORMAT : return "invalid data format";
+      case ASM_FOPEN_ERROR : return "fopen failed";
+      case ASM_INVALID_INPUT_FILE : return "invalid file pointer";
+      case ASM_FWRITE_ERROR : return "fwrite failed";
+      case ASM_FCLOSE_ERROR : return "fclose failed";
+      case ASM_CODE_NOT_PRESENT : return "code segment is empty";
+      case ASM_OUT_OF_MEMORY : return "out of memory";
+      case ASM_INVALID_OPCODE : return "invalid opcode found";
+      case ASM_UNKNOWN_ERROR : return "unknown error found";
+      default : return "<invalid errorcode>";
+   }
+}

+ 548 - 0
assembler/collections.c

@@ -0,0 +1,548 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * collections.c
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include "collections.h"
+
+/* function prototypes */
+static t_list * newElement(void *data);
+
+
+/* remove the first element of the list. Returns the new
+ * head of the list */
+t_list * removeFirst(t_list *list)
+{
+   t_list *first_elem;
+   
+   if (list == NULL)
+      return NULL;
+
+   first_elem = list;
+   list = LNEXT(list);
+   if (list != NULL)
+      SET_PREV(list, NULL);
+   
+   _FREE_FUNCTION(first_elem);
+
+   /* postconditions: return the new head of the list */
+   return list;
+}
+
+/* add an element `data' to the list `list' at position `pos'. If pos is negative
+ * , or is larger than the number of elements in the list, the new element is
+ * added on to the end of the list. Function `addElement' returns a pointer
+ * to the new head of the list */
+t_list * addElement(t_list *list, void * data, int pos)
+{
+	t_list *result;
+	t_list *current_elem;
+	t_list *last_elem;
+	int	current_pos;
+	
+	/* initialize the value of `result' */
+	result = newElement(data);
+
+	if (list == NULL)
+		return result;
+	
+	if (pos == 0)
+	{
+		/* update the control informations */
+		SET_NEXT(result, list);
+		SET_PREV(list, result);
+		
+		/* return the new head of the list */
+		return result;
+	}
+	
+	/* retrieve the last element of the list */
+	last_elem = getLastElement(list);
+	assert(last_elem != NULL);
+	
+	if (pos < 0)
+	{
+		/* update the control informations */
+		SET_NEXT(last_elem, result);
+		SET_PREV(result, last_elem);
+		
+		/* update the value of result */
+		return list;
+	}
+	
+	/* `pos' is a positive integer */
+	current_pos = 0;
+	current_elem = list;
+	
+	while(current_pos < pos)
+	{
+		if (current_elem == last_elem)
+		{
+			/* update the control informations */
+			SET_NEXT(last_elem, result);
+			SET_PREV(result, last_elem);
+			
+			/* update the value of result */
+			return list;
+		}
+		
+		/* update the loop informations */
+		current_elem = LNEXT(current_elem);
+		current_pos++;
+	}
+
+	/* assertions */
+	assert(current_elem != NULL);
+	
+	/* update the control informations */
+	SET_NEXT(result, current_elem);
+	SET_PREV(result, LPREV(current_elem));
+	SET_NEXT(LPREV(current_elem), result);
+	SET_PREV(current_elem, result);
+	
+	/* return the new head of the list */
+	return list;
+}
+
+/* add an element at the beginning of the list */
+t_list * addFirst(t_list *list, void * data)
+{
+	t_list *result;
+	
+	/* initialize the value of `result' */
+	result = newElement(data);
+	
+	if (list == NULL)
+		return result;
+	
+	/* postconditions */
+	SET_PREV(list, result);
+	SET_NEXT(result, list);
+	
+	/* return the new head of the list */
+	return result;
+}
+
+/* add an element to the end of the list */
+t_list * addLast(t_list *list, void * data)
+{
+	/* call the `addElement' */
+	return addElement(list, data, -1);
+}
+
+/* remove an element from the list */
+t_list * removeElement(t_list *list, void * data)
+{
+	t_list *current_elem;
+	
+	/* preconditions: the list shouldn't be empty */
+	if (list == NULL)
+		return NULL;
+	
+	/* intialize the value of `current_elem' */
+	current_elem = list;
+	while (  (current_elem != NULL)
+			   && (LDATA(current_elem) != data))
+	{
+		current_elem = LNEXT(current_elem);
+	}
+	
+	/* the value hasn't been found */
+	if (current_elem == NULL)
+		return list;
+	
+	/* the value is found */
+	if (LPREV(current_elem) != NULL)
+	{
+		SET_NEXT(LPREV(current_elem), LNEXT(current_elem));
+		if (LNEXT(current_elem) != NULL)
+			SET_PREV(LNEXT(current_elem), LPREV(current_elem));
+		
+		_FREE_FUNCTION(current_elem);
+	}
+	else
+	{
+		/* check the preconditions */
+		assert(list == current_elem);
+		
+		if (LNEXT(current_elem) != NULL)
+      {
+			SET_PREV(LNEXT(current_elem), NULL);
+			
+         /* update the new head of the list */
+		   list = LNEXT(current_elem);
+      }
+      else
+         list = NULL;
+		
+		_FREE_FUNCTION(current_elem);
+	}
+	
+	/* postconditions: return the new head of the list */
+	return list;
+}
+
+/* remove all the elements of a list */
+void freeList(t_list *list)
+{
+	/* verify the preconditions */
+	if (list == NULL)
+		return;
+
+	/* recursively call the freeList */
+	freeList(LNEXT(list));
+	
+	/* deallocate memory for the current element of the list */
+	_FREE_FUNCTION(list);
+}
+
+t_list * newElement(void *data)
+{
+	t_list * result;
+	
+	/* create an instance of t_list in memory */
+	result = (t_list *) _ALLOC_FUNCTION(sizeof(t_list));
+
+   /* verify the out of memory condition */
+   if (result == NULL)
+   {
+      fprintf(stderr, "COLLECTIONS.C:: _ALLOC_FUNCTION returned a NULL pointer \n");
+      abort();
+   }
+
+	/* set the internal value of the just created t_list element */
+	SET_DATA(result, data);
+	SET_PREV(result, NULL);
+	SET_NEXT(result, NULL);
+	
+	/* postconditions : return the element */
+	return result;
+}
+
+t_list * getLastElement(t_list *list)
+{
+	/* preconditions */
+	if (list == NULL)
+		return NULL;
+	
+	/* test if the current element is the last element of the list */
+	if (LNEXT(list) == NULL)
+		return list;
+	
+	/* recursively call the getLastElement on the next item of the list */
+	return getLastElement(LNEXT(list));
+}
+
+/* remove a link from the list `list' */
+extern t_list * removeElementLink(t_list *list, t_list *element)
+{
+	t_list *current_elem;
+	
+	/* preconditions */
+	if (list == NULL || element == NULL)
+		return list;
+	
+	if ((LPREV(element) == NULL) && (element != list))
+		return list;
+	
+	/* intialize the value of `current_elem' */
+	current_elem = list;
+	while(	(LDATA(current_elem) != LDATA(element))
+			|| (LPREV(current_elem) != LPREV(element))
+			|| (LNEXT(current_elem) != LNEXT(element)) )
+	{
+		/* retrieve the next element from the list */
+		current_elem = LNEXT(current_elem);
+		
+		/* test if we reached the end of the list */
+		if (current_elem == NULL)
+			return list;
+	}
+
+   if (LPREV(element) == NULL)
+   {
+      assert(list == element);
+      
+      if (LNEXT(element) != NULL)
+      {
+         list = LNEXT(element);
+         SET_PREV(LNEXT(element), NULL);
+      }
+      else
+         list = NULL;
+
+      /* remove the allocated memory of element */
+      _FREE_FUNCTION(element);
+      return list;
+   }
+   
+	/* we found the element */
+	if (LPREV(element) != NULL)
+	{
+		/* we found the element, and it is the top of the list */
+		SET_NEXT(LPREV(element), LNEXT(element));
+	}
+	
+	if (LNEXT(element) != NULL)
+		SET_PREV(LNEXT(element), LPREV(element));
+	
+	/* remove the allocated memory of element */
+	_FREE_FUNCTION(element);
+	
+	/* return the new top of the list */
+	return list;
+}
+
+/* find an element inside the list `list'. The current implementation calls the
+ * CustomfindElement' passing a NULL reference as `func' */
+t_list * findElement(t_list *list, void *data)
+{
+	t_list *current_elem;
+	
+	/* if the list is empty returns a NULL pointer */
+	if (list == NULL)
+		return NULL;
+
+	/* intialize the value of `current_elem' */
+	current_elem = list;
+	while (	(current_elem != NULL)
+			&& (	LDATA(current_elem) != data) )
+	{
+		current_elem = LNEXT(current_elem);
+	}
+	
+	/* postconditions */
+	return current_elem;
+}
+
+/* find an element inside the list `list'. */
+t_list * CustomfindElement(t_list *list, void *data
+		, int (*compareFunc)(void *a, void *b))
+{
+	t_list *current_elem;	
+	
+	/* preconditions */
+	if (compareFunc == NULL)
+		return findElement(list, data);
+	
+	if (list == NULL)
+		return NULL;
+	
+	/* intialize the value of `current_elem' */
+	current_elem = list;
+	while (current_elem != NULL)
+	{
+      void *other_Data;
+
+      other_Data = LDATA(current_elem);
+
+      if (compareFunc(other_Data, data))
+         break;
+      
+		current_elem = LNEXT(current_elem);
+	}	
+
+	/* postconditions */
+	return current_elem;
+}
+
+int getPosition(t_list *list, t_list *element)
+{
+	int counter;
+	
+	/* preconditions */
+	if (list == NULL || element == NULL)
+		return -1;
+	
+	/* initialize the local variable `counter' */
+	counter = 0;
+	
+	if (list == element)
+		return counter;
+	
+	/* update values */
+	counter++;
+	list = LNEXT(list);
+	
+	while (list != NULL)
+	{
+		if (list == element)
+			return counter;
+		
+		counter++;
+		list = LNEXT(list);
+	}
+	
+	return -1;
+}
+
+int getLength(t_list *list)
+{
+	int counter;
+	
+   /* initialize the local variable `counter' */
+   counter = 0;
+
+   /* precondition */
+	if (list == NULL)
+		return counter;
+	
+	while (list != NULL)
+	{
+		counter++;
+		list = LNEXT(list);
+	}
+	
+	/* postconditions: return the length of the list */
+	return counter;
+}
+
+t_list * cloneList(t_list *list)
+{
+   t_list *result;
+   t_list *current_element;
+
+   /* initialize the local variables */
+   result = NULL;
+   current_element = list;
+
+   /* preconditions */
+   if (current_element == NULL)
+      return result;
+
+   while(current_element != NULL)
+   {
+      /* add an element to the new list */
+      result = addElement(result, LDATA(current_element), -1);
+
+      /* retrieve the next element of the list */
+      current_element = LNEXT(current_element);
+   }
+
+   /* return the new list */
+   return result;
+}
+
+t_list * getElementAt(t_list *list, unsigned int position)
+{
+   t_list *result;
+   t_list *current_element;
+   unsigned int current_pos;
+   
+   if (list == NULL)
+      return NULL;
+
+   /* initialize the local variables */
+   result = NULL;
+   current_element = list;
+   current_pos = 0;
+   while((current_element != NULL) && (current_pos < position))
+   {
+      current_element = LNEXT(current_element);
+      current_pos++;
+   }
+
+   /* return the element at the requested position */
+   return current_element;
+}
+
+t_list * addList(t_list *list, t_list *elements)
+{
+   t_list *current_element;
+   void *current_data;
+
+   /* if the list of elements is null, this function
+    * will return `list' unmodified */
+   if (elements == NULL)
+      return list;
+
+   /* initialize the value of `current_element' */
+   current_element = elements;
+   while (current_element != NULL)
+   {
+      /* retrieve the data associated with the current element */
+      current_data = LDATA(current_element);
+      list = addElement(list, current_data, -1);
+
+      /* retrieve the next element in the list */
+      current_element = LNEXT(current_element);
+   }
+
+   /* return the new list */
+   return list;
+}
+
+t_list * addListToSet(t_list *list, t_list *elements
+      , int (*compareFunc)(void *a, void *b), int *modified)
+{
+   t_list *current_element;
+   void *current_data;
+
+   /* if the list of elements is NULL returns the current list */
+   if (elements == NULL)
+      return list;
+
+   /* initialize the value of `current_element' */
+   current_element = elements;
+   while (current_element != NULL)
+   {
+      /* retrieve the data associated with the current element */
+      current_data = LDATA(current_element);
+
+      /* Test if the element was already inserted. */
+      if (CustomfindElement(list, current_data, compareFunc) == NULL)
+      {
+         list = addElement(list, current_data, -1);
+         if (modified != NULL)
+            (* modified) = 1;
+      }
+
+      /* retrieve the next element in the list */
+      current_element = LNEXT(current_element);
+   }
+
+   /* return the new list */
+   return list;
+}
+
+/* add sorted */
+t_list * addSorted(t_list *list, void * data
+            , int (*compareFunc)(void *a, void *b))
+{
+   t_list *current_element;
+   void *current_data;
+   int counter;
+   
+   /* preconditions */
+   if (list == NULL)
+      return addFirst(list, data);
+
+   counter = 0;
+   current_element = list;
+   while(current_element != NULL)
+   {
+      /* get the current interval informations */
+      current_data = LDATA(current_element);
+      assert(current_data != NULL);
+
+      if (compareFunc(current_data, data) >= 0)
+      {
+         list = addElement(list, data, counter);
+         return list;
+      }
+         
+      /* retrieve the next element */
+      current_element = LNEXT(current_element);
+
+      /* update the value of counter */
+      counter++;
+   }
+
+   return addElement(list, data, -1);
+}

+ 102 - 0
assembler/collections.h

@@ -0,0 +1,102 @@
+/*
+ * Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * collections.h
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#ifndef _COLLECTIONS_H
+#define _COLLECTIONS_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+/* macros */
+#define LNEXT(item) ((item)->next)
+#define LPREV(item) ((item)->prev)
+#define LDATA(item) ((item)->data)
+#define SET_DATA(item, _data) ((item)->data = (_data))
+#define SET_NEXT(item, _next) ((item)->next = (_next))
+#define SET_PREV(item, _prev) ((item)->prev = (_prev))
+#ifndef _ALLOC_FUNCTION
+#	define _ALLOC_FUNCTION malloc
+#endif
+#ifndef _FREE_FUNCTION
+#	define _FREE_FUNCTION free
+#endif
+
+/* a list element */
+typedef struct t_list
+{
+	void	*data;
+	struct t_list *next;
+	struct t_list *prev;
+}t_list;
+
+
+/* add an element `data' to the list `list' at position `pos'. If pos is negative
+ * , or is larger than the number of elements in the list, the new element is
+ * added on to the end of the list. Function `addElement' returns a pointer
+ * to the new head of the list */
+extern t_list * addElement(t_list *list, void * data, int pos);
+
+/* add sorted */
+extern t_list * addSorted(t_list *list, void * data
+            , int (*compareFunc)(void *a, void *b));
+
+/* add an element to the end of the list */
+extern t_list * addLast(t_list *list, void * data);
+
+/* add an element at the beginning of the list */
+extern t_list * addFirst(t_list *list, void * data);
+
+/* remove an element at the beginning of the list */
+extern t_list * removeFirst(t_list *list);
+
+/* remove an element from the list */
+extern t_list * removeElement(t_list *list, void * data);
+
+/* remove a link from the list `list' */
+extern t_list * removeElementLink(t_list *list, t_list *element);
+
+/* find an element inside the list `list'. The current implementation calls the
+ * CustomfindElement' passing a NULL reference as `func' */
+extern t_list * findElement(t_list *list, void *data);
+
+/* find an element inside the list `list'. */
+extern t_list * CustomfindElement(t_list *list, void *data
+            , int (*compareFunc)(void *a, void *b));
+
+/* find the position of an `element' inside the `list'. -1 if not found */
+extern int getPosition(t_list *list, t_list *element);
+
+/* find the length of `list' */
+extern int getLength(t_list *list);
+
+/* remove all the elements of a list */
+extern void freeList(t_list *list);
+
+/* get the last element of the list. Returns NULL if the list is empty
+ * or list is a NULL pointer */
+extern t_list * getLastElement(t_list *list);
+
+/* retrieve the list element at position `position' inside the `list'.
+ * Returns NULL if: the list is empty, the list is a NULL pointer or
+ * the list holds less than `position' elements. */
+extern t_list * getElementAt(t_list *list, unsigned int position);
+
+/* create a new list with the same elements */
+extern t_list * cloneList(t_list *list);
+
+/* add a list of elements to another list */
+extern t_list * addList(t_list *list, t_list *elements);
+
+/* add a list of elements to a set */
+extern t_list * addListToSet(t_list *list, t_list *elements
+      , int (*compareFunc)(void *a, void *b), int *modified);
+
+
+#endif

+ 26 - 0
mace/Makefile

@@ -0,0 +1,26 @@
+project = ../bin/mace
+objects = machine.o fetch.o getbits.o decode.o main.o
+deps = $(objects:.o=.d)
+export project objects deps
+
+.PHONY: all clean
+
+all: $(deps)
+	make -f Makefile.all
+
+$(project): $(objects)
+	gcc -o $@ $^
+
+clean:
+	rm -f $(objects) $(deps) $(project) $(project:=.exe)
+
+# Automake dependencies for C/C++ files
+define make-dep
+@echo "Making dependencies for $<..." 
+@$(SHELL) -ec "$(CC) -MM $(CPPFLAGS) $< | sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@; \
+	[ -s $@ ] || rm -f $@"
+endef
+%.d: %.c
+	$(make-dep)
+
+

+ 15 - 0
mace/Makefile.all

@@ -0,0 +1,15 @@
+.PHONY: all
+
+all: $(project)
+
+$(project): $(objects)
+	gcc -o $@ $^
+
+# Implicit rule for C
+%.o: %.c
+	gcc -c -o $@ $<
+
+# Include dependencies
+include $(deps)
+
+

+ 110 - 0
mace/decode.c

@@ -0,0 +1,110 @@
+/*
+ * Giovanni Agosta, Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * decode.c
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+#include <stdlib.h>
+#include "decode.h"
+
+/* Code Names for debug printing  */
+char *names[4][16] = { 
+	{ "ADD", "SUB", "ANDL", "ORL", "EORL", "ANDB", "ORB", "EORB", "MUL", "DIV", "SHL", "SHR", "ROTL", "ROTR", "NEG", "SPCL" },
+	{ "ADDI", "SUBI", "ANDLI", "ORLI", "EORLI", "ANDBI", "ORBI", "EORBI", "MULI", "DIVI", "SHLI", "SHRI", "ROTLI", "ROTRI", "NOTL", "NOTB" },
+	{ "NOP", "MOVA", "JSR", "RET", "LOAD", "STORE", "HALT", "SEQ", "SGE", "SGT", "SLE", "SLT", "SNE", "READ", "WRITE", "ILL15" },
+	{ "BT", "BF", "BHI", "BLS", "BCC", "BCS", "BNE", "BEQ", "BVC", "BVS", "BPL", "BMI", "BGE", "BLT", "BGT", "BLE" } 
+};
+
+decoded_instr *decode(int the_instr) {
+		decoded_instr *instr = (decoded_instr *) malloc(sizeof(decoded_instr));
+		/* decodifica */
+		instr->format = getbits(the_instr,31,30); /* Instruction format (2 bits) */
+		instr->opcode = getbits(the_instr,29,26); /* Opcode (4 bits) */
+		instr->dest   = getbits(the_instr,25,21); /* Destination register */
+		instr->src1   = getbits(the_instr,20,16); /* Source register 1 */
+		instr->src2   = getbits(the_instr,15,11); /* Source register 2 */
+		instr->imm    = getbits(the_instr,15, 0); /* 16 bits immediate value */
+		instr->addr   = getbits(the_instr,19, 0); /* 20 bits immediate address */
+		instr->func   = getbits(the_instr,10, 0); /* 11 extra bits, used to encode extra info */
+      normalizeValues(instr);
+		return instr;
+}		
+
+int carry(decoded_instr *instr){
+	return instr->func & 1;
+}
+
+int sign(decoded_instr *instr){
+	return instr->func & 2;
+}
+
+int indirect_dest(decoded_instr *instr){
+	return instr->func & 4;
+}
+
+int indirect_src2(decoded_instr *instr){
+	return instr->func & 8;
+}
+
+/* Debug printf: print out the current instruction */
+void print(FILE* file, decoded_instr *instr)
+{
+   /* default value for file is stderr */
+   if (file == NULL)
+      file = stderr;
+
+   /* precondition: instr should be different from NULL */
+   if (instr == NULL)
+   {
+      fprintf(file,"[NULL POINTER] \n");
+      return;
+   }
+
+   switch (instr->format)
+   {
+      case FORMAT_TER :
+         fprintf(file,"%s ", names[instr->format][instr->opcode]);
+         if (indirect_dest(instr))
+            fprintf(file,"(R%d) ", instr->dest);
+         else
+            fprintf(file,"R%d ", instr->dest);
+         fprintf(file,"R%d ", instr->src1);
+         if (indirect_src2(instr))
+            fprintf(file,"(R%d) \n", instr->src2);
+         else
+            fprintf(file,"R%d \n", instr->src2);
+         break;
+      case FORMAT_BIN :
+         fprintf(file,"%s R%d, R%d, #%d \n"
+            , names[instr->format][instr->opcode], instr->dest
+                  , instr->src1, instr->imm);
+         break;
+      case FORMAT_UNR :
+         if (instr->opcode == 0 || instr->opcode == 6)
+            fprintf(file,"%s \n", names[instr->format][instr->opcode]);
+         else if (instr->opcode == 13 || instr->opcode == 14)
+            fprintf(file,"%s R%d \n"
+                  , names[instr->format][instr->opcode], instr->dest);
+         else
+            fprintf(file,"%s R%d, $%d \n", names[instr->format][instr->opcode]
+                        , instr->dest, instr->addr);
+         break;
+      case FORMAT_CC :
+         fprintf(file,"%s $%d \n"
+            , names[instr->format][instr->opcode], instr->addr);
+         break;
+      default :
+         fprintf(file,"[UNKNOWN INSTRUCTION FORMAT] \n");
+         break;
+   }
+}
+
+void normalizeValues(decoded_instr *instr)
+{
+   instr->imm = (instr->imm << 16);
+   instr->imm = (instr->imm >> 16);
+   instr->addr = (instr->addr << 12);
+   instr->addr = (instr->addr >> 12);
+}

+ 144 - 0
mace/decode.h

@@ -0,0 +1,144 @@
+/*
+ * Giovanni Agosta, Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * decode.h
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+#ifndef _DECODE_H
+#define _DECODE_H
+
+#include <stdio.h>
+#include "getbits.h"
+
+#define FORMAT_TER 0
+#define FORMAT_BIN 1
+#define FORMAT_UNR 2
+#define FORMAT_CC 3
+
+typedef struct _instr {
+	int opcode;
+	int dest;
+	int src1;
+	int src2;
+	int addr;
+	int imm;
+	int func;
+	int format;
+} decoded_instr;
+
+
+
+/*
+ * Formats ([..] optional elements, default at 0):
+ *  opcode dest src1 src2 [func]
+ *  opcode dest src1 [imm]
+ *  opcode dest [addr]
+ *  ccode [dest] addr
+ */
+decoded_instr *decode(int the_instr);
+
+int carry(decoded_instr *instr);
+
+int sign(decoded_instr *instr);
+
+int indirect_dest(decoded_instr *instr);
+
+int indirect_src2(decoded_instr *instr);
+
+void print(FILE* file, decoded_instr *instr);
+
+void normalizeValues(decoded_instr *instr);
+/*
+
+Formats
+00 opcode dest src1 [src2] [func]
+	0000 ADD
+	0001 SUB
+	0010 ANDL
+	0011 ORL
+	0100 XORL
+	0101 ANDB
+	0110 ORB
+	0111 XORB
+	1000 MUL
+	1001 DIV
+	1010 SHL
+	1011 SHR
+	1100 ROTL
+	1101 ROTR
+	1110 NEG
+	1111 (SPCL, used for extensions)
+
+func bits
+	0 add carry
+	1 signed/unsigned
+	2 indirect addressing dest
+	3 indirect addressing src2
+	4
+	5
+	6
+	7
+	8
+	9
+	10
+	11
+
+01 opcode dest src1 [imm]
+	0000 ADDI
+	0001 SUBI
+	0010 ANDLI
+	0011 ORLI
+	0100 XORLI
+	0101 ANDBI
+	0110 ORBI
+	0111 XORBI
+	1000 MULI
+	1001 DIVI
+	1010 SHLI
+	1011 SHRI
+	1100 ROTLI
+	1101 ROTRI
+	1110 NOTL
+	1111 NOTB
+
+10 opcode [dest] [addr]
+	0000 NOP
+	0001 MOVA
+	0010 JSR
+	0011 RET
+	0100 LOAD
+	0101 STORE
+	0110 HALT
+	0111 SEQ
+	1000 SGE
+	1001 SGT
+	1010 SLE
+	1011 SLT
+	1100 SNE
+	1101 READ
+	1110 WRITE
+	1111 
+
+11 ccode [dest] addr
+	Branch to:
+	0000 T
+	0001 F
+	0010 HI
+	0011 LS
+	0100 CC
+	0101 CS
+	0110 NE
+	0111 EQ
+	1000 VC
+	1001 VS
+	1010 PL
+	1011 MI
+	1100 GE
+	1101 LT
+	1110 GT
+	1111 LE
+	
+*/
+#endif /* _DECODE_H */

+ 339 - 0
mace/fetch.c

@@ -0,0 +1,339 @@
+/*
+ * Giovanni Agosta, Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * fetch.c
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+#include <stdlib.h>
+#include "decode.h"
+#include "fetch.h"
+#include "machine.h"
+
+#define MAX(X,Y) ((X) > (Y) ? (X) : (Y) )
+#define SIGN(X) ((X) >= 0?1:0)
+
+
+static int executeTER(decoded_instr *instr);
+static int executeBIN(decoded_instr *instr);
+static int executeUNR(decoded_instr *instr);
+static int executeJMP(decoded_instr *instr);
+static int handle_special_instruction(decoded_instr *instr);
+
+
+/* returns next pc, negative values are error codes, 0 is correct termination */
+int fetch_execute(unsigned int *code, int pc){
+   int result;
+	decoded_instr *instr = decode(code[pc]);
+
+	switch (instr->format) {
+		case TER : result = executeTER(instr);
+			break;
+		case BIN : result = executeBIN(instr);
+			break;
+		case UNR : result = executeUNR(instr);
+			break;
+		case JMP : result = executeJMP(instr);
+			break;
+		default : result = INVALID_INSTR_FORMAT;
+	}
+
+   /* free the memory associated with `instr' */
+   if (instr != NULL)
+      free(instr);
+
+   /* return the new PC (or the value _HALT) as result */
+   return result;
+}
+
+int executeTER(decoded_instr *instr){
+	int *dest, *src1, *src2;
+	int carryout=0, overflow=0, negative=0, zero=0;
+
+	/* Manage addressing modes (direct/indirect) */
+	if (indirect_dest(instr)) dest=&(mem[reg[instr->dest]]);
+	else dest=&(reg[instr->dest]);
+	src1=&(reg[instr->src1]);
+	if (indirect_src2(instr)) src2=&(mem[reg[instr->src2]]);
+	else src2=&(reg[instr->src2]);
+
+   switch (instr->opcode) {
+		case ADD  : *dest=*src1 + *src2;
+			if (!sign(instr)) {
+				if (carry(instr)) *dest= *dest + getflag(CARRY);
+				if (*dest<*src1 || (getflag(CARRY) && *dest==*src1)) carryout = 1;
+			} else {
+				if (SIGN(*dest)!=SIGN(*src1) && SIGN(src1)==SIGN(*src2)) overflow=1;
+			}
+		 break;
+		case SUB  : *dest=*src1 - *src2; 
+			if (!sign(instr)) {
+				if (carry(instr)) *dest=*dest - getflag(CARRY);
+				if (*dest>*src1 || (getflag(CARRY) && *dest==*src1)) carryout = 1;
+			} else {
+				if (SIGN(*dest)!=SIGN(*src1) && SIGN(src1)==SIGN(*src2)) overflow=1;
+			}
+		 break;
+		case ANDL : *dest = *src1 && *src2 ;
+		 break;
+		case ORL  : *dest = *src1 || *src2 ;
+		 break;
+		case EORL : *dest = (*src1 && !*src2) || (!*src1 && *src2);
+		 break;
+		case ANDB : *dest = *src1 & *src2 ;
+		 break;
+		case ORB  : *dest = *src1 | *src2 ;
+		 break;
+		case EORB : *dest = *src1 ^ *src2 ;
+		 break;
+		case MUL  : *dest=*src1 * *src2; 
+			/* TODO: check carry and overflow */
+			if (!sign(instr)) {
+				if (carry(instr)) *dest= *dest + getflag(CARRY);
+				if (*dest<*src1 || (getflag(CARRY) && *dest==*src1)) carryout = 1;
+			} else {
+				if (SIGN(*dest)!=SIGN(*src1) && SIGN(src1)==SIGN(*src2)) overflow=1;
+			}
+		 break;
+		case DIV  : *dest=*src1 / *src2; 
+			/* TODO: check carry and overflow */
+			if (!sign(instr)) {
+				if (carry(instr)) *dest=*dest - getflag(CARRY);
+				if (*dest>*src1 || (getflag(CARRY) && *dest==*src1)) carryout = 1;
+			} else {
+				if (SIGN(*dest)!=SIGN(*src1) && SIGN(src1)==SIGN(*src2)) overflow=1;
+			}
+		 break;
+		case SHL  : *dest = *src2 << *src1; 
+			if ((!sign(instr)) && carry(instr)) *dest=*dest + getflag(CARRY);
+			/* TODO: carryout */
+		 break;
+		case SHR  : *dest = *src2 >> *src1; /* Should use sign bit to implement arithmetic and logic shift */
+			if ((!sign(instr)) && carry(instr)) *dest=*dest + getflag(CARRY);
+			/* TODO: carryout, signed shift */
+		 break;
+		case ROTL : ;
+		 break;
+		case ROTR : ;
+		 break;
+		case NEG  : *dest = - *src2;
+		 break;
+		case SPCL : pc=handle_special_instruction(instr) ;
+		 break;
+		default :
+         return INVALID_INSTR;
+	}
+	zero = (*dest == 0);
+	negative = (*dest < 0);
+
+	setflag(CARRY,carryout);
+	setflag(OVERFLOW,overflow);
+	setflag(ZERO,zero);
+	setflag(NEGATIVE,negative);
+
+	return pc+1;
+}
+
+int executeBIN(decoded_instr *instr)
+{
+	int *dest, *src1, *src2;
+	int carryout=0, overflow=0, negative=0, zero=0;
+
+	/* Manage addressing modes (direct only) */
+	dest=&(reg[instr->dest]);
+	src1=&(reg[instr->src1]);
+	src2=&(instr->imm);
+
+	switch (instr->opcode) {
+		case ADDI : *dest=*src1 + *src2; 
+				if (SIGN(*dest)!=SIGN(*src1) && SIGN(src1)==SIGN(*src2)) overflow=1;
+		 break;
+		case SUBI : *dest=*src1 - *src2; 
+				if (SIGN(*dest)!=SIGN(*src1) && SIGN(src1)!=SIGN(*src2)) overflow=1;
+		 break;
+		case ANDLI : *dest = *src1 && *src2 ;
+		 break;
+		case ORLI  : *dest = *src1 || *src2 ;
+		 break;
+		case EORLI : *dest = (*src1 && !*src2) || (!*src1 && *src2);
+		 break;
+		case ANDBI : *dest = *src1 & *src2 ;
+		 break;
+		case ORBI  : *dest = *src1 | *src2 ;
+		 break;
+		case EORBI : *dest = *src1 ^ *src2 ;
+		 break;
+		case MULI  : *dest=*src1 * *src2; 
+				if (SIGN(*dest)!=SIGN(*src1) && SIGN(src1)==SIGN(*src2)) overflow=1;
+		 break;
+		case DIVI  : *dest=*src1 / *src2; 
+				if (SIGN(*dest)!=SIGN(*src1) && SIGN(src1)==SIGN(*src2)) overflow=1;
+		 break;
+		case SHLI  : *dest = *src1 << *src2; 
+		 break;
+		case SHRI  : *dest = *src1 >> *src2; 
+		 break;
+		case ROTLI: ;
+		 break;
+		case ROTRI: ;
+		 break;
+		case NOTL : *dest = !*src1 ;
+		 break;
+		case NOTB : *dest = ~*src1 ;
+		 break;
+		default : return INVALID_INSTR;
+	}
+	zero = (*dest == 0);
+	negative = (*dest < 0);
+
+	setflag(CARRY,carryout);
+	setflag(OVERFLOW,overflow);
+	setflag(ZERO,zero);
+	setflag(NEGATIVE,negative);
+	
+	return pc+1;
+}
+
+int executeUNR(decoded_instr *instr){
+	int *dest, src ;
+
+	/* Manage addressing modes (direct only) */
+	dest=&reg[instr->dest];
+	src=instr->addr;
+
+	switch (instr->opcode) {
+		case NOP : /* NOP */
+			break;
+		case HALT : /* HALT */
+			return _HALT;
+			break;
+		case MOVA : *dest = src ; /* Move a 20-bit constant to a register */
+			break;
+      case LOAD : *dest = mem[src];
+         break;
+      case STORE : mem[src] = *dest;
+         break;
+		case JSR : /* Not implemented yet */ ;
+			break;
+		case RET : /* Not implemented yet */ ;
+			break;
+      case SEQ :  *dest = getflag(ZERO);
+                  setflag(ZERO, (*dest == 0));
+                  setflag(NEGATIVE, 0);
+                  setflag(CARRY, 0);
+                  setflag(OVERFLOW, 0);
+                  break;
+      case SGT :  *dest = ( ( getflag(NEGATIVE) && getflag(OVERFLOW)
+                              && (!getflag(ZERO)))
+                           || (!getflag(NEGATIVE) && !getflag(OVERFLOW)
+                              && !getflag(ZERO)) );
+                  setflag(ZERO, (*dest == 0));
+                  setflag(NEGATIVE, 0);
+                  setflag(CARRY, 0);
+                  setflag(OVERFLOW, 0);
+                  break;
+      case SGE :  *dest = ((getflag(NEGATIVE) && getflag(OVERFLOW))
+                           || (!getflag(NEGATIVE) && !getflag(OVERFLOW)));
+                  setflag(ZERO, (*dest == 0));
+                  setflag(NEGATIVE, 0);
+                  setflag(CARRY, 0);
+                  setflag(OVERFLOW, 0);
+                  break;
+      case SLE :  *dest = (getflag(ZERO) || (getflag(NEGATIVE) && !getflag(OVERFLOW))
+                               || (!getflag(NEGATIVE) && getflag(OVERFLOW)));
+                  setflag(ZERO, (*dest == 0));
+                  setflag(NEGATIVE, 0);
+                  setflag(CARRY, 0);
+                  setflag(OVERFLOW, 0);
+                  break;
+      case SLT :  *dest = ( (getflag(NEGATIVE) && !getflag(OVERFLOW))
+                               || (!getflag(NEGATIVE) && getflag(OVERFLOW)));
+                  setflag(ZERO, (*dest == 0));
+                  setflag(NEGATIVE, 0);
+                  setflag(CARRY, 0);
+                  setflag(OVERFLOW, 0);
+                  break;
+      case SNE :  *dest = !getflag(ZERO);
+                  setflag(ZERO, (*dest == 0));
+                  setflag(NEGATIVE, 0);
+                  setflag(CARRY, 0);
+                  setflag(OVERFLOW, 0);
+                  break;
+      case READ : fputs("int value? >", stdout);
+                  fscanf(stdin, "%d", dest);
+         break;
+      case WRITE : fprintf(stdout, "%d\n", (*dest) );
+         break;
+		default : return INVALID_INSTR;
+	}
+
+   /* update the value of program counter */
+	return pc+1;
+}
+
+int executeJMP(decoded_instr *instr){
+	/*
+	 * Handles Bcc instructions 
+	 * (see M68000 docs for an overview of the possible branches)
+	 */
+	int src;
+   int taken;
+
+   /* initialize src */
+   src = instr->addr;
+   taken = 0;
+   
+	switch (instr->opcode) {
+		case BT : if (1) taken = 1;
+			break;
+		case BF : if (0) taken = 1;
+			break;
+		case BHI : if (!(getflag(CARRY)||getflag(ZERO))) taken = 1;
+			break;
+		case BLS : if (getflag(CARRY)||getflag(ZERO)) taken = 1;
+			break;
+		case BCC : if (!getflag(CARRY)) taken = 1;
+			break;
+		case BCS : if (getflag(CARRY)) taken = 1;
+			break;
+		case BNE : if (!getflag(ZERO)) taken = 1;
+			break;
+		case BEQ : if (getflag(ZERO)) taken = 1;
+			break;
+		case BVC : if (!getflag(OVERFLOW)) taken = 1;
+			break;
+		case BVS : if (getflag(OVERFLOW)) taken = 1;
+			break;
+		case BPL : if (!getflag(NEGATIVE)) taken = 1;
+			break;
+		case BMI : if (getflag(NEGATIVE)) taken = 1;
+			break;
+		case BGE : if (!(getflag(NEGATIVE)^getflag(OVERFLOW))) taken = 1;
+			break;
+		case BLT : if (getflag(NEGATIVE)^getflag(OVERFLOW)) taken = 1;
+			break;
+		case BGT : if (   !(getflag(ZERO)
+                        ||(getflag(NEGATIVE)^getflag(OVERFLOW)))) taken = 1;
+			break;
+		case BLE : if (getflag(ZERO)||(getflag(NEGATIVE)^getflag(OVERFLOW))) taken = 1;
+			break;
+		default : return INVALID_INSTR;
+	}
+
+   /* test if the branch is taken or not */
+   if (taken)
+	   pc += src;
+   else
+      pc++;
+
+   return pc;
+}
+
+
+int handle_special_instruction(decoded_instr *instr){
+	/* here should be inserted code to handle special instructions
+	 * using the function bits
+	 */
+	return INVALID_INSTR;
+}

+ 14 - 0
mace/fetch.h

@@ -0,0 +1,14 @@
+/*
+ * Giovanni Agosta, Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * fetch.h
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+#ifndef _FETCH_H
+#define _FETCH_H
+
+int fetch_execute(unsigned int *code, int pc);
+
+#endif /* _FETCH_H */

+ 23 - 0
mace/getbits.c

@@ -0,0 +1,23 @@
+/*
+ * Giovanni Agosta, Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * getbits.c
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include "getbits.h"
+
+unsigned int getbits(unsigned int data, int from, int to){
+   unsigned int res;
+   unsigned int mask;
+
+   mask = (0xFFFFFFFF >> (31 - from));
+   res = data & mask;
+   mask = (0xFFFFFFFF << to);
+   res = res & mask;
+   res = res >> to;
+  return res;
+}

+ 13 - 0
mace/getbits.h

@@ -0,0 +1,13 @@
+/*
+ * Giovanni Agosta, Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * getbits.h
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+#ifndef _GETBITS_H
+#define _GETBITS_H
+/* Estrae i bit di data da from a to come unsigned int */
+unsigned int getbits(unsigned int data, int from, int to);
+#endif /* _GETBITS_H */

+ 96 - 0
mace/machine.c

@@ -0,0 +1,96 @@
+/*
+ * Giovanni Agosta, Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * machine.c
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+
+#include "machine.h"
+
+/* Debug printf, print the value of the status word */
+void print_psw(FILE *file)
+{
+   /* precondition */
+   if (file == NULL)
+      file = stderr;
+
+   fprintf(file, "PSW=[0x%08x]\n", psw);
+   fprintf(file,  "CARRY (C):\t %d\nOVERFLOW (V):\t %d\n"
+                  "ZERO (Z):\t %d\nNEGATIVE (N):\t %d\n\n"
+                  , getflag(CARRY), getflag(OVERFLOW)
+                  , getflag(ZERO), getflag(NEGATIVE));
+}
+
+/* Debug printf, print the content of the register file */
+void print_regs(FILE *file)
+{
+	int i;
+
+   /* precondition */
+   if (file == NULL)
+      file = stderr;
+   
+   fprintf(file, "\n*** REGISTER FILE STATUS ***\n");
+	for (i=0; i<NREGS / 8; i++)
+	   fprintf(file,"R%d =[0x%08x]\t", i, reg[i]);
+   fprintf(file, "\n");
+   for (i=NREGS / 8; i<NREGS / 4; i++)
+      fprintf(file,"R%d =[0x%08x]\t", i, reg[i]);
+   fprintf(file, "\n");
+   for (i=NREGS / 4; i< (3*NREGS / 8); i++)
+   {
+      if (i < 10)
+         fprintf(file,"R%d =[0x%08x]\t", i, reg[i]);
+      else
+         fprintf(file,"R%d=[0x%08x]\t", i, reg[i]);
+   }
+   fprintf(file, "\n");
+   for (i=(3*NREGS / 8); i<NREGS / 2; i++)
+      fprintf(file,"R%d=[0x%08x]\t", i, reg[i]);
+   fprintf(file, "\n");
+   for (i= NREGS / 2; i<(5*NREGS / 8); i++)
+      fprintf(file,"R%d=[0x%08x]\t", i, reg[i]);
+   fprintf(file, "\n");
+   for (i=(5*NREGS / 8); i<(6*NREGS / 8); i++)
+      fprintf(file,"R%d=[0x%08x]\t", i, reg[i]);
+   fprintf(file, "\n");
+   for (i=(6*NREGS / 8); i<(7*NREGS / 8); i++)
+      fprintf(file,"R%d=[0x%08x]\t", i, reg[i]);
+   fprintf(file, "\n");
+   for (i=(7*NREGS / 8); i<NREGS; i++)
+      fprintf(file,"R%d=[0x%08x]\t", i, reg[i]);
+	fprintf(file,"\n");
+}
+
+/* Debug, execute a memory dump      */
+void print_Memory_Dump(FILE *file, int lcode)
+{
+	int i;
+
+   /* if not specified, `file' is set to stderr */
+   if (file == NULL)
+      file = stderr;
+   
+	fprintf(file,"*** Memory Dump *** \n");
+	for (i=0; i<lcode; i++)
+	   fprintf(file,"[0x%08x]\n", mem[i]);
+   
+	fprintf(file,"*** END Memory Dump *** \n");
+}
+
+/* Get flag from processor status word */
+unsigned int getflag(int flag)
+{
+	return getbits(psw, flag, flag);
+}
+
+/* Set flag in processor status word*/
+void setflag(int flag, int value){
+	int mask = 1<<flag;
+	if (value)
+		psw = psw | mask;
+	else 
+		psw = psw & ~mask;
+}

+ 56 - 0
mace/machine.h

@@ -0,0 +1,56 @@
+/*
+ * Giovanni Agosta, Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * machine.h
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+#ifndef _MACHINE_H
+#define _MACHINE_H
+
+#define NREGS 32
+#define MEMSIZE 4096
+
+#define _HALT -1
+
+#include <stdio.h>
+#include "getbits.h"
+
+/* FORMATS 0 to 3 */
+enum formats { TER, BIN, UNR, JMP };
+
+/* OPCODES (da 0 a 15)            */
+enum opcTER { ADD, SUB, ANDL, ORL, EORL, ANDB, ORB, EORB, MUL, DIV, SHL, SHR, ROTL, ROTR, NEG, SPCL };
+enum opcBIN { ADDI, SUBI, ANDLI, ORLI, EORLI, ANDBI, ORBI, EORBI, MULI, DIVI, SHLI, SHRI, ROTLI, ROTRI, NOTL, NOTB };
+enum opcUNR { NOP, MOVA, JSR, RET, LOAD, STORE, HALT, SEQ, SGE, SGT, SLE, SLT, SNE, READ, WRITE, /* 1 UNISED */};
+enum opcJMP { BT, BF, BHI, BLS,	BCC, BCS, BNE, BEQ, BVC, BVS, BPL, BMI, BGE, BLT, BGT, BLE };
+
+/* Possibili terminazioni (OK e' corretta) */
+enum term  { OK, NOARGS, NOFILE, INVALID_INSTR, INVALID_INSTR_FORMAT, MEM_FAULT, WRONG_FORMAT, WRONG_ARGS, BREAK };
+
+/* Modi di esecuzione */
+enum modes { BASIC, SEGMENTED };
+
+/* Dichiarazione degli elementi di memoria */
+int reg[NREGS];
+
+void print_regs(FILE *file);
+void print_psw(FILE *file);
+
+int mem[MEMSIZE];
+
+void print_Memory_Dump(FILE *file, int begin);
+
+unsigned int pc;  /* the program counter      */
+int psw; /* the four condition flags */
+
+enum flags { CARRY, OVERFLOW, ZERO, NEGATIVE } ;
+
+/* Get flag from processor status word */
+unsigned int getflag(int flag);
+
+/* Set flag in processor status word*/
+void setflag(int flag, int value);
+
+#endif /* _MACHINE_H */

+ 216 - 0
mace/main.c

@@ -0,0 +1,216 @@
+/*
+ * Giovanni Agosta, Andrea Di Biagio
+ * Politecnico di Milano, 2007
+ * 
+ * main.c
+ * Formal Languages & Compilers Machine, 2007/2008
+ * 
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "fetch.h"
+#include "machine.h"
+#include "decode.h"
+
+int main(int argc, char **argv)
+{
+	FILE *fp;       		/* pointer to the object file    */
+	int len=0;      		/* length of the object file   */
+	unsigned int *code=NULL;	/* pointer to the code block */
+	int lcode = 0;  		/* length of the code block         */
+	int mmgmt=BASIC;		/* memory management */
+	int i;
+	int breakat=-1; 		/* break execution at instruction # */
+	int count=0;    		/* iterations counter    */
+	pc=0;           		/* PC register is set ot zero in the beginning */
+#ifdef DEBUG
+   decoded_instr *current_instr;
+#endif
+	
+	/* Apertura del file oggetto */
+	if (argc<2)
+	{
+		/* L'esecuzione termina poichè non è stato specificato il file
+		 * oggetto come argomento */
+		fprintf(stdout, "Formal Languages & Compilers Machine, 2007/2008.\n"
+			"\n\nSyntax:\n\tmace [options] objectfile\n");
+	  	return NOARGS;
+	}
+	
+	/* apre il file oggetto specificato come argomento */
+  	fp = fopen(argv[argc-1],"r");
+	if (fp == NULL)
+	{
+		fprintf(stderr,"Object file %s doesn't exist.\n", argv[argc-1]);
+		
+		/* termina l'esecuzione in quanto è stato specificato un file
+		 * oggetto inesistente */
+		return NOFILE;
+	}
+	
+	for(i=1; i<argc-1; i++)
+	{
+		if (strcmp(argv[i],"segmented")==0) 
+			mmgmt = SEGMENTED;
+		else if (strcmp(argv[i],"break")==0)
+		{
+			char *error;
+			
+			/* legge il prossimo argomento come numero in base 10 */
+			breakat = strtol(argv[i+1],&error,10);
+			
+			if (*error != '\0')
+			{
+				/* errore nella lettura dell'argomento */
+				#ifdef DEBUG
+				fprintf(stderr,"Error while reading option "
+					"break: %d=%c, string=%s "
+					"=> %d.\n",*error,*error,argv[i+1],breakat);
+				#endif
+				return WRONG_ARGS;
+      			}
+			i++; /* salta l'argomento gia' letto */
+		}
+	}
+
+	#ifdef DEBUG
+	fprintf(stderr,"Running with %s memory \n", (mmgmt == BASIC)? "BASIC" : "SEGMENTED");
+	#endif
+	
+	/* Resetta i registri e la memoria */
+	for (i=0; i<NREGS; i++) reg[i] = 0;
+	for (i=0; i<MEMSIZE; i++) mem[i] = 0;
+	
+	/* Calcola lunghezza del file */
+	fseek(fp,0,SEEK_END);
+	len = ftell(fp);
+	fseek(fp,0,SEEK_SET);
+	
+   #ifdef DEBUG
+   fprintf(stderr,"Available memory: %d. "
+               "Requested memory: %d \n", MEMSIZE, len);
+   #endif
+   
+	if (mmgmt==BASIC)
+	{
+		/* Usa una sola area di memoria per codice e dati */
+		if (len>MEMSIZE)
+		{
+			fprintf(stderr,"Out of memory.\n");
+	
+			return MEM_FAULT;
+		}
+    		
+		code = (unsigned int*)mem;
+	} else
+	{
+		/* Alloca spazio in memoria per il codice */
+		code = (unsigned int*) malloc(sizeof(unsigned int)*len);
+	}
+
+	/* Carica il codice macchina in memoria   */
+	for (i=0; i<len; i=i+2)
+	{
+		if (i==0)
+      {
+         unsigned int c1,c2,c3,c4;
+         c1 = fgetc(fp);
+         c2 = fgetc(fp);
+         c3 = fgetc(fp);
+         c4 = fgetc(fp);
+
+         if (c1!='L' && c2 != 'F' && c3!='C' && c4!='M')
+		   {
+			   #ifdef DEBUG
+			   fprintf(stderr,"Wrong object file format.\n");
+			   #endif
+		  
+			   return WRONG_FORMAT;
+		   }
+         else
+         {
+            int value[4];
+            int found;
+            int count;
+
+            /* initialize the local variables */
+            count = 0;
+            found = 0;
+            memset(value, 0, 4);
+
+            while (count < 4)
+            {
+               found += fread(value + count, 4, 1, fp);
+
+               /* verify the header format */
+               if (value[count] != 0)
+               {
+                  #ifdef DEBUG
+                  fprintf(stderr,"Wrong object file format.\n");
+                  #endif
+        
+                  return WRONG_FORMAT;
+               }
+               count ++;
+            }
+          }
+      }
+		
+		if (!fread(code + lcode, 4, 1, fp))
+         break;
+		
+		lcode++;
+	}
+   #ifdef DEBUG
+   fprintf(stderr,"Starting execution.\n");
+   print_regs(stderr);
+   print_psw(stderr);
+   print_Memory_Dump(stderr, lcode);
+   if (pc < lcode) {
+      current_instr = decode(code[0]);
+      print(stderr, current_instr);
+      free(current_instr);
+   }
+   #endif
+
+   /* decodifica ed esegue il codice */
+	for (pc=0; pc<lcode && pc>=0; )
+	{
+      pc = fetch_execute(code,pc);
+
+#ifdef DEBUG
+      print_regs(stderr);
+      print_psw(stderr);
+      print_Memory_Dump(stderr, lcode);
+#endif
+
+		reg[0]=0; /* reset R0 to 0; R0 is wired to 0, so we ignore all writes */
+
+		count++; /* conta le istruzioni eseguite */
+		if ((breakat>0) && (breakat<=count))
+		{
+			#ifdef DEBUG
+			fprintf(stderr,"Break after %d instructions.\n",count);
+			#endif
+			return BREAK;
+		}
+		
+		/* Check the HALT condition */
+		if (pc == _HALT)
+			return OK;
+
+#ifdef DEBUG
+      current_instr = decode(code[pc]);
+      fprintf(stderr,"\n\n");
+      print(stderr, current_instr);
+      free(current_instr);
+#endif
+	}
+	
+	#ifdef DEBUG
+	fprintf(stderr,"Memory access error.\n");
+	#endif
+	
+	return pc;
+}

+ 12 - 0
tests/Makefile

@@ -0,0 +1,12 @@
+asm=$(CURDIR)/../bin/asm
+acse=$(CURDIR)/../bin/acse
+export asm acse
+dirs:=arrays sum dowhile fact mult_table power semi assign arrays arrays2 misc
+
+test :
+	for i in $(dirs); do $(MAKE) -C $$i -f ../Makefile.test ; done
+
+.PHONY : test clean
+
+clean :
+	for i in $(dirs); do $(MAKE) -C $$i -f ../Makefile.test clean ; done

+ 19 - 0
tests/Makefile.test

@@ -0,0 +1,19 @@
+objects=$(patsubst %.src,%.o,$(wildcard *.src))
+
+test : $(objects)
+
+%.o : %.asm
+	$(asm) $< $@	
+
+%.asm : %.src
+	$(acse) $< $@
+
+.PRECIOUS : %.asm
+
+.PHONY : clean test
+
+clean :
+	rm -f *.out
+	rm -f *.cfg
+	rm -f *.asm
+	rm -f *.o

+ 121 - 0
tests/arrays/arrays.src

@@ -0,0 +1,121 @@
+int b,d;
+int a[21];
+int c;
+
+/*b = 5;*/
+
+
+a[0] = 0;
+a[1] = 1;
+a[2] = 2;
+a[3] = 3;
+a[4] = 4;
+a[5] = 5;
+a[6] = 6;
+a[7] = 7;
+a[8] = 8;
+a[9] = 9;
+a[10] = 10;
+a[11] = 11;
+a[12] = 12;
+a[13] = 13;
+a[14] = 14;
+a[15] = 15;
+a[16] = 16;
+a[17] = 17;
+a[18] = 18;
+a[19] = 19;
+a[20] = 20;
+
+
+b = a[0];
+
+write(b);
+b = a[1];
+
+write(b);
+b = a[2];
+
+write(b);
+b = a[3];
+
+write(b);
+b = a[4];
+
+write(b);
+b = a[5];
+
+write(b);
+b = a[6];
+
+write(b);
+b = a[7];
+
+write(b);
+b = a[8];
+
+write(b);
+b = a[9];
+
+write(b);
+b = a[10];
+
+write(b);
+b = a[11];
+
+write(b);
+b = a[12];
+
+write(b);
+b = a[13];
+
+write(b);
+b = a[14];
+
+write(b);
+b = a[15];
+
+write(b);
+b = a[16];
+
+write(b);
+b = a[17];
+
+write(b);
+b = a[18];
+
+write(b);
+b = a[19];
+
+write(b);
+
+b = a[20];
+write(b); /* 20 */
+write(c); /* 0 */
+c = a[20];
+write(c); /* 20 */
+c = b;
+write(c); /* 20 */
+c = b + a[20]; 
+write(c); /* 40 */
+c = b + a[20] + 5 + a[17];
+write(c); /* 62 */
+/* write(d); */ 
+d = c + a[15] + 12;
+write(d); /* 89 */
+/*b = a[2];*/ 
+write(d); /* 89 */
+write(b); /* 20 */
+write(d); /* 89 */
+write(d); /* 89 */
+b = a[3]; 
+write(d); /* 89 */
+write(b); /* 3 */
+write(d); /* 89 */
+b = a[4]; 
+write(b); /* 4 */
+write(d); /* 89 */
+
+/* write(c); */ /* 62 */
+/* write(d); */ /* 89 */
+

+ 27 - 0
tests/arrays2/arrays2.src

@@ -0,0 +1,27 @@
+int a,b;
+int c[5], d[6];
+int e,f,g;
+
+read(a); /* 11 */ /* -11 */
+read(b); /* 23 */ /* 22 */
+
+if (a > 0)
+{
+	c[0] = 1;
+	d[0] = a;
+	c[1] = c[0] + d[0] + b;
+}
+else
+{
+	c[0] = a;   /* -11 */
+	d[0] = a + b;  /* 11 */
+	c[1] = c[0] - d[0];  /* -22 */
+}
+
+e = c[0]; /* 1 */    /* -11 */
+f = c[1]; /* 35 */   /* -22 */
+g = d[0]; /* 11 */   /* 11 */
+write(e);
+write(f);
+write(g);
+

+ 13 - 0
tests/assign/assign.src

@@ -0,0 +1,13 @@
+int a,b,c;
+int result;
+
+read(a);
+read(b);
+read(c);
+
+result = a + b;
+
+result = result + c;
+
+write(result);
+

+ 12 - 0
tests/dowhile/dowhile.src

@@ -0,0 +1,12 @@
+int a,b;
+
+a = 0;
+read(b);
+
+do
+{
+	a = a + 1;
+	b = b - 1;
+}while(b > 0);
+
+write(a);

+ 6 - 0
tests/errors/error1.src

@@ -0,0 +1,6 @@
+int a,b,c;
+
+d = 5;
+a = 7;
+
+write(a + d);

+ 6 - 0
tests/errors/error2.src

@@ -0,0 +1,6 @@
+int a,b,c;
+int d,c;
+
+a = b+c;
+b = c+d;
+c = d+a;

+ 7 - 0
tests/errors/errore.src

@@ -0,0 +1,7 @@
+int a,b,y;
+
+a = 35
+b = 4;
+c = 7;
+
+a = b+c;

+ 20 - 0
tests/fact/fact.src

@@ -0,0 +1,20 @@
+int value, fact;
+
+read(value);
+
+if (value < 0)
+{
+	write(-1);
+	return;
+}
+
+fact = 1;
+
+while(value > 0)
+{
+	fact = value * fact;
+	value = value - 1;
+}
+
+write(fact);
+

+ 9 - 0
tests/misc/while0.src

@@ -0,0 +1,9 @@
+int x;
+
+read(x);
+
+while (0) {
+   write(0);
+}
+
+write(x);

+ 22 - 0
tests/misc/while1.src

@@ -0,0 +1,22 @@
+int a[10];
+int x = 0;
+int k = 0;
+
+while (k < 10) {
+  read(x);
+  a[k] = x;
+  k = k + 1;
+}
+x = a[9];
+
+/* Look for the first occurrence of the last element */
+k = 0;
+while (1) {
+  /* Not actually an infinite loop:
+     we cannot go beyond the last element */
+  if (x == a[k]) {
+    write(k);
+    return;
+  }
+  k = k + 1;
+}

+ 14 - 0
tests/misc/while_id.src

@@ -0,0 +1,14 @@
+int s = 0;
+int x;
+
+read(x);
+
+if (x >= 0) {
+   while (x) {
+      s = s + x;
+      x = x - 1;
+   }
+   write(s);
+} else {
+   write(-1);
+}

+ 12 - 0
tests/mult_table/mult_table.src

@@ -0,0 +1,12 @@
+int value, counter;
+
+read(value);
+
+counter = 1;
+
+while(counter <= 10)
+{
+	write(value * counter);
+	counter = counter + 1;
+}
+

+ 36 - 0
tests/power/power.src

@@ -0,0 +1,36 @@
+/*
+*	Author: Andrea Di Biagio
+*	power.src
+*/
+
+int value, result, power, negative;
+
+read(value);
+read(power);
+
+if (power == 0)
+{
+	write(0);
+	return;
+}
+
+if (power < 0)
+{
+	negative = 1;
+	power = -power;
+}
+else
+ 	negative = 0;
+
+result = value;
+while (power > 1)
+{
+	result = result * value;
+	power = power - 1;
+}
+
+if (negative == 1)
+	result = 1 / result;
+
+write(result);
+

+ 13 - 0
tests/semi/semi.src

@@ -0,0 +1,13 @@
+int a,b;
+int c;
+
+;
+
+read(a);
+read(b);
+
+c = a + b;
+
+;
+
+write(c);

+ 18 - 0
tests/spilltest/spilltest.src

@@ -0,0 +1,18 @@
+int a;
+int b[5];
+int c;
+
+b[0] = 0;
+b[1] = 1;
+b[2] = 2;
+b[3] = 3;
+b[4] = 4;
+
+a = b[0] + 2;
+write(a); /* 2 */
+a = a + b[1];
+write(a); /* 3 */
+a = a + b[2];
+write(a); /* 5 */
+c = a + b[4];
+write(c); /* 9 */

+ 8 - 0
tests/sum/sum.src

@@ -0,0 +1,8 @@
+int a,b,somma;
+
+read(a);
+read(b);
+
+somma = a + b;
+
+write(somma);

+ 209 - 0
tests/sum/tests

@@ -0,0 +1,209 @@
+Running with memory 0
+Available memory: 4096. Requested memory: 68 
+Starting execution.
+
+*** REGISTER FILE STATUS ***
+R0 =[0x00000000]	R1 =[0x00000000]	R2 =[0x00000000]	R3 =[0x00000000]	
+R4 =[0x00000000]	R5 =[0x00000000]	R6 =[0x00000000]	R7 =[0x00000000]	
+R8 =[0x00000000]	R9 =[0x00000000]	R10=[0x00000000]	R11=[0x00000000]	
+R12=[0x00000000]	R13=[0x00000000]	R14=[0x00000000]	R15=[0x00000000]	
+R16=[0x00000000]	R17=[0x00000000]	R18=[0x00000000]	R19=[0x00000000]	
+R20=[0x00000000]	R21=[0x00000000]	R22=[0x00000000]	R23=[0x00000000]	
+R24=[0x00000000]	R25=[0x00000000]	R26=[0x00000000]	R27=[0x00000000]	
+R28=[0x00000000]	R29=[0x00000000]	R30=[0x00000000]	R31=[0x00000000]	
+PSW=[0x00000000]
+CARRY (C):	 0
+OVERFLOW (V):	 0
+ZERO (Z):	 0
+NEGATIVE (N):	 0
+
+*** Stack *** 
+*** END Stack *** 
+READ R1 
+
+*** REGISTER FILE STATUS ***
+R0 =[0x00000000]	R1 =[0xfffffff5]	R2 =[0x00000000]	R3 =[0x00000000]	
+R4 =[0x00000000]	R5 =[0x00000000]	R6 =[0x00000000]	R7 =[0x00000000]	
+R8 =[0x00000000]	R9 =[0x00000000]	R10=[0x00000000]	R11=[0x00000000]	
+R12=[0x00000000]	R13=[0x00000000]	R14=[0x00000000]	R15=[0x00000000]	
+R16=[0x00000000]	R17=[0x00000000]	R18=[0x00000000]	R19=[0x00000000]	
+R20=[0x00000000]	R21=[0x00000000]	R22=[0x00000000]	R23=[0x00000000]	
+R24=[0x00000000]	R25=[0x00000000]	R26=[0x00000000]	R27=[0x00000000]	
+R28=[0x00000000]	R29=[0x00000000]	R30=[0x00000000]	R31=[0x00000000]	
+PSW=[0x00000000]
+CARRY (C):	 0
+OVERFLOW (V):	 0
+ZERO (Z):	 0
+NEGATIVE (N):	 0
+
+*** Stack *** 
+*** END Stack *** 
+
+
+READ R2 
+
+*** REGISTER FILE STATUS ***
+R0 =[0x00000000]	R1 =[0xfffffff5]	R2 =[0x00000016]	R3 =[0x00000000]	
+R4 =[0x00000000]	R5 =[0x00000000]	R6 =[0x00000000]	R7 =[0x00000000]	
+R8 =[0x00000000]	R9 =[0x00000000]	R10=[0x00000000]	R11=[0x00000000]	
+R12=[0x00000000]	R13=[0x00000000]	R14=[0x00000000]	R15=[0x00000000]	
+R16=[0x00000000]	R17=[0x00000000]	R18=[0x00000000]	R19=[0x00000000]	
+R20=[0x00000000]	R21=[0x00000000]	R22=[0x00000000]	R23=[0x00000000]	
+R24=[0x00000000]	R25=[0x00000000]	R26=[0x00000000]	R27=[0x00000000]	
+R28=[0x00000000]	R29=[0x00000000]	R30=[0x00000000]	R31=[0x00000000]	
+PSW=[0x00000000]
+CARRY (C):	 0
+OVERFLOW (V):	 0
+ZERO (Z):	 0
+NEGATIVE (N):	 0
+
+*** Stack *** 
+*** END Stack *** 
+
+
+ADD R3 R1 R2 
+
+*** REGISTER FILE STATUS ***
+R0 =[0x00000000]	R1 =[0xfffffff5]	R2 =[0x00000016]	R3 =[0x0000000b]	
+R4 =[0x00000000]	R5 =[0x00000000]	R6 =[0x00000000]	R7 =[0x00000000]	
+R8 =[0x00000000]	R9 =[0x00000000]	R10=[0x00000000]	R11=[0x00000000]	
+R12=[0x00000000]	R13=[0x00000000]	R14=[0x00000000]	R15=[0x00000000]	
+R16=[0x00000000]	R17=[0x00000000]	R18=[0x00000000]	R19=[0x00000000]	
+R20=[0x00000000]	R21=[0x00000000]	R22=[0x00000000]	R23=[0x00000000]	
+R24=[0x00000000]	R25=[0x00000000]	R26=[0x00000000]	R27=[0x00000000]	
+R28=[0x00000000]	R29=[0x00000000]	R30=[0x00000000]	R31=[0x00000000]	
+PSW=[0x00000000]
+CARRY (C):	 0
+OVERFLOW (V):	 0
+ZERO (Z):	 0
+NEGATIVE (N):	 0
+
+*** Stack *** 
+*** END Stack *** 
+
+
+STORE R2, $10 
+
+*** REGISTER FILE STATUS ***
+R0 =[0x00000000]	R1 =[0xfffffff5]	R2 =[0x00000016]	R3 =[0x0000000b]	
+R4 =[0x00000000]	R5 =[0x00000000]	R6 =[0x00000000]	R7 =[0x00000000]	
+R8 =[0x00000000]	R9 =[0x00000000]	R10=[0x00000000]	R11=[0x00000000]	
+R12=[0x00000000]	R13=[0x00000000]	R14=[0x00000000]	R15=[0x00000000]	
+R16=[0x00000000]	R17=[0x00000000]	R18=[0x00000000]	R19=[0x00000000]	
+R20=[0x00000000]	R21=[0x00000000]	R22=[0x00000000]	R23=[0x00000000]	
+R24=[0x00000000]	R25=[0x00000000]	R26=[0x00000000]	R27=[0x00000000]	
+R28=[0x00000000]	R29=[0x00000000]	R30=[0x00000000]	R31=[0x00000000]	
+PSW=[0x00000000]
+CARRY (C):	 0
+OVERFLOW (V):	 0
+ZERO (Z):	 0
+NEGATIVE (N):	 0
+
+*** Stack *** 
+*** END Stack *** 
+
+
+STORE R1, $9 
+
+*** REGISTER FILE STATUS ***
+R0 =[0x00000000]	R1 =[0xfffffff5]	R2 =[0x00000016]	R3 =[0x0000000b]	
+R4 =[0x00000000]	R5 =[0x00000000]	R6 =[0x00000000]	R7 =[0x00000000]	
+R8 =[0x00000000]	R9 =[0x00000000]	R10=[0x00000000]	R11=[0x00000000]	
+R12=[0x00000000]	R13=[0x00000000]	R14=[0x00000000]	R15=[0x00000000]	
+R16=[0x00000000]	R17=[0x00000000]	R18=[0x00000000]	R19=[0x00000000]	
+R20=[0x00000000]	R21=[0x00000000]	R22=[0x00000000]	R23=[0x00000000]	
+R24=[0x00000000]	R25=[0x00000000]	R26=[0x00000000]	R27=[0x00000000]	
+R28=[0x00000000]	R29=[0x00000000]	R30=[0x00000000]	R31=[0x00000000]	
+PSW=[0x00000000]
+CARRY (C):	 0
+OVERFLOW (V):	 0
+ZERO (Z):	 0
+NEGATIVE (N):	 0
+
+*** Stack *** 
+*** END Stack *** 
+
+
+ADD R1 R0 R3 
+
+*** REGISTER FILE STATUS ***
+R0 =[0x00000000]	R1 =[0x0000000b]	R2 =[0x00000016]	R3 =[0x0000000b]	
+R4 =[0x00000000]	R5 =[0x00000000]	R6 =[0x00000000]	R7 =[0x00000000]	
+R8 =[0x00000000]	R9 =[0x00000000]	R10=[0x00000000]	R11=[0x00000000]	
+R12=[0x00000000]	R13=[0x00000000]	R14=[0x00000000]	R15=[0x00000000]	
+R16=[0x00000000]	R17=[0x00000000]	R18=[0x00000000]	R19=[0x00000000]	
+R20=[0x00000000]	R21=[0x00000000]	R22=[0x00000000]	R23=[0x00000000]	
+R24=[0x00000000]	R25=[0x00000000]	R26=[0x00000000]	R27=[0x00000000]	
+R28=[0x00000000]	R29=[0x00000000]	R30=[0x00000000]	R31=[0x00000000]	
+PSW=[0x00000000]
+CARRY (C):	 0
+OVERFLOW (V):	 0
+ZERO (Z):	 0
+NEGATIVE (N):	 0
+
+*** Stack *** 
+*** END Stack *** 
+
+
+WRITE R1 
+
+*** REGISTER FILE STATUS ***
+R0 =[0x00000000]	R1 =[0x0000000b]	R2 =[0x00000016]	R3 =[0x0000000b]	
+R4 =[0x00000000]	R5 =[0x00000000]	R6 =[0x00000000]	R7 =[0x00000000]	
+R8 =[0x00000000]	R9 =[0x00000000]	R10=[0x00000000]	R11=[0x00000000]	
+R12=[0x00000000]	R13=[0x00000000]	R14=[0x00000000]	R15=[0x00000000]	
+R16=[0x00000000]	R17=[0x00000000]	R18=[0x00000000]	R19=[0x00000000]	
+R20=[0x00000000]	R21=[0x00000000]	R22=[0x00000000]	R23=[0x00000000]	
+R24=[0x00000000]	R25=[0x00000000]	R26=[0x00000000]	R27=[0x00000000]	
+R28=[0x00000000]	R29=[0x00000000]	R30=[0x00000000]	R31=[0x00000000]	
+PSW=[0x00000000]
+CARRY (C):	 0
+OVERFLOW (V):	 0
+ZERO (Z):	 0
+NEGATIVE (N):	 0
+
+*** Stack *** 
+*** END Stack *** 
+
+
+STORE R1, $11 
+
+*** REGISTER FILE STATUS ***
+R0 =[0x00000000]	R1 =[0x0000000b]	R2 =[0x00000016]	R3 =[0x0000000b]	
+R4 =[0x00000000]	R5 =[0x00000000]	R6 =[0x00000000]	R7 =[0x00000000]	
+R8 =[0x00000000]	R9 =[0x00000000]	R10=[0x00000000]	R11=[0x00000000]	
+R12=[0x00000000]	R13=[0x00000000]	R14=[0x00000000]	R15=[0x00000000]	
+R16=[0x00000000]	R17=[0x00000000]	R18=[0x00000000]	R19=[0x00000000]	
+R20=[0x00000000]	R21=[0x00000000]	R22=[0x00000000]	R23=[0x00000000]	
+R24=[0x00000000]	R25=[0x00000000]	R26=[0x00000000]	R27=[0x00000000]	
+R28=[0x00000000]	R29=[0x00000000]	R30=[0x00000000]	R31=[0x00000000]	
+PSW=[0x00000000]
+CARRY (C):	 0
+OVERFLOW (V):	 0
+ZERO (Z):	 0
+NEGATIVE (N):	 0
+
+*** Stack *** 
+*** END Stack *** 
+
+
+HALT 
+
+*** REGISTER FILE STATUS ***
+R0 =[0x00000000]	R1 =[0x0000000b]	R2 =[0x00000016]	R3 =[0x0000000b]	
+R4 =[0x00000000]	R5 =[0x00000000]	R6 =[0x00000000]	R7 =[0x00000000]	
+R8 =[0x00000000]	R9 =[0x00000000]	R10=[0x00000000]	R11=[0x00000000]	
+R12=[0x00000000]	R13=[0x00000000]	R14=[0x00000000]	R15=[0x00000000]	
+R16=[0x00000000]	R17=[0x00000000]	R18=[0x00000000]	R19=[0x00000000]	
+R20=[0x00000000]	R21=[0x00000000]	R22=[0x00000000]	R23=[0x00000000]	
+R24=[0x00000000]	R25=[0x00000000]	R26=[0x00000000]	R27=[0x00000000]	
+R28=[0x00000000]	R29=[0x00000000]	R30=[0x00000000]	R31=[0x00000000]	
+PSW=[0x00000000]
+CARRY (C):	 0
+OVERFLOW (V):	 0
+ZERO (Z):	 0
+NEGATIVE (N):	 0
+
+*** Stack *** 
+[0x00000000]
+*** END Stack ***