diff --git a/Makefile b/Makefile
index 7ad3754..7d549f7 100644
--- a/Makefile
+++ b/Makefile
@@ -29,6 +29,7 @@ COMMON = \
 	 odbg.cc \
 	 sync.cc \
 	 control.cc \
+	 ops.cc \
 	 opast.cc \
 	 opparser.cc \
 	 opcomp.cc \
diff --git a/control.hh b/control.hh
index 396200c..e41f008 100644
--- a/control.hh
+++ b/control.hh
@@ -36,6 +36,10 @@ enum E_OpType
 	OP_FP_INV ,
 };
 
+M_LSHIFT_OP( T_StringBuilder , E_OpType );
+uint32_t ArgumentsFor( E_OpType op ) noexcept;
+
+
 struct T_Op
 {
 	E_OpType op;
@@ -50,6 +54,8 @@ struct T_Op
 			arg0( arg0 ) , arg1( arg1 )
 	{ }
 };
+M_LSHIFT_OP( T_StringBuilder , T_Op const& );
+
 
 union T_OpValue
 {
diff --git a/opcomp.cc b/opcomp.cc
index 4405798..9362d3d 100644
--- a/opcomp.cc
+++ b/opcomp.cc
@@ -47,9 +47,15 @@ struct T_CompilerImpl_
 
 	void addInstruction(
 			E_OpType op ,
-			T_SRDLocation const& location ,
-			uint32_t arg0 = 0 ,
-			uint32_t arg1 = 0 ) noexcept;
+			T_SRDLocation const& location ) noexcept;
+	void addInstruction(
+			E_OpType op ,
+			uint32_t arg0 ,
+			T_SRDLocation const& location ) noexcept;
+	void addInstruction(
+			E_OpType op ,
+			uint32_t arg0 , uint32_t arg1 ,
+			T_SRDLocation const& location ) noexcept;
 };
 
 
@@ -91,7 +97,18 @@ P_OpProgram T_CompilerImpl_::compile(
 				return compileNode( cfi , node , exit );
 			} );
 #ifdef INVASIVE_TRACES
-		printf( "\t%d instructions generated\n" , output->ops.sizeOf( cfi ) );
+		T_StringBuilder dump , temp;
+		for ( auto i = 0u ; i < output->ops.sizeOf( cfi ) ; i ++ ) {
+			temp << "(" << output->ops.get( cfi , i ) << ")";
+			while ( temp.length( ) < 30 ) {
+				temp << ' ';
+			}
+			dump << "\t\t" << temp << "{ " << output->ops.get( cfi , i ).location << " }\n";
+			temp.clear( );
+		}
+		dump << '\t' << output->ops.sizeOf( cfi ) << " instructions\n"
+			<< '\0';
+		printf( "%s" , dump.data( ) );
 		nInstr += output->ops.sizeOf( cfi );
 #endif
 	}
@@ -288,7 +305,7 @@ bool T_CompilerImpl_::compileNode(
 			auto& fcallee( (T_FuncNode&) callee );
 			const auto args( fcallee.arguments( ) );
 			assert( sdMain > args );
-			addInstruction( OP_CALL , node.location( ) , fi );
+			addInstruction( OP_CALL , fi , node.location( ) );
 			sdMain -= args;
 		}
 		break;
@@ -300,14 +317,14 @@ bool T_CompilerImpl_::compileNode(
 					(T_IdentifierExprNode&)  n.expression( ) ) };
 			if ( !main ) {
 				addInstruction( OP_PUSH , node.location( ) );
-				addInstruction( OP_FP_SSTORE , node.location( ) , 0 );
+				addInstruction( OP_FP_SSTORE , 0 , node.location( ) );
 				sdMain ++;
 				sdFPU --;
 			}
 			return false;
 		} else if ( exit && !n.isIdentifier( ) ) {
 			addInstruction( OP_PUSH , node.location( ) );
-			addInstruction( OP_FP_SSTORE , node.location( ) , 0 );
+			addInstruction( OP_FP_SSTORE , 0 , node.location( ) );
 			sdMain ++;
 			sdFPU --;
 		}
@@ -321,11 +338,12 @@ bool T_CompilerImpl_::compileNode(
 			auto& func{ input->root.function( funcIndex ) };
 			if ( func.hasLocal( id ) ) {
 				const auto pos( func.getLocalIndex( id ) + 1 );
-				addInstruction( OP_FP_SSTORE , node.location( ) ,
-						sdMain - pos - 1 );
+				addInstruction( OP_FP_SSTORE , sdMain - pos - 1 ,
+						node.location( ) );
 			} else {
-				addInstruction( OP_FP_STORE , node.location( ) ,
-						*locations.get( ((T_SetInstrNode&)node).id( ) ) );
+				addInstruction( OP_FP_STORE ,
+						*locations.get( ((T_SetInstrNode&)node).id( ) ) ,
+						node.location( ) );
 			}
 			sdFPU --;
 		}
@@ -334,7 +352,7 @@ bool T_CompilerImpl_::compileNode(
 	    case A_Node::OP_COND:
 		if ( exit ) {
 			assert( sdMain > 0 );
-			addInstruction( OP_POP , node.location( ) , 0 );
+			addInstruction( OP_POP , 0 , node.location( ) );
 			sdMain --;
 		}
 		break;
@@ -342,7 +360,7 @@ bool T_CompilerImpl_::compileNode(
 	    case A_Node::TN_CONDITION:
 		if ( exit ) {
 			addInstruction( OP_PUSH , node.location( ) );
-			addInstruction( OP_FP_SSTORE_INT , node.location( ) , 0 );
+			addInstruction( OP_FP_SSTORE_INT , 0 , node.location( ) );
 			sdFPU --;
 			sdMain ++;
 		}
@@ -360,8 +378,8 @@ bool T_CompilerImpl_::compileNode(
 		} else {
 			auto& c( (T_CondInstrNode::T_ValuedCase&) node );
 			condJumps.add( output->ops.sizeOf( funcIndex ) );
-			addInstruction( OP_COND_JUMP , node.location( ) ,
-					c.value( ) , 0 );
+			addInstruction( OP_COND_JUMP , 0 , c.value( ) ,
+					node.location( ) );
 		}
 		break;
 
@@ -371,7 +389,7 @@ bool T_CompilerImpl_::compileNode(
 		if ( exit ) {
 			const uint32_t op( dynamic_cast< T_BinaryOperatorNode& >( node ).op( )
 					- T_BinaryOperatorNode::CMP_EQ );
-			addInstruction( OP_FP_CMP , node.location( ) , op );
+			addInstruction( OP_FP_CMP , op , node.location( ) );
 		}
 		break;
 
@@ -408,8 +426,9 @@ bool T_CompilerImpl_::compileNode(
 		if ( !exit ) {
 			T_OpValue value;
 			value.f = dynamic_cast< T_ConstantExprNode& >( node ).floatValue( );
-			addInstruction( OP_FP_LOAD , node.location( ) ,
-					constants.indexOf( value.u ) + 3 );
+			addInstruction( OP_FP_LOAD ,
+					constants.indexOf( value.u ) + 3 ,
+					node.location( ) );
 			sdFPU ++;
 		}
 		break;
@@ -434,15 +453,15 @@ void T_CompilerImpl_::processFunction(
 	if ( exit ) {
 		assert( sdMain == args + lvars + 1 );
 		if ( lvars ) {
-			addInstruction( OP_POP , location , lvars - 1 );
+			addInstruction( OP_POP , lvars - 1 , location );
 			sdMain -= lvars;
 		}
 		sdMain -= 1 + args;
-		addInstruction( OP_RET , location , args );
+		addInstruction( OP_RET , args , location );
 		assert( sdMain == 0 );
 	} else {
 		if ( lvars ) {
-			addInstruction( OP_RES_STACK , location , lvars - 1 );
+			addInstruction( OP_RES_STACK , lvars - 1 , location );
 			sdMain += lvars;
 		}
 		sdMain += 1 + args;
@@ -472,12 +491,12 @@ bool T_CompilerImpl_::processIdentifier(
 
 		const auto p( sdMain - ( stackPos + 1 ) );
 		if ( dt == E_DataType::VARIABLE ) {
-			addInstruction( OP_FP_SLOAD , node.location( ) , p );
+			addInstruction( OP_FP_SLOAD , p , node.location( ) );
 			sdFPU ++;
 			return false;
 		}
 
-		addInstruction( OP_SLOAD , node.location( ) , p );
+		addInstruction( OP_SLOAD , p , node.location( ) );
 		addInstruction( OP_PUSH , node.location( ) );
 		sdMain ++;
 		return true;
@@ -488,14 +507,14 @@ bool T_CompilerImpl_::processIdentifier(
 	assert( dt != E_DataType::UNKNOWN );
 	assert( locations.contains( node.id( ) ) );
 	if ( dt == E_DataType::VARIABLE || dt == E_DataType::BUILTIN ) {
-		addInstruction( OP_FP_LOAD , node.location( ) ,
-				*locations.get( node.id( ) ) );
+		addInstruction( OP_FP_LOAD , *locations.get( node.id( ) ) ,
+				node.location( ) );
 		sdFPU ++;
 		return false;
 	}
 
-	addInstruction( OP_LOAD , node.location( ) ,
-			*locations.get( node.id( ) ) );
+	addInstruction( OP_LOAD , *locations.get( node.id( ) ) ,
+			node.location( ) );
 	addInstruction( OP_PUSH , node.location( ) );
 	sdMain ++;
 	return true;
@@ -504,16 +523,28 @@ bool T_CompilerImpl_::processIdentifier(
 
 void T_CompilerImpl_::addInstruction(
 		const E_OpType op ,
-		T_SRDLocation const& location ,
-		const uint32_t arg0 ,
-		const uint32_t arg1 ) noexcept
+		T_SRDLocation const& location ) noexcept
 {
-#ifdef INVASIVE_TRACES
-	T_StringBuilder tracer;
-	tracer << "\t+I( " << int( op ) << " ; " << arg0 << " ; "
-		<< arg1 << " ) @ " << location << '\n' << '\0';
-	printf( "%s" , tracer.data( ) );
-#endif
+	assert( ArgumentsFor( op ) == 0 );
+	output->ops.addNew( op , location );
+}
+
+void T_CompilerImpl_::addInstruction(
+		const E_OpType op ,
+		const uint32_t arg0 ,
+		T_SRDLocation const& location ) noexcept
+{
+	assert( ArgumentsFor( op ) == 1 );
+	output->ops.addNew( op , location , arg0 );
+}
+
+void T_CompilerImpl_::addInstruction(
+		const E_OpType op ,
+		const uint32_t arg0 ,
+		const uint32_t arg1 ,
+		T_SRDLocation const& location ) noexcept
+{
+	assert( ArgumentsFor( op ) == 2 );
 	output->ops.addNew( op , location , arg0 , arg1 );
 }
 
diff --git a/ops.cc b/ops.cc
new file mode 100644
index 0000000..738bf5e
--- /dev/null
+++ b/ops.cc
@@ -0,0 +1,93 @@
+#include "externals.hh"
+#include "control.hh"
+#include "globals.hh"
+#include "sync.hh"
+
+using namespace ops;
+using namespace ebcl;
+
+
+/*= OPCODE INFORMATIONS ========================================================*/
+
+namespace {
+
+struct T_OpInfo
+{
+	char const* name;
+	int nArgs;
+
+	T_OpInfo( char const* name ,
+			int nArgs = 0 )
+		: name( name ) , nArgs( nArgs )
+	{ }
+};
+
+static T_KeyValueTable< E_OpType , T_OpInfo > OpInfoTable_{ ([]() {
+	T_KeyValueTable< E_OpType , T_OpInfo > infos;
+
+	infos.add( E_OpType::OP_END , T_OpInfo{ "end" } );
+	//
+	infos.add( E_OpType::OP_CALL , T_OpInfo{ "call" , 1 } );
+	infos.add( E_OpType::OP_RET , T_OpInfo{ "ret" , 1 } );
+	infos.add( E_OpType::OP_COND_JUMP , T_OpInfo{ "cond-jump" , 2 } );
+	//
+	infos.add( E_OpType::OP_RES_STACK , T_OpInfo{ "res-stack" , 1 } );
+	infos.add( E_OpType::OP_PUSH , T_OpInfo{ "push" } );
+	infos.add( E_OpType::OP_POP , T_OpInfo{ "pop" , 1 } );
+	//
+	infos.add( E_OpType::OP_LOAD , T_OpInfo{ "load" , 1 } );
+	infos.add( E_OpType::OP_SLOAD , T_OpInfo{ "load-stack" , 1 } );
+	//
+	infos.add( E_OpType::OP_FP_LOAD , T_OpInfo{ "fp-load" , 1 } );
+	infos.add( E_OpType::OP_FP_SLOAD , T_OpInfo{ "fp-load-stack" , 1 } );
+	infos.add( E_OpType::OP_FP_STORE , T_OpInfo{ "fp-store" , 1 } );
+	infos.add( E_OpType::OP_FP_SSTORE , T_OpInfo{ "fp-store-stack" , 1 } );
+	infos.add( E_OpType::OP_FP_SSTORE_INT , T_OpInfo{ "fp-store-stack-int" , 1 } );
+	//
+	infos.add( E_OpType::OP_FP_CMP , T_OpInfo{ "fp-cmp" , 1 } );
+	infos.add( E_OpType::OP_FP_ADD , T_OpInfo{ "fp-add" } );
+	infos.add( E_OpType::OP_FP_SUB , T_OpInfo{ "fp-sub" } );
+	infos.add( E_OpType::OP_FP_MUL , T_OpInfo{ "fp-mul" } );
+	infos.add( E_OpType::OP_FP_DIV , T_OpInfo{ "fp-div" } );
+	infos.add( E_OpType::OP_FP_MUL , T_OpInfo{ "fp-neg" } );
+	infos.add( E_OpType::OP_FP_DIV , T_OpInfo{ "fp-inv" } );
+
+	return infos;
+})( ) };
+
+} // namespace
+
+uint32_t ops::ArgumentsFor(
+		const E_OpType op ) noexcept
+{
+	assert( OpInfoTable_.contains( op ) );
+	return OpInfoTable_.get( op )->nArgs;
+}
+
+
+/*= STRING FORMATTING ==========================================================*/
+
+T_StringBuilder& ops::operator<<(
+		T_StringBuilder& sb ,
+		const E_OpType et )
+{
+	assert( OpInfoTable_.contains( et ) );
+	sb << OpInfoTable_.get( et )->name;
+	return sb;
+}
+
+T_StringBuilder& ops::operator<<(
+		T_StringBuilder& sb ,
+		T_Op const& op )
+{
+	sb << op.op;
+
+	const auto args{ OpInfoTable_.get( op.op )->nArgs };
+	if ( args ) {
+		sb << ' ' << op.arg0;
+		if ( args == 2 ) {
+			sb << ' ' << op.arg1;
+		}
+	}
+	return sb;
+}