#include <iostream> // cin, cout et cerr
#include <sstream>  // istringstream
#include <string>   // Chaînes de caractères de la STL
#include <map>      // Tableaux associatifs de la STL
#include <vector>   // Vecteurs de la STL

using namespace std ;

// Erreur fatale : le message est affiché et le programme se termine avec un code de 
// retour égal à 1.
inline void
fatal(const string & message)
{
	cerr << "Erreur fatale, message : " << message << '.' << endl ;
	exit(1) ;
}
// Type qui représente une instruction.
class Inst {
	size_t code_ ;   // Code de l'instruction.
	size_t taille_ ; // Taille de l'instruction.
	public :
	// Constructeur normal.
	Inst(const size_t & code, const size_t & taille) : code_(code), taille_(taille) {}
	// Constructeur de copie.
	Inst(const Inst & arg) : code_(arg.code()), taille_(arg.taille()) {}
	// Constructeur par défaut.
	Inst() { fatal("Erreur interne, appel du constructeur par défaut de `Inst'") ; }
	size_t code() const { return code_ ; }      // Lecture de l'attribut `code_'.
	size_t taille() const { return taille_ ; }  // Lecture de l'attribut `taille_'.
} ;
// Code des différentes opérations.
const size_t ASE = 0 ;   // Appel du système d'exploitation.
const size_t CRG = 1 ;   // Charger le registre général.
const size_t SRG = 2 ;   // Stocker le registre général.
const size_t MOINS = 3 ; // Soustraire.
const size_t BI = 4 ;    // Branchement inconditionnel.
const size_t BSDZ = 5 ;  // Branchement si différent de zéro.
const size_t CRGP = 6 ;  // Charger le registre général depuis la pile.
const size_t SRGP = 7 ;  // Stocker le registre général vers la pile.
const size_t APPEL = 8 ; // Appeler une fonction.
const size_t RET = 9 ;   // Retourner.
const size_t DEF = 10 ;  // Définir un emplacement de mémoire.
const size_t SYN = 11 ;  // Rendre un symbole synonyme d'un naturel.

int
main()
{
	// Tableau associatif `mnémonique de l'opération' --> `Inst(code, taille)'.
	map<string, Inst> mnemo2inst ;
	// Initialisation de `mnemo2inst'.
	mnemo2inst.insert(make_pair<string, Inst>("ase", Inst(ASE, 2))) ;
	mnemo2inst.insert(make_pair<string, Inst>("crg", Inst(CRG, 3))) ;
	mnemo2inst.insert(make_pair<string, Inst>("srg", Inst(SRG, 3))) ;
	mnemo2inst.insert(make_pair<string, Inst>("-", Inst(MOINS, 3))) ;
	mnemo2inst.insert(make_pair<string, Inst>("bi", Inst(BI, 3))) ;
	mnemo2inst.insert(make_pair<string, Inst>("bsdz", Inst(BSDZ, 3))) ;
	mnemo2inst.insert(make_pair<string, Inst>("crgp", Inst(CRGP, 2))) ;
	mnemo2inst.insert(make_pair<string, Inst>("srgp", Inst(SRGP, 2))) ;
	mnemo2inst.insert(make_pair<string, Inst>("appel", Inst(APPEL, 3))) ;
	mnemo2inst.insert(make_pair<string, Inst>("ret", Inst(RET, 1))) ;
	mnemo2inst.insert(make_pair<string, Inst>("déf", Inst(DEF, 1))) ;
	mnemo2inst.insert(make_pair<string, Inst>("syn", Inst(SYN, 0))) ;

	typedef map<string, string> Map_str_str ; // Pour se simplifier la vie.
	// Tableau associatif : Table des symboles `symbole' --> `valeur du symbole'.
	Map_str_str table_symboles ;

	// Vecteur qui mémorise les deux ou trois items de chaque ligne lue.
	vector< vector<string> > lignes_lues ;

	// Première passe ; validation des instructions et récolement des symboles.
	size_t adresse = 0 ; // Adresse courante dans le programme.
	string ligne ;       // Ligne courante lue depuis `cin'.
	while ( getline(cin, ligne) ) { // `false' si fin du fichier (ou si err. de lecture).
		vector<string> items ; // Vecteur pour stocker les deux ou trois items de la ligne.
		// La ligne lue devient un `istringstream', c'est-à-dire un `fichier en mémoire'.
		istringstream lecture(ligne) ;
		string item ;
		// Lecture de trois champs au maximum dans la ligne, séparés par un `\t'.
		while ( getline(lecture, item, '\t') && (items.size() < 3) ) {
			items.push_back(item) ; }
		// Les lignes vides sont ignorées ; de même les lignes qui débutent par `#'.
		if ( items.empty() || (items[0][0] == '#') ) {
			continue ; }
		if ( items.size() < 2 ) {
			cerr << ligne << endl ;
			fatal("Ligne, comportant moins de deux items, invalide") ; }
		// Les deux ou trois premiers items sont stockés dans `lignes_lues'.
		lignes_lues.push_back(items) ;
		// Le deuxième item `items[1]' est le mnémonique de l'opérateur.
		map<string, Inst>::const_iterator itr = mnemo2inst.find(items[1]) ;
		if ( itr != mnemo2inst.end() ) {
			// L'étiquette est égale à l'adresse courante, sauf pour l'opération `syn' où
			// l'étiquette est égale à l'opérande. `itr->second' désigne l'instance de `Inst'
			// qui a été retrouvée.
			if ( itr->second.code() != SYN ) {
				// On ne renseigne la table des symboles que si l'étiquette n'est pas vide.
				if ( ! items[0].empty() ) {
					// Une adresse est codée sur deux positions.
					string temporaire ;
					temporaire.push_back('0' + adresse/10) ;
					temporaire.push_back('0' + adresse%10) ;
					table_symboles[items[0]] = temporaire ; } }
			else {
				if ( (items.size() != 3) || items[0].empty() ) {
					cerr << ligne << endl ;
					fatal("Ligne invalide : " + items[0] + '\t' + items[1]) ; }
				table_symboles[items[0]] = items[2] ; }
			// L'adresse est incrémentée en raison de la taille de l'instruction.
			adresse += itr->second.taille() ; }
		else {
			cerr << ligne << endl ;
			fatal("Opérateur `" + items[1] + "' non reconnu") ; }
	} // Fin du `while ( getline(cin, ligne) )'.

	// Deuxième passe ; le code exécutable est engendré sur `cout'.
	for ( size_t i = 0 ; i < lignes_lues.size() ; ++ i ) {
		// On renouvelle la recherche (qui doit réussir) du mnémonique de l'opérateur. C'est
		// pour cela que l'on utilise la syntaxe `mnemo2inst[clef]'. Si, à l'exécution, le
		// constructeur par défaut est appelé c'est une erreur interne. C'est pour cela que
		// le constructeur par défaut de `Inst' engendre une erreur fatale quand il est
		// appelé.
		Inst inst = mnemo2inst[lignes_lues[i][1]] ;
		// Ne pas engendrer du code pour la pseudo-instruction `syn'.
		if ( inst.code() == SYN ) {
			continue ; }
		// L'instruction `ret' n'a pas d'opérande.
		if ( inst.code() == RET ) {
			cout << RET << endl ;
			continue ; }
		// Il faut s'assurer qu'un opérande a bien été spécifié.
		if ( lignes_lues[i].size() != 3 ) {
			fatal("Ligne invalide : " + lignes_lues[i][0] + '\t' + lignes_lues[i][1]) ; }
		// L'opération `déf' n'engendre pas de code, seulement une valeur initiale.
		if ( inst.code() == DEF ) {
			cout << lignes_lues[i][2] << endl ;
			continue ; }
		// Les autres opérations comportent un opérande, le rechercher dans la table des
		// symboles.
		Map_str_str::const_iterator itr = table_symboles.find(lignes_lues[i][2]) ;
		if ( itr == table_symboles.end() ) {
			fatal("Symbole `" + lignes_lues[i][2] + "' indéfini") ; }
		cout << inst.code() << ' ' << itr->second << endl ; }

	// Troisième passe ; l'impression de contrôle est engendrée sur `cerr'.
	adresse = 0 ;
	cerr << "Adresse\tCode\tExplication" << endl ;
	for ( size_t i = 0 ; i < lignes_lues.size() ; ++ i ) {
		Inst inst = mnemo2inst[lignes_lues[i][1]] ;
		string a ; // `a' désigne soit l'adresse soit, pour une instruction `ase', le code.
		switch ( inst.code() ) {
			case ASE : a = table_symboles[lignes_lues[i][2]] ;
			cerr << adresse << '\t' << ASE << ' ' << a << '\t' <<
				"Appeler le système d'exploitation." << endl ;
			switch ( a[0] ) {
				case '0' : cerr << "\t\t\t0 est le code `Fin du programme'." << endl ;
				break ;
				case '1' : cerr << "\t\t\t1 est le code `Lecture d'un entier depuis "
					"std::cin'." << endl ;
				break ;
				case '2' : cerr << "\t\t\t2 est le code `Écriture d'un entier vers "
					"std::cout'." << endl ;
				break ;
				default : cerr << "\t\t\t" << a << " est un code inconnu." << endl ;
			}
			break ;

			case CRG : a = table_symboles[lignes_lues[i][2]] ;
			cerr << adresse << '\t' << CRG << ' ' << a << '\t' <<
				"Charger le registre général." << endl ;
			cerr << "\t\t\t" << a << " est l'adresse de " << lignes_lues[i][2] << '.' <<
				endl ;
			break ;

			case SRG : a = table_symboles[lignes_lues[i][2]] ;
			cerr << adresse << '\t' << SRG << ' ' << a << '\t' <<
				"Stocker le contenu du registre général." << endl ;
			cerr << "\t\t\t" << a << " est l'adresse de " << lignes_lues[i][2] << '.' <<
				endl ;
			break ;

			case MOINS : a = table_symboles[lignes_lues[i][2]] ;
			cerr << adresse << '\t' << MOINS << ' ' << a << '\t' << "Soustraire." << endl ;
			cerr << "\t\t\t" << a << " est l'adresse de " << lignes_lues[i][2] << '.' <<
				endl ;
			break ;

			case BI : a = table_symboles[lignes_lues[i][2]] ;
			cerr << adresse << '\t' << BI << ' ' << a << '\t' << "Se brancher "
				"inconditionnellement." << endl ;
			cerr << "\t\t\t" << a << " est l’adresse de l’instruction à exécuter, étiquetée "
				<< lignes_lues[i][2] << '.' << endl ;
			break ;

			case BSDZ : a = table_symboles[lignes_lues[i][2]] ;
			cerr << adresse << '\t' << BSDZ << ' ' << a << '\t' <<
				"Sauter si le registre général n’est pas égal à zéro." << endl ;
			cerr << "\t\t\t" << a << " est l’adresse de l’instruction à exécuter, "
				"étiquetée " << lignes_lues[i][2] << '.' << endl ;
			break ;

			case CRGP : a = table_symboles[lignes_lues[i][2]] ;
			cerr << adresse << '\t' << CRGP << ' ' << a << '\t' <<
				"Charger le registre général depuis la pile." << endl ;
			cerr << "\t\t\t" << a << " est le déplacement qui désigne la variable "
				"locale " << lignes_lues[i][2] << '.' << endl ;
			break ;

			case APPEL : a = table_symboles[lignes_lues[i][2]] ;
			cerr << adresse << '\t' << APPEL << ' ' << a << '\t' <<
				"Appeler une fonction." << endl ;
			cerr << "\t\t\t" << a << " est l'adresse de la première instruction à exécuter, "
				"étiquetée " << lignes_lues[i][2] << '.' << endl ;
			break ;

			case RET : cerr << adresse << '\t' << RET << '\t' << "Retourner." <<
				endl ;
			break ;

			case DEF : cerr << adresse << '\t' << lignes_lues[i][2] << '\t' <<
				"Symbole " << lignes_lues[i][0] << '.' << endl ;
			break ;

			case SYN : break ;

			default : cerr << "Erreur interne, prévenir F. Legendre" << endl ;
		} // Fin du `switch ( inst.code() ) {'
	adresse += inst.taille() ; }

	return 0 ; // Retour au système d'exploitation avec le code `0'.
}            // Fin de `main(...)'
