#!/usr/bin/perl -w #Compiler for CAMSI's R3K assembler. #Copyright (C) 2005 Cedric VINCENT #This program is free software; you can redistribute it and/or #modify it under the terms of the GNU General Public License #as published by the Free Software Foundation; either version 2 #of the License, or (at your option) any later version. #This program is distributed in the hope that it will be useful, #but WITHOUT ANY WARRANTY; without even the implied warranty of #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #GNU General Public License for more details. #You should have received a copy of the GNU General Public License #along with this program; if not, write to the Free Software #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. use strict; use Getopt::Std; use locale; main(); my %registres; my @free_reg; my $num_allocated_register; my $num_while; my $num_if; my $num_for; my $verbose; my $debug; my $strip; my @context; sub get_register { my ($variable, $declaration) = @_; my $register = 0; my $i = 0; if( defined( $registres{"$variable"} )) { $register = $registres{"$variable"}; } elsif( 0 == $declaration ) { printf(STDERR "use of undeclared variable '$variable' "); return -1; } elsif( $num_allocated_register <= 31 ) { for( $i = 0; $i <= 31 ; $i++) { if( 0 == $free_reg[$i] ) { $register = $i + 1; $free_reg[$i] = 1; last; } } $registres{"$variable"} = $register; $num_allocated_register = $num_allocated_register + 1; if( 1 == $verbose ) { printf("register R$register dedicated to variable '$variable'\n"); } } else { printf(STDERR "no more free register (use 'free' instruction to desallocated unused varaiables) "); return -1; } return $register; } sub free_register { my ($variable) = @_; my $register = 0; if( defined( $registres{"$variable"} )) { $register = $registres{"$variable"}; delete( $registres{"$variable"} ); $free_reg[$register - 1] = 0; if( 1 == $verbose ) { printf("register R$register freed from variable '$variable'\n"); } } else { printf(STDERR "'$variable' is not a valid register "); return -1; } return 0; } sub handle_copy { my ($result, $right_operand) = @_; my $reg_result = 0; my $reg_right_operand = 0; $reg_result = get_register($result, 1); if(-1 == $reg_result) { return -1; } if( $right_operand =~ m/^-?\d+$/ ) { printf(DEST_FILE "addi R$reg_result,R0,$right_operand\n"); } else { $reg_right_operand = get_register($right_operand, 0); if(-1 == $reg_right_operand) { return -1; } printf(DEST_FILE "add R$reg_result,R0,R$reg_right_operand\n"); } return 0; } sub handle_nor { my ($result, $left_operand, $right_operand) = @_; my $reg_result = 0; my $reg_left_operand = 0; my $reg_right_operand = 0; $reg_result = get_register($result, 0); if(-1 == $reg_result) { return -1; } $reg_left_operand = get_register($left_operand, 0); if(-1 == $reg_left_operand) { return -1; } $reg_right_operand = get_register($right_operand, 0); if(-1 == $reg_right_operand) { return -1; } printf(DEST_FILE "nor R$reg_result,R$reg_left_operand,R$reg_right_operand\n"); return 0; } sub handle_rimm { my ($result, $left_operand, $right_operand, $op) = @_; my $reg_result = 0; my $reg_left_operand = 0; my $reg_right_operand = 0; $reg_result = get_register($result, 0); if(-1 == $reg_result) { return -1; } if( $left_operand =~ m/^-?\d+$/ ) { if( $right_operand =~ m/^-?\d+$/ ) { printf(STDERR "syntax error "); return -1; } else { $reg_right_operand = get_register($right_operand, 0); if(-1 == $reg_right_operand) { return -1; } if("sub" eq $op) { #subi n'existe pas... printf(DEST_FILE "addi R$reg_result,R$reg_right_operand,-$left_operand\n"); } else { printf(DEST_FILE $op."i R$reg_result,R$reg_right_operand,$left_operand\n"); } if("sub" eq $op) { #inverse le r�ulat en cas de besoin printf(DEST_FILE "sub R$reg_result,R0,R$reg_result\n"); } if("slt" eq $op) { #inverse le r�ulat en cas de besoin printf(DEST_FILE "xori R$reg_result,R$reg_result,1\n"); } return 0; } } if( $right_operand =~ m/^-?\d+$/ ) { if( $left_operand =~ m/^-?\d+$/ ) { printf(STDERR "syntax error "); return -1; } else { $reg_left_operand = get_register($left_operand, 0); if(-1 == $reg_left_operand) { return -1; } if("sub" eq $op) { printf(DEST_FILE "addi R$reg_result,R$reg_left_operand,-$right_operand\n"); } else { printf(DEST_FILE $op."i R$reg_result,R$reg_left_operand,$right_operand\n"); } return 0; } } $reg_left_operand = get_register($left_operand, 0); if(-1 == $reg_left_operand) { return -1; } $reg_right_operand = get_register($right_operand, 0); if(-1 == $reg_right_operand) { return -1; } printf(DEST_FILE "$op R$reg_result,R$reg_left_operand,R$reg_right_operand\n"); return 0; } sub handle_shift { my ($result, $left_operand, $right_operand, $op) = @_; my $reg_result = 0; my $reg_left_operand = 0; my $reg_right_operand = 0; $reg_result = get_register($result, 0); if(-1 == $reg_result) { return -1; } if( $left_operand =~ m/^-?\d+$/ ) { if( $right_operand =~ m/^-?\d+$/ ) { printf(STDERR "syntax error "); return -1; } else { $reg_right_operand = get_register($right_operand, 0); if(-1 == $reg_right_operand) { return -1; } printf(DEST_FILE "$op R$reg_result,R$reg_right_operand,$left_operand\n"); return 0; } } if( $right_operand =~ m/^-?\d+$/ ) { if( $left_operand =~ m/^-?\d+$/ ) { printf(STDERR "syntax error "); return -1; } else { $reg_left_operand = get_register($left_operand, 0); if(-1 == $reg_left_operand) { return -1; } printf(DEST_FILE "$op R$reg_result,R$reg_left_operand,$right_operand\n"); return 0; } } printf(STDERR "syntax error "); return -1; } sub handle_operation { my ($operator, $result, $left_operand, $right_operand) = @_; my $ret_code = 0; if( $result =~ m/^-?\d+$/ ) { printf(STDERR "invalid result operand "); return -1; } if( $operator eq "+" ) { $ret_code = handle_rimm($result, $left_operand, $right_operand, "add"); if(-1 == $ret_code) { return -1; } } elsif( $operator eq "-" ) { $ret_code = handle_rimm($result, $left_operand, $right_operand, "sub"); if(-1 == $ret_code) { return -1; } } elsif( $operator eq "&" ) { $ret_code = handle_rimm($result, $left_operand, $right_operand, "and"); if(-1 == $ret_code) { return -1; } } elsif( $operator eq "|" ) { $ret_code = handle_rimm($result, $left_operand, $right_operand, "or"); if(-1 == $ret_code) { return -1; } } elsif( $operator eq "<<" ) { $ret_code = handle_shift($result, $left_operand, $right_operand, "lsl"); if(-1 == $ret_code) { return -1; } } elsif( $operator eq ">>" ) { $ret_code = handle_shift($result, $left_operand, $right_operand, "lsr"); if(-1 == $ret_code) { return -1; } } elsif( $operator eq "<|" ) { $ret_code = handle_rimm($result, $left_operand, $right_operand, "slt"); if(-1 == $ret_code) { return -1; } } elsif( $operator eq "=" ) { $ret_code = handle_copy($result, $right_operand); if(-1 == $ret_code) { return -1; } } elsif( $operator =~ m/nor/i ) { $ret_code = handle_nor($result, $left_operand, $right_operand); if(-1 == $ret_code) { return -1; } } elsif( $operator =~ m/xor/i ) { $ret_code = handle_rimm($result, $left_operand, $right_operand, "xor"); if(-1 == $ret_code) { return -1; } } else { printf(STDERR "unknown operator '$operator' "); return -1; } return 0; } sub handle_mem { my ($result, $left_operand, $right_operand, $op) = @_; my $reg_result = 0; my $reg_left_operand = 0; my $reg_right_operand = 0; $reg_result = get_register($result, 0); if(-1 == $reg_result) { return -1; } if( $left_operand =~ m/^\d+$/ ) { if( $right_operand =~ m/^\d+$/ ) { printf(STDERR "syntax error "); return -1; } else { $reg_right_operand = get_register($right_operand, 0); if(-1 == $reg_right_operand) { return -1; } printf(DEST_FILE "$op R$reg_result,$left_operand(R$reg_right_operand)\n"); return 0; } } if( $right_operand =~ m/^\d+$/ ) { if( $left_operand =~ m/\d+$/ ) { printf(STDERR "syntax error "); return -1; } else { $reg_left_operand = get_register($left_operand, 0); if(-1 == $reg_left_operand) { return -1; } printf(DEST_FILE "$op R$reg_result,$right_operand(R$reg_left_operand)\n"); return 0; } } printf(STDERR "syntax error "); return -1; } sub handle_eq { my ($left_operand, $right_operand, $label, $comparator) = @_; my $reg_left_operand = 0; my $reg_right_operand = 0; my $ret_code = 0; if( $left_operand =~ m/^-?\d+$/ ) { if( $right_operand =~ m/^-?\d+$/ ) { printf(STDERR "syntax error "); return -1; } else { $reg_right_operand = get_register($right_operand, 0); if(-1 == $reg_right_operand) { return -1; } $reg_left_operand = get_register("00temp", 1); if(-1 == $reg_left_operand) { return -1; } $ret_code = handle_copy("00temp", $left_operand); if(-1 == $ret_code) { return -1; } printf(DEST_FILE "$comparator R$reg_right_operand,R$reg_left_operand,:$label\n"); $ret_code = free_register("00temp"); if(-1 == $ret_code) { return -1; } return 0; } } if( $right_operand =~ m/^-?\d+$/ ) { if( $left_operand =~ m/^-?\d+$/ ) { printf(STDERR "syntax error "); return -1; } else { $reg_left_operand = get_register($left_operand, 0); if(-1 == $reg_left_operand) { return -1; } $reg_right_operand = get_register("00temp", 1); if(-1 == $reg_right_operand) { return -1; } $ret_code = handle_copy("00temp", $right_operand); if(-1 == $ret_code) { return -1; } printf(DEST_FILE "$comparator R$reg_right_operand,R$reg_left_operand,:$label\n"); $ret_code = free_register("00temp"); if(-1 == $ret_code) { return -1; } return 0; } } $reg_left_operand = get_register($left_operand, 0); if(-1 == $reg_left_operand) { return -1; } $reg_right_operand = get_register($right_operand, 0); if(-1 == $reg_right_operand) { return -1; } printf(DEST_FILE "$comparator R$reg_right_operand,R$reg_left_operand,:$label\n"); return 0; } sub handle_ineq { my ($left_operand, $right_operand, $label, $comparator) = @_; my $ret_code = 0; my $register = 0; my $reg_left_operand = 0; my $reg_right_operand = 0; $register = get_register("00temp", 1); if(-1 == $register) { return -1; } $ret_code = handle_rimm("00temp", $left_operand, $right_operand, "sub"); if(-1 == $ret_code) { return -1; } printf(DEST_FILE "$comparator R$register,:$label\n"); $ret_code = free_register("00temp"); if(-1 == $ret_code) { return -1; } return 0; } sub handle_comparator { my ($operator, $left_operand, $right_operand, $label) = @_; my $ret_code = 0; if( $operator eq "==" ) { $ret_code = handle_eq($left_operand, $right_operand, $label, "bne"); } elsif( $operator eq "!=" ) { $ret_code = handle_eq($left_operand, $right_operand, $label, "beq"); } elsif( $operator eq "<=" ) { $ret_code = handle_ineq($left_operand, $right_operand, $label, "bgtz"); } elsif( $operator eq ">=" ) { $ret_code = handle_ineq($left_operand, $right_operand, $label, "bltz"); } elsif( $operator eq ">" ) { $ret_code = handle_ineq($left_operand, $right_operand, $label, "blez"); } elsif( $operator eq "<" ) { $ret_code = handle_ineq($left_operand, $right_operand, $label, "bgez"); } else { printf(STDERR "unknown comparator '$operator' "); return -1; } return $ret_code; } sub handle_if { my ($operator, $left_operand, $right_operand) = @_; my $label = 0; my $ret_code = 0; $label = "end_then_$num_if"; push(@context, $label); $num_if = $num_if + 1; if( 1 == $verbose ) { printf("$label pushed\n"); } $ret_code = handle_comparator($operator, $left_operand, $right_operand, $label); return $ret_code; } sub handle_else { my $label = 0; my $label_end_else = 0; my $cross = 0; if( scalar(@context) == 0 ) { printf(STDERR "'else' without 'if' "); return -1; } $label = pop(@context); if( 1 == $verbose ) { printf("$label poped\n"); } if( $label !~ m/end_then_(\d)+/ ) { $label =~ m/end_(\w+)_\d+/; if( "while" eq $1 ) { $cross = "while"; } elsif( "else" eq $1 ) { $cross = "if"; } else { $cross = "for"; } printf(STDERR "context crossed ('else' before 'end$cross') "); return -1; } $label_end_else = "end_else_$1"; printf(DEST_FILE "j :$label_end_else\n"); push(@context, $label_end_else); handle_label($label); if( 1 == $verbose ) { printf("$label_end_else pushed\n"); } return 0; } sub handle_endif { my $label = 0; my $cross = 0; if( scalar(@context) == 0 ) { printf(STDERR "'endif' without 'if' "); return -1; } $label = pop(@context); if( 1 == $verbose ) { printf("$label poped\n"); } if( $label !~ m/end_then_\d+/ && $label !~ m/end_else_\d+/) { $label =~ m/end_(\w+)_\d+/; if( "while" eq $1 ) { $cross = "while"; } else { $cross = "for"; } printf(STDERR "context crossed ('endif' before 'end$cross') "); return -1; } handle_label($label); return 0; } sub handle_while { my ($operator, $left_operand, $right_operand) = @_; my $label = 0; my $label_end = 0; my $ret_code = 0; $label_end = "end_while_$num_while"; $label = "while_$num_while"; push(@context, $label_end); $num_while = $num_while + 1; if( 1 == $verbose ) { printf("$label_end pushed\n"); } handle_label($label); $ret_code = handle_comparator($operator, $left_operand, $right_operand, $label_end); return $ret_code; } sub handle_endwhile { my $label_end = 0; my $label = 0; my $cross = 0; if( scalar(@context) == 0 ) { printf(STDERR "'endwhile' without 'while' "); return -1; } $label_end = pop(@context); if( 1 == $verbose ) { printf("$label_end poped\n"); } if( $label_end !~ m/end_(while_\d+)/ ) { $label_end =~ m/end_(\w+)_\d+/; if( "then" eq $1 || "else" eq $1 ) { $cross = "if"; } else { $cross = "for"; } printf(STDERR "context crossed ('endwhile' before 'end$cross') "); return -1; } $label = $1; printf(DEST_FILE "j :$label\n"); handle_label($label_end); return 0; } sub handle_for { my ($variable, $from, $to, $step) = @_; my $label = 0; my $label_end = 0; my $ret_code = 0; $label_end = "end_for_$num_for"; $label = "for_$num_for"; push(@context, $label_end); $num_for = $num_for + 1; if( 1 == $verbose ) { printf("$label_end pushed\n"); } $ret_code = handle_copy($variable, $from); if(-1 == $ret_code) { return -1; } handle_label($label); $ret_code = handle_comparator("<=", $variable, $to, $label_end); if(-1 == $ret_code) { return -1; } $ret_code = handle_rimm($variable, $variable, $step, "add"); if(-1 == $ret_code) { return -1; } return $ret_code; } sub handle_endfor { my $label_end = 0; my $label = 0; my $cross = 0; if( scalar(@context) == 0 ) { printf(STDERR "'endfor' without 'for' "); return -1; } $label_end = pop(@context); if( 1 == $verbose ) { printf("$label_end poped\n"); } if( $label_end !~ m/end_(for_\d+)/ ) { $label_end =~ m/end_(\w+)_\d+/; if( "then" eq $1 || "else" eq $1 ) { $cross = "if"; } else { $cross = "for"; } printf(STDERR "context crossed ('endfor' before 'end$cross') "); return -1; } $label = $1; printf(DEST_FILE "j :$label\n"); handle_label($label_end); return 0; } sub handle_goto { my ($label) = @_; my $register = 0; if( $label =~ m/\$(\w+)/ ) { $label = $1; if( defined( $registres{"$label"} )) { $register = $registres{"$label"}; printf(DEST_FILE "jr R$register\n"); } else { return -1; } } else { printf(DEST_FILE "j :$label\n"); } return 0; } sub handle_label { my ($label) = @_; printf(DEST_FILE ":$label\n"); return 0; } sub handle_break { my $label = 0; my $i = 0; for( $i = @context - 1; $i >= 0 ; $i--) { $label = $context[$i]; if( $label =~ m/end_while_\d+/ || $label =~ m/end_for_\d+/ ) { printf(DEST_FILE "j :$label\n"); return 0; } } printf(STDERR "'break' not inside 'while' or 'for' context "); return -1; } sub handle_continue { my $label = 0; my $i = 0; for( $i = @context - 1; $i >= 0 ; $i--) { $label = $context[$i]; if( $label =~ m/end_(while_\d+)/ || $label =~ m/end_(for_\d+)/ ) { printf(DEST_FILE "j :$1\n"); return 0; } } printf(STDERR "'continue' not inside 'while' or 'for' context "); return -1; } sub parse_line { my ($line) = @_; my $result = 0; my $left_operand = 0; my $operator = 0; my $right_operand = 0; my $label = 0; my $ret_code = -1; if( 1 == $debug and $line !~ m/^\s*\/\//i ) { printf(DEST_FILE "//$line"); } if( $line =~ m/^\s*(\w+)\s*=\s*(-?\w+)\s*([-+&\|<>]+|\s+xor\s+|\s+nor\s+)\s*(-?\w+)\s*$/ ) { $result = $1; $left_operand = $2; $operator = $3; $right_operand = $4; $ret_code = handle_operation($operator, $result, $left_operand, $right_operand); } elsif( $line =~ m/^\s*(\w+)\s*=\s*mem\s*\[\s*(\w+)\s*,\s*(\w+)\s*\]\s*$/i ) { $result = $1; $left_operand = $2; $right_operand = $3; $ret_code = handle_mem($result, $left_operand, $right_operand, "lw"); } elsif( $line =~ m/^\s*mem\s*\[\s*(\w+)\s*,\s*(\w+)\s*\]\s*=\s*(\w+)\s*$/i ) { $result = $3; $left_operand = $1; $right_operand = $2; $ret_code = handle_mem($result, $left_operand, $right_operand, "sw"); } elsif( $line =~ m/^\s*if\s+(-?\w+)\s*([<>=!]+)\s*(-?\w+)\s*then\s*$/i ) { $left_operand = $1; $operator = $2; $right_operand = $3; $ret_code = handle_if($operator, $left_operand, $right_operand); } elsif( $line =~ m/^\s*else\s*$/i ) { $ret_code = handle_else(); } elsif( $line =~ m/^\s*endif\s*$/i ) { $ret_code = handle_endif(); } elsif( $line =~ m/^\s*while\s+(-?\w+)\s*([<>=!]+)\s*(-?\w+)\s*do\s*$/i ) { $left_operand = $1; $operator = $2; $right_operand = $3; $ret_code = handle_while($operator, $left_operand, $right_operand); } elsif( $line =~ m/^\s*endwhile\s*$/i ) { $ret_code = handle_endwhile(); } elsif( $line =~ m/^\s*for\s+(\w+)\s+from\s+(-?\d+)\s+to\s+(-?\d+)\s+step\s+(-?\d+)\s+do\s*$/i ) { $result = $1; $left_operand = $2; $right_operand = $3; $operator = $4; $ret_code = handle_for($result, $left_operand, $right_operand, $operator); } elsif( $line =~ m/^\s*endfor\s*$/i ) { $ret_code = handle_endfor(); } elsif( $line =~ m/^\s*\/\//i ) { #handle_comment(); if( 0 == $strip ) { printf(DEST_FILE "$line"); } $ret_code = 0; } elsif( $line =~ m/^\s*$/i ) { #handle_empty_line(); if( 0 == $strip ) { printf(DEST_FILE "\n"); } $ret_code = 0; } elsif( $line =~ m/^\s*(\w+)\s*(=)\s*(-?\w+)\s*$/i ) { $result = $1; $operator = $2; $right_operand = $3; $left_operand = $3; $ret_code = handle_operation($operator, $result, $left_operand, $right_operand); } elsif( $line =~ m/^\s*goto\s+(\$?\w+)\s*$/i ) { $label = $1; $ret_code = handle_goto($label); } elsif( $line =~ m/^\s*label\s+(\w+)\s*$/i ) { $label = $1; $ret_code = handle_label($label); } elsif( $line =~ m/^\s*free\s+(\w+)\s*$/i) { $result = $1; printf(STDERR "DON'T USE FREE, PLEASE !\n"); $ret_code = free_register($result); } elsif( $line =~ m/^\s*continue\s*$/i) { $result = $1; $ret_code = handle_continue(); } elsif( $line =~ m/^\s*break\s*$/i) { $result = $1; $ret_code = handle_break(); } else { printf(STDERR "syntax error "); } return $ret_code; } sub parse_file { my $check_line = 0; my $num_line = 0; while( ) { $num_line = $num_line + 1; $check_line = parse_line($_); if(-1 == $check_line) { printf(STDERR "at line $num_line :\n>> $_"); return -1; } } return 0; } sub usage { print("usage: $0 [OPTIONS]\n"); print("options are:\n"); print("\t -s SOURCE , source code file\n"); print("\t -d DESTINATION , destination asm file\n"); print("\t -v , verbose screen output\n"); print("\t -g , debug asm output\n"); print("\t -t , stripped asm output\n"); print("\t -h , print this help and store a French tutorial in tutorial.code\n\n"); } sub tuto { open(TUTO_FILE, ">tutorial.code") or die("open(tutorial.code) : $!"); printf(TUTO_FILE "// R3KCompiler // // Resume // // Ce document est un tutoriel pour le compilateur R3KCompiler. Cet outils // permet de generer, a partir d'un code en langage evolue, du code // assembleur compatible avec les outils du projet <> du Master CAMSI. // // Telechargez R3KCompiler ici : R3KCompiler // // Copyright (c) 2004, 2005 // // ---------------------------------------------------------------------- // // Table des matieres // // 1. Variables et syntaxe // // 2. Operations // // 3. Memoire // // 4. Iterations // // 5. Comparaisons et conditions // // 6. Gestion des registres // // 7. Sauts // // 8. Invocation // // 1.Variables et syntaxe // // Comme en C, toutes les variables doivent etre declarees avant leur // utilisation. Cependant la syntaxe de ce langage est telle que toutes les // variables sont du type entier signe 32 bits. Il est donc inutile de // preciser un type... J'entends deja les mauvaises langues dire <>, je leur repondrais : // // o ce projet est libre, donc s'il ne vous convient pas, modifiez le ! // o ce projet est avant tout un <>, pour montrer // que notre processeur <> peut executer des // algorithmes sympathiques, et pas seulement des additions ou autres. // o en 3 jours, je ne pouvais pas faire mieux, surtout que je n'avais // presque jamais programme en Perl... // // Revenons-en a nos moutons, voila comment declarer des variables, avec // une valeur par defaut : // iterator = 1 temp1 = 2 temp2 = 0 temp3 = 5 // // Vous avez du remarquer qu'il n'y avait pas de ; en fin de ligne. En fait // la syntaxe de ce langage n'autorise qu'une seule operation par ligne^[1]. // Pour faire une addition par exemple, on peut ecrire : // temp2 = temp1 + 2 // // Mais on ne peut pas faire : iterator = temp + 4 - 2 // // Pour mettre en commentaire une ligne, il suffit de la faire commencer par // //. // // 2.Operations // // En ce qui concerne les operations que l'on peut faire, nous avons le choix // entre : // // o l'addition : temp1 = temp3 + temp2 // o la soustraction : temp3 = 3 - temp1 // o le et logique : temp2 = temp2 & temp2 // o le ou logique : temp3 = temp1 | 0 // o le decalage a gauche (l'operande de droite doit etre une variable) : temp1 = temp1 << 1 // o le decalage a droite (l'operande de gauche doit etre une variable) : temp1 = 2 >> temp3 // o le positionner si inferieur (ou egale, tout depend du context) : temp1 = 0 <| temp2 // o l'affectation : temp3 = temp1 // o le non ou logique (toutes les operandes doivent etre des variables) : temp2 = temp1 nor temp2 // o le ou exclusif logique : temp1 = temp2 xor temp3 // // Comme vous l'avez lu, il existe certaines contraintes, lies a notre // processeur, en ce qui concerne l'utilisation des operations. Lorsque j'ai // eu le temps, j'ai fais en sorte de passer outre ces limitations, mais il // en reste quelques unes... // // 3.Memoire // // Commencons a jouer avec la memoire. Pour une ecriture en memoire, il // suffit de faire : // mem[10,temp2] = temp1 // // Il faut bien respecter le type des operandes, cette limitation est encore // due a notre architecture, et je n'ai pas eu le temps de contourner le // probleme. En ce qui concerne la lecture en memoire, c'est le meme principe // : // temp3 = mem[21,temp1] // // 4.Iterations // // Nous avons vu les variables, les operations, et la memoire, continuons // avec les boucles ! En ce qui concerne les boucles for, il faut preciser la // variable d'iteration, le debut, la fin et le pas : // for iterator from 0 to 100 step 2 do // something to do endfor // // Une autre maniere de boucler consiste a utiliser le while : // while temp1 >= temp2 do // something to do endwhile // // J'allais oublier quelque chose a propos des boucles ;) ! On peut utiliser // les mot clefs break pour terminer la boucle (for ou while) en plein // milieu, ou continue pour sauter une iteration, comme en C : // for iterator from 0 to 100 step 2 do // something to check break endfor // while temp1 >= temp2 do // something to check continue endwhile // // 5.Comparaisons et conditions // // Toutes les conditions de comparaisons sont possibles : // // o egalite : == // o difference : != // o inferieur : < et l'equivalent large : <= // o superieur : > et l'equivalent large : >= // // Tout cela nous amene au branchement if : // if temp1 != temp3 then // something to do endif // // Nous pouvons aussi utiliser le else : // if temp1 < temp3 then // something to do else // something else to do endif // // 6.Gestion des registres // // Nous voila deja a l'avant dernier chapitre... Si vous avez regarde le // code source de R3KCompiler, vous avez du remarquer l'allocateur de // registre (c'est la premiere fonction). C'est en fait un dedicateur de // registres dans le sens ou lorsqu'une variable est affectee a un registre, // c'est de maniere definitive... Le seul moyen de liberer un registre est // d'utiliser le mot clef free : // free iterator // // Mais il faut etre sur de ce que l'on fait !!! Je n'ai mis cette // fonctionnalite juste pour me simplifier la vie, elle devrait etre // interdite ! En effet, imaginez qu'on libere une variable, avec les sauts, // on ne peut pas predire facilement si c'est le meme registre qui sera // utilise^[2]... // // 7.Sauts // // Enfin, comme tout mauvais langage de programmation, il gere aussi les goto // et les label... // label pas_beau // something to do goto pas_beau // // J'avais commence a reflechir sur les fonctions, donc il est possible de // sauter a une adresse stoquee dans un registre (dedie a la variable temp1 // dans cet exemple) : // goto \$temp1 // // 8.Invocation // // Voila, nous avons fait le tour d'horizon de ce fabuleux langage nomme... // euh... En fait c'est un langage sans nom :) ! // // En ce qui concerne le compilateur, voila une liste des options qu'il gere // : // // o -s specifie le nom du fichier source // o -d specifie le nom du fichier de destination // o -v affiche l'allocation de registre et les contextes // o -g enregistre dans le fichier source le code source en commentaire // o -t n'enregistre pas dans le fichier source les commentaires d'origine // o -h devinez ;) ! // // Amusez-vous a compiler l'aide tutoriel en faisant : // // ./r3kcompiler -h // ./r3kcompiler -s tutorial.code -d tutorial.asm -g -t // // Vous trouverez dans tutorial.asm le code assembleur de ce tutoriel :) // // Il ne reste plus qu'a l'assembler avec votre assembleur favoris (mais ce code risque de ne pas faire grand chose d'utile !). // // Merci de votre lecture (je crois n'avoir rien oublie) ! // // -------------- // // ^[1] pour ceux qui ne sont pas contents, c.f. paragraphe precedent // // ^[2] Voir mon rapport sur les allocateurs de registres.\n"); } sub main { my %opts; my $check_file = -1; my $label = 0; my $i = 0; print("r3kcompiler, Copyright (C) 2005 Cedric VINCENT \n"); print("r3kcompiler (release 060718) comes with ABSOLUTELY NO WARRANTY\n"); print("This is free software, and you are welcome to copy, study, modify, and redistribute it under GPL\n\n"); if( !getopts("s:d:vgth", \%opts) ) { usage(); exit(1); } if( exists($opts{h}) ) { usage(); tuto(); exit(1); } if( !exists($opts{s}) || !exists($opts{d}) ) { usage(); exit(1); } if( exists($opts{v}) ) { $verbose = 1; } else { $verbose = 0; } if( exists($opts{g}) ) { $debug = 1; } else { $debug = 0; } if( exists($opts{t}) ) { $strip = 1; } else { $strip = 0; } open(SOURCE_FILE, "<$opts{s}") or die("open($opts{s}) : $!"); open(DEST_FILE, ">$opts{d}") or die("open($opts{d}) : $!"); $num_allocated_register = 1; $num_while = 0; $num_if = 0; $num_for = 0; for( $i = 0; $i <= 31; $i++) { $free_reg[$i] = 0; } $check_file = parse_file(); if( -1 == $check_file ) { printf(STDERR "failed to compile $opts{s}\n"); return -1; } if( scalar(@context) != 0 ) { $label = pop(@context); $label =~ m/end_(\w+)_\d+/; if( "while" eq $1 ) { $label = "while"; } elsif( "else" eq $1 || "then" eq $1 ) { $label = "if"; } else { $label = "for"; } printf(STDERR "unbalanced context at end of file ('end$label' missing) \n"); printf(STDERR "failed to compile $opts{s}\n"); return -1; } print("Compilation succeeded !\n"); }