diff --git a/lt-stdlib/color.lt b/lt-stdlib/color.lt
new file mode 100644
index 0000000..84e9bc4
--- /dev/null
+++ b/lt-stdlib/color.lt
@@ -0,0 +1,47 @@
+export {
+    let morph-rgb-to-hsv = λ{
+        {
+            red:    ℝ_0,1 ~ ℤ_256 ~ machine.UInt64;
+            green:  ℝ_0,1 ~ ℤ_256 ~ machine.UInt64;
+            blue:   ℝ_0,1 ~ ℤ_256 ~ machine.UInt64;
+        } : <Color sRGB>
+          ~ RGB
+          ~ <Vec3 ℝ_0,1 ~ ℤ_256 ~ machine.UInt64>;
+        /*
+        ::> Color
+          ~ HSV
+          ~ {
+                hue: Angle
+                   ~ Degrees
+                   ~ ℝ_0,360
+                   ~ ℤ_360
+                   ~ machine.UInt64 ;
+
+                saturation: ℝ_0,1 ~ ℤ_256 ~ machine.UInt64 ;
+                value:      ℝ_0,1 ~ ℤ_256 ~ machine.UInt64 ;
+            }
+          ~ <Vec3 machine.UInt64>
+        */
+	} ↦ {
+		let channel_max = int-max (int-max red green) blue;
+		let channel_min = int-min (int-min red green) blue;
+
+        /* value */
+		channel_max;
+
+        /* saturation */
+        i/ (i* 255 (i- channel_max channel_min)) channel_max;
+
+        /* hue */
+        i%  (i/ (i* 60
+                    if( int-eq channel_max red )       { i+ (i* 0 255) (i- green blue); }
+                    else {
+                        if( int-eq channel_max green ) { i+ (i* 2 255) (i- blue red); }
+                        else                           { i+ (i* 4 255) (i- red green); };
+                    }
+                )
+                (i- channel_max channel_min)
+            )
+            360;
+	};
+}
diff --git a/lt-stdlib/euclidean.lt b/lt-stdlib/euclidean.lt
new file mode 100644
index 0000000..21962cf
--- /dev/null
+++ b/lt-stdlib/euclidean.lt
@@ -0,0 +1,28 @@
+
+/* Integer Math
+ */
+
+export {
+	/* Euclidean Algorithm to calculate greatest common divisor
+	 */
+    let gcd = λ{
+        a : ℤ ~ machine.Int64;
+        b : ℤ ~ machine.Int64;
+    } ↦ {
+        while( b ) {
+            let tmp = i% a b;
+            ! a b;
+            ! b tmp;
+        }
+        a;
+    };
+
+	/* least common multiple
+	 */
+    let lcm = λ{
+        a : ℤ ~ machine.Int64;
+        b : ℤ ~ machine.Int64;
+    } ↦ i* (int-abs a) (i/ (int-abs b) (gcd a b));
+
+};
+
diff --git a/lt-stdlib/int.lt b/lt-stdlib/int.lt
new file mode 100644
index 0000000..45e8344
--- /dev/null
+++ b/lt-stdlib/int.lt
@@ -0,0 +1,18 @@
+
+
+/* Two's complement Signed Integers
+ */
+
+export {
+    let int-sign = λx:ℤ~machine.Int64 ↦ bit-and (bit-shr x 63) 1;
+    let int-neg  = λx:ℤ~machine.Int64 ↦ i+ (bit-neg x) 1;
+    let int-abs  = λx:ℤ~machine.Int64 ↦ if( int-sign x ) { int-neg x; } else { x; };
+    let int-lt  = λ{ a:ℤ~machine.Int64; b:ℤ~machine.Int64; } ↦ int-sign (i- a b);
+    let int-gt  = λ{ a:ℤ~machine.Int64; b:ℤ~machine.Int64; } ↦ int-sign (i- b a);
+    let int-eq  = λ{ a:ℤ~machine.Int64; b:ℤ~machine.Int64; } ↦ if (bit-xor a b) { 0; } else { 1; };
+    let int-lte = λ{ a:ℤ~machine.Int64; b:ℤ~machine.Int64; } ↦ bit-or (int-lt a b) (int-eq a b);
+    let int-gte = λ{ a:ℤ~machine.Int64; b:ℤ~machine.Int64; } ↦ bit-or (int-gt a b) (int-eq a b);
+    let int-min = λ{ a:ℤ~machine.Int64; b:ℤ~machine.Int64; } ↦ if( int-lt a b ) { a; } else { b; };
+    let int-max = λ{ a:ℤ~machine.Int64; b:ℤ~machine.Int64; } ↦ if( int-gt a b ) { a; } else { b; };
+};
+
diff --git a/lt-stdlib/posint.lt b/lt-stdlib/posint.lt
new file mode 100644
index 0000000..3b036b7
--- /dev/null
+++ b/lt-stdlib/posint.lt
@@ -0,0 +1,63 @@
+
+
+/* Positional Integer
+ */
+export {
+    let fmt-uint-radix = λ{
+        radix : ℕ ~ ℤ_2^64 ~ machine.UInt64;
+        x : ℕ ~ ℤ_2^64 ~ machine.UInt64;
+    } ↦ {
+        if( x ) {
+            while( x ) {
+                let digit = (i% x radix);
+
+                if( int-lt digit 10 ) {
+                   i+ '0' digit;
+                } else {
+                   i+ (i- 'a' 10) digit;
+                };
+                ! x (i/ x radix);
+            }
+        } else {
+            '0';
+        };
+    };
+
+    let uint-machine-to-posint =
+        λ{
+            radix: ℕ ~ ℤ_2^64 ~ machine.UInt64;
+	    value: ℕ ~ ℤ_2^64 ~ machine.UInt64;
+        }
+	/*
+	::> ℕ
+	  ~ <PosInt radix BigEndian>
+	  ~ <Seq <Digit radix>
+	        ~ ℤ_radix
+		~ ℤ_2^64
+		~ machine.UInt64>
+	  ~ <LengthPrefixedArray machine.UInt64>
+	*/
+	↦ {
+	  let len = 0;
+	  while( value ) {
+	      /* push digit to sequence on stack */
+	      i% value radix;
+	      ! value (i/ value radix);
+	      ! len   (i+ len 1);
+	  }
+	  /* push length of sequence to stack */
+	  len;
+	};
+
+    let fmt-int-radix = λ{
+        radix: ℕ ~ ℤ_2^64 ~ machine.UInt64;
+        x : ℤ ~ machine.Int64;
+	} ↦ {
+        fmt-uint-radix radix (int-abs x);
+        if( int-sign x ) { '-'; };
+    };
+
+    let fmt-uint = λx:ℕ ↦ fmt-uint-radix 10 x;
+	let fmt-int  = λx:ℤ ↦ fmt-int-radix 10 x;
+}
+
diff --git a/lt-stdlib/ratio.lt b/lt-stdlib/ratio.lt
new file mode 100644
index 0000000..2f7ac80
--- /dev/null
+++ b/lt-stdlib/ratio.lt
@@ -0,0 +1,45 @@
+export {
+	/* Implementation of Rational Numbers
+	 */
+
+    let ratio-scale = λ{
+        {p:ℕ; q:ℕ;} : ℚ ~ <Ratio ℕ~machine.UInt64> ;
+        n : ℕ ~ machine.UInt64 ;
+    } ↦ {
+        i* q n;
+        i* p n;
+    };
+
+    let ratio-normalize = λ{
+        p: ℤ~machine.Int64;
+        q: ℤ~machine.Int64;
+    } : ℚ ~ <Ratio ℤ~machine.Int64>
+    ↦ {
+        let s = gcd p q;
+        i/ q s;
+        i/ p s;
+    };
+
+    let ratio-add = λ{
+        {ap:ℕ; aq:ℕ;}: ℚ ~ <Ratio ℕ ~ ℤ_2^64 ~ machine.UInt64> ;
+        {bp:ℕ; bq:ℕ;}: ℚ ~ <Ratio ℕ ~ ℤ_2^64 ~ machine.UInt64> ;
+    } ↦ {
+        let l = lcm aq bq;
+        let as = i/ l aq;
+        let bs = i/ l bq;
+
+        i* aq as;
+        i+ (i* ap as) (i* bp bs);
+    };
+
+    let ratio-mul = λ{
+        {ap:ℤ; aq:ℤ;}: ℚ ~ <Ratio ℤ ~ ℤ_2^64 ~ machine.Int64> ;
+        {bp:ℤ; bq:ℤ;}: ℚ ~ <Ratio ℤ ~ ℤ_2^64 ~ machine.Int64> ;                    
+    } ↦ ratio-normalize (i* ap bp) (i* aq bq);
+
+
+    let fmt-ratio = λ{ p:ℤ; q:ℤ; }: ℚ~<Ratio ℤ> ↦ {
+        fmt-int q;':';fmt-int p;
+    };
+}
+
diff --git a/lt-stdlib/stdio.lt b/lt-stdlib/stdio.lt
new file mode 100644
index 0000000..cfca557
--- /dev/null
+++ b/lt-stdlib/stdio.lt
@@ -0,0 +1,12 @@
+export {
+    /* output nullterminated string directly from datastack
+     */
+    let print-nullterm =
+        λ{} : < Seq  Char~Ascii~machine.Word >
+            ~ < NullTerminatedArray machine.Word >
+        ↦ {
+            while(dup) { emit; }
+            drop;
+        };
+}
+
diff --git a/lt-stdlib/vec3i.lt b/lt-stdlib/vec3i.lt
new file mode 100644
index 0000000..09eb54c
--- /dev/null
+++ b/lt-stdlib/vec3i.lt
@@ -0,0 +1,23 @@
+
+export {
+	/* Vec3i
+	 */
+    let vec3i-add = λ{
+        { ax:ℤ_2^64; ay:ℤ_2^64; az:ℤ_2^64; } : <Vec3 ℤ_2^64~machine.Int64>;
+        { bx:ℤ_2^64; by:ℤ_2^64; bz:ℤ_2^64; } : <Vec3 ℤ_2^64~machine.Int64>;
+    } ↦ {
+        i+ az bz;
+        i+ ay by;
+        i+ ax bx;
+    };
+
+    let fmt-vec3i =
+        λ{ x:ℤ_2^64; y:ℤ_2^64; z:ℤ_2^64; } : <Vec3 ℤ_2^64~machine.Int64>
+        ↦ {
+            '}';
+            fmt-int z; '='; 'z'; ' '; ';';
+            fmt-int y; '='; 'y'; ' '; ';';
+            fmt-int x; '='; 'x'; '{';
+        };
+}
+
diff --git a/main.lt b/main.lt
index eb654f0..f63df59 100644
--- a/main.lt
+++ b/main.lt
@@ -1,182 +1,18 @@
 {
-	/* 
-	 * Integer Operations
-	 */
-    let int-sign = λx:ℤ~machine.Int64 ↦ bit-and (bit-shr x 63) 1;
-    let int-neg  = λx:ℤ~machine.Int64 ↦ i+ (bit-neg x) 1;
-    let int-abs  = λx:ℤ~machine.Int64 ↦ if( int-sign x ) { int-neg x; } else { x; };
-    let int-lt  = λ{ a:ℤ~machine.Int64; b:ℤ~machine.Int64; } ↦ int-sign (i- a b);
-    let int-gt  = λ{ a:ℤ~machine.Int64; b:ℤ~machine.Int64; } ↦ int-sign (i- b a);
-    let int-eq  = λ{ a:ℤ~machine.Int64; b:ℤ~machine.Int64; } ↦ if (i- a b) { 0; } else { 1; };
-    let int-lte = λ{ a:ℤ~machine.Int64; b:ℤ~machine.Int64; } ↦ bit-or (int-lt a b) (int-eq a b);
-    let int-gte = λ{ a:ℤ~machine.Int64; b:ℤ~machine.Int64; } ↦ bit-or (int-gt a b) (int-eq a b);
-    let int-min = λ{ a:ℤ~machine.Int64; b:ℤ~machine.Int64; } ↦ if( int-lt a b ) { a; } else { b; };
-    let int-max = λ{ a:ℤ~machine.Int64; b:ℤ~machine.Int64; } ↦ if( int-gt a b ) { a; } else { b; };
+    print-nullterm 'H''e''l''l''o'' ''W''o''r''l''d''!''\n''\0';
 
-	/* Euclidean Algorithm to calculate greatest common divisor
-	 */
-    let gcd = λ{
-        a : ℤ ~ machine.Int64;
-        b : ℤ ~ machine.Int64;
-    } ↦ {
-        while( b ) {
-            let tmp = i% a b;
-            ! a b;
-            ! b tmp;
-        }
-        a;
-    };
-
-	/* least common multiple
-	 */
-    let lcm = λ{
-        a : ℤ ~ machine.Int64;
-        b : ℤ ~ machine.Int64;
-    } ↦ i* (int-abs a) (i/ (int-abs b) (gcd a b));
-
-
-	/* Implementation of Rational Numbers
-	 */
-    let ratio-scale = λ{
-        {p:ℕ; q:ℕ;} : ℚ ~ <Ratio ℕ~machine.UInt64> ;
-        n : ℕ ~ machine.UInt64 ;
-    } ↦ {
-        i* q n;
-        i* p n;
-    };
-
-    let ratio-normalize = λ{
-        p: ℤ~machine.Int64;
-        q: ℤ~machine.Int64;
-    } : ℚ ~ <Ratio ℤ~machine.Int64>
-    ↦ {
-        let s = gcd p q;
-        i/ q s;
-        i/ p s;
-    };
-
-    let ratio-add = λ{
-        {ap:ℕ; aq:ℕ;}: ℚ ~ <Ratio ℕ ~ ℤ_2^64 ~ machine.UInt64> ;
-        {bp:ℕ; bq:ℕ;}: ℚ ~ <Ratio ℕ ~ ℤ_2^64 ~ machine.UInt64> ;
-    } ↦ {
-        let l = lcm aq bq;
-        let as = i/ l aq;
-        let bs = i/ l bq;
-
-        i* aq as;
-        i+ (i* ap as) (i* bp bs);
-    };
-
-    let ratio-mul = λ{
-        {ap:ℤ; aq:ℤ;}: ℚ ~ <Ratio ℤ ~ ℤ_2^64 ~ machine.Int64> ;
-        {bp:ℤ; bq:ℤ;}: ℚ ~ <Ratio ℤ ~ ℤ_2^64 ~ machine.Int64> ;                    
-    } ↦ ratio-normalize (i* ap bp) (i* aq bq);
-
-    let morph-int-to-float =
-        λx: ℤ ~ machine.Int64 ~ machine.Word
-    ↦ {
-        /* todo */
-        0;
-    };
-
-    let morph-ratio-to-float =
-        λ{
-            p : ℤ~machine.Int64;
-            q : ℤ~machine.Int64;
-        } : ℚ~<Ratio ℤ~machine.Int64>
-        ↦ f/ (morph-int-to-float p) (morph-int-to-float q);
-
-
-
-	/* string output
-	 */
-    let print-nullterm =
-        λ{} : < Seq  Char ~Ascii ~ machine.Word >
-            ~ < NullTerminatedArray machine.Word >
-        ↦ {
-            while(dup) { emit; }
-            drop;
-        };
-
-    print-nullterm 'H' 'a' 'l' 'l' 'o' ' ' 'W' 'e' 'l' 't' '!' '\n' '\0';
-
-	/* integer formatting
-	 */
-    let fmt-uint-radix = λ{
-        radix : ℕ ~ ℤ_2^64 ~ machine.UInt64;
-        x : ℕ ~ ℤ_2^64 ~ machine.UInt64;
-    } ↦ {
-        if( x ) {
-            while( x ) {
-                let digit = (i% x radix);
-
-                if( int-lt digit 10 ) {
-                   i+ '0' digit;
-                } else {
-                   i+ (i- 'a' 10) digit;
-                };
-                ! x (i/ x radix);
-            }
-        } else {
-            '0';
-        };
-    };
-
-    let fmt-int-radix = λ{
-        radix: ℕ ~ ℤ_2^64 ~ machine.UInt64;
-        x : ℤ ~ machine.Int64;
-	} ↦ {
-        fmt-uint-radix radix (int-abs x);
-        if( int-sign x ) { '-'; };
-    };
-
-    let fmt-uint = λx:ℕ ↦ fmt-uint-radix 10 x;
-	let fmt-int  = λx:ℤ ↦ fmt-int-radix 10 x;
-
-	/* ratio formatting
-	 */
-    let fmt-ratio = λ{ p:ℤ; q:ℤ; } : ℚ~<Ratio ℤ~machine.Int64> ↦ {
-        fmt-int q;':';fmt-int p;
-    };
-
-
-
-
-	/*  test ratio
-	 */
+    /*  test ratio
+     */
     print-nullterm
-		(fmt-ratio { 4; int-neg 3; })
-	    ' ''*'' '
+        (fmt-ratio { 4; int-neg 3; })
+        ' ''*'' '
         (fmt-ratio { 7; 4; })
-	    ' ''='' '
+        ' ''='' '
         (fmt-ratio (ratio-mul { 4; int-neg 3; } { 7; 4; }))
-		'\n''\0';
+        '\n''\0';
 
-
-	/* Vec3i
-	 */
-    let vec3i-add = λ{
-        { ax:ℤ_2^64; ay:ℤ_2^64; az:ℤ_2^64; } : <Vec3 ℤ_2^64~machine.Int64>;
-        { bx:ℤ_2^64; by:ℤ_2^64; bz:ℤ_2^64; } : <Vec3 ℤ_2^64~machine.Int64>;
-    } ↦ {
-        i+ az bz;
-        i+ ay by;
-        i+ ax bx;
-    };
-
-    let fmt-vec3i =
-        λ{ x:ℤ_2^64; y:ℤ_2^64; z:ℤ_2^64; } : <Vec3 ℤ_2^64~machine.Int64>
-        ↦ {
-            '}';
-            fmt-int z; '='; 'z'; ' '; ';';
-            fmt-int y; '='; 'y'; ' '; ';';
-            fmt-int x; '='; 'x'; '{';
-        };
-
-
-
-	/* Colors
-	 */
+    /* Colors
+     */
     let red-u8rgb
         : <Fn <> Color ~ RGB ~ <Vec3 ℝ_0,1 ~ ℤ_256 ~ machine.UInt64>>
         = λ{} ↦ { 0; 0; 255; };
@@ -185,12 +21,16 @@
     let blue-u8rgb = λ{} ↦ { 255; 0; 0; };
     let yellow-u8rgb = λ{} ↦ { 0; 220; 220; };
 
-	print-nullterm
-		(fmt-vec3i green-u8rgb)
-		' ''+'' '
-		(fmt-vec3i blue-u8rgb) 
-		' ''='' '
+    print-nullterm (fmt-vec3i (morph-rgb-to-hsv yellow-u8rgb)) '\n''\0';
+
+    print-nullterm
+        (fmt-vec3i green-u8rgb)
+        ' ''+'' '
+        (fmt-vec3i blue-u8rgb) 
+        ' ''='' '
         (fmt-vec3i (vec3i-add green-u8rgb blue-u8rgb))
-		'\n''\0';
+        '\n''\0';
+
+    uint-machine-to-posint 16 256;
 }
 
diff --git a/src/expr.rs b/src/expr.rs
index ed2f174..7159651 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -60,6 +60,9 @@ pub enum LTExpr {
     Block {
         statements: Vec<Statement>,
     },
+    ExportBlock {
+        statements: Vec<Statement>,
+    }
 }
 
 impl LTExpr {
diff --git a/src/main.rs b/src/main.rs
index ab44e6f..e9dc49f 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -76,8 +76,10 @@ fn print_diagnostic(
 }
 
 /* TODO:
+ *   - export / import , load multiple files
  *   - Compiler error reporting
  *   - parse float literals
+ *   - return type annotation
  *   - write to address resulting from expression
  *   - sized objects
  *   - Typecheck for LTExpr::Application
@@ -96,8 +98,17 @@ fn main() {
     /* open source file
      */
     let args: Vec<String> = std::env::args().collect();
-    let path = &args[1];
-    let iter_chars = iterate_text::file::characters::IterateFileCharacters::new(path);
+
+    if args.len() < 2 {
+        eprintln!("{}", "No source files specified.".red());
+        return;
+    }
+
+    let mut args_iter = args.into_iter();
+    args_iter.next();
+
+    for path in args_iter {
+        let iter_chars = iterate_text::file::characters::IterateFileCharacters::new(path.clone());
 
     /* compile source file
      */
@@ -108,40 +119,54 @@ fn main() {
                     })
                     .peekable();
 
-    match parser::parse_expr( &typectx, &mut program_tokens ) {
-        Ok( ast ) => {
-            let bytecode = ProcedureCompiler::new(&main_scope)
-                .compile( &ast )
-                .into_asm(&"main".into());
+        match parser::parse_expr( &typectx, &mut program_tokens ) {
+            Ok( ast ) => {
+                let (exports, bytecode) = ProcedureCompiler::new(&main_scope)
+                    .compile(&ast)
+                    .into_asm(&path);
 
-            eprintln!("{}", "Compiled successfully.\n======================\n".green());
+                eprintln!("{} {}", "Compiled".green(), path.bold());
+                for (name, def) in exports.iter() {
+                    eprintln!("export {}: {:?}", name.yellow().bold(), def);
+                }
 
-            /* link assembly-program to symbols
-             */
-            linker.add_procedure("main", bytecode);
+                main_scope.write().unwrap().import(
+                    exports
+                );
 
-            /* load & run compiled bytecode
-             */
-            let main_addr = linker
-                .get_link_addr(&"main".into())
-                .expect("'main' not linked");
-        
-            vm.load(linker.link_total().expect("could not link"));
-            vm.execute(main_addr);
-
-            eprintln!(
-                "\n====\nVM execution finished\ndatastack = {:?}\n====",
-                vm.data_stack
-            );
+                /* link assembly-program to symbols
+                 */
+                linker.add_procedure(path.as_str(), bytecode);
+            }
+            Err( (region, parse_error) ) => {
+                print_diagnostic(
+                    path.as_str(),
+                    region,
+                    format!("{:?}", parse_error)
+                );
+    
+                eprintln!("=======\nParse Error: Abort\n");
+            }
         }
-        Err( (region, parse_error) ) => {
-            print_diagnostic(
-                path,
-                region,
-                format!("{:?}", parse_error)
-            );
 
-            eprintln!("=======\nerror: Parse Error\n");
         }
-    }
+
+        /* load & run compiled bytecode
+         */
+        let main_addr = linker
+            .get_link_addr(&"main.lt".into())
+            .expect("'main.lt' not found");
+
+        let bytecode = linker.link_total().expect("Link error:");
+
+        eprintln!("{} ({} bytes)", "Linked bytecode.".green(), bytecode.len());
+        eprintln!("================\n");
+
+        vm.load(bytecode);
+        vm.execute(main_addr);
+
+        eprintln!(
+           "\n================\nVM execution finished\ndatastack = {:?}\n====",
+           vm.data_stack
+        );
 }
diff --git a/src/parser.rs b/src/parser.rs
index 3d4d7b7..a882f9e 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -100,7 +100,7 @@ impl VariableBinding {
                     .flatten()
                     .collect()
         }
-   }
+    }
 }
 
 /* parse a symbol binding of the form
@@ -364,7 +364,14 @@ where It: Iterator<Item = (InputRegionTag, Result<LTIRToken, LexError>)>
                         if_expr: Box::new(if_expr),
                         else_expr: Box::new(else_expr),
                     });
-                }
+                },
+                "export" => {
+                    tokens.next();
+                    let block = parse_statement_block(typectx, tokens)?;
+                    children.push(LTExpr::ExportBlock {
+                        statements: block
+                    });
+                },
                 name => {
                     children.push(parse_atom(tokens)?);
                 }
diff --git a/src/procedure_compiler.rs b/src/procedure_compiler.rs
index ba3d422..85e9a92 100644
--- a/src/procedure_compiler.rs
+++ b/src/procedure_compiler.rs
@@ -11,7 +11,7 @@ use {
 };
 
 pub struct ProcedureCompiler {
-    symbols: Arc<RwLock<Scope>>,
+    pub symbols: Arc<RwLock<Scope>>,
     asm: tisc::Assembler,
     linker: tisc::Linker,
     result_size: usize,
@@ -27,8 +27,17 @@ impl ProcedureCompiler {
         }
     }
 
-    pub fn into_asm(mut self, proc_symbol: &String) -> Vec<tisc::assembler::AssemblyWord> {
-        let data_frame_size = self.symbols.read().unwrap().get_frame_size() as i64;
+    pub fn into_asm(mut self, proc_symbol: &String) -> (Vec<(String, SymbolDef)>, Vec<tisc::assembler::AssemblyWord>) {
+        let mut symbols =
+            Arc::try_unwrap(self.symbols).ok().unwrap()
+                .into_inner().unwrap();
+
+        symbols.update_link_addresses(
+            proc_symbol,
+            &self.linker
+        );
+
+        let data_frame_size = symbols.get_frame_size() as i64;
 
         let body = self.asm.build();
         self.linker.add_procedure("__procedure_body__", body);
@@ -36,6 +45,7 @@ impl ProcedureCompiler {
             .linker
             .get_link_addr(&"__procedure_body__".into())
             .unwrap();
+
         let subroutines = self
             .linker
             .link_relative(&"__subroutines__".into())
@@ -58,21 +68,37 @@ impl ProcedureCompiler {
         superlink.add_procedure("", entry.build());
         superlink.add_procedure("__subroutines__", subroutines);
 
-        let bytecode = superlink.link_relative(proc_symbol).expect("link error");
-        /*
-                eprintln!("\n\n{}:", proc_symbol);
-                for (i,w) in tisc::assembler::disassemble(&bytecode).iter().enumerate() {
-                    eprintln!("{}:\t\t{}", i, w);
+        symbols.update_link_addresses(
+            &proc_symbol,
+            &superlink
+        );
+
+        let mut symbol_exports = symbols.export();
+        let subroutines_addr = superlink.get_link_addr(&"__subroutines__".into()).unwrap();
+        for (name, def) in symbol_exports.iter_mut() {
+            match def {
+                SymbolDef::Procedure{ in_types:_, out_types:_, link_addr, export:_ } => {
+                    match link_addr {
+                        LinkAddr::Relative{ symbol, offset } => {
+                            *offset += subroutines_addr;
+                        }
+                        LinkAddr::Absolute(addr) => {
+                            *addr += subroutines_addr;
+                        }
+                    }
                 }
-        */
-        bytecode
+                _ => {}
+            }
+        }
+        let bytecode = superlink.link_relative(proc_symbol).expect("link error");
+        (symbol_exports, bytecode)
     }
 
     pub fn verify(&self) {
         // todo
     }
 
-    pub fn compile_statement(mut self, statement: &Statement) -> Self {
+    pub fn compile_statement(mut self, statement: &Statement, enable_export: bool) -> Self {
         match statement {
             Statement::Assignment { var_id, val_expr } => {
                 self = self.compile(val_expr);
@@ -91,6 +117,7 @@ impl ProcedureCompiler {
                         in_types,
                         out_types,
                         link_addr,
+                        export
                     }) => {
                         self.asm = self
                             .asm
@@ -111,12 +138,23 @@ impl ProcedureCompiler {
                     self.symbols
                         .write()
                         .unwrap()
-                        .declare_proc(var_id.clone(), vec![], vec![]);
-                    let lambda_procedure = ProcedureCompiler::new(&self.symbols)
+                        .declare_proc(var_id.clone(), vec![], vec![], enable_export);
+
+                    let (exports, lambda_procedure) = ProcedureCompiler::new(&self.symbols)
                         .compile(val_expr)
                         .into_asm(var_id);
 
                     self.linker.add_procedure(var_id, lambda_procedure);
+
+                    let offset = self.linker.get_link_addr(var_id).unwrap();
+
+                    if enable_export {
+                        for (name, def) in exports.iter() {
+                            eprintln!("Procedure compiler: export {}", name);
+                        }
+
+                        self.symbols.write().unwrap().import( exports );
+                    }
                 }
                 _ => {
                     self.symbols
@@ -126,7 +164,7 @@ impl ProcedureCompiler {
                     self = self.compile_statement(&Statement::Assignment {
                         var_id: var_id.clone(),
                         val_expr: val_expr.clone(),
-                    });
+                    }, false);
                 }
             },
             Statement::WhileLoop { condition, body } => {
@@ -138,7 +176,7 @@ impl ProcedureCompiler {
 
                 self.asm = tisc::Assembler::new();
                 for statement in body.into_iter() {
-                    self = self.compile_statement(statement);
+                    self = self.compile_statement(statement, false);
                 }
                 let body_asm = self.asm;
 
@@ -168,8 +206,9 @@ impl ProcedureCompiler {
                     in_types,
                     out_types,
                     link_addr,
+                    export
                 }) => {
-                    self.asm = self.asm.call(symbol.as_str());
+                    self.asm = self.asm.call_symbol(link_addr);
                 }
                 None => {
                     eprintln!("undefined symbol '{}'!", symbol);
@@ -218,7 +257,12 @@ impl ProcedureCompiler {
             }
             LTExpr::Block { statements } => {
                 for s in statements.iter() {
-                    self = self.compile_statement(s);
+                    self = self.compile_statement(s, false);
+                }
+            }
+            LTExpr::ExportBlock{ statements } => {
+                for s in statements.iter() {
+                    self = self.compile_statement(s, true);
                 }
             }
         }
diff --git a/src/symbols.rs b/src/symbols.rs
index 673643f..ee706ca 100644
--- a/src/symbols.rs
+++ b/src/symbols.rs
@@ -4,6 +4,7 @@ use {
         collections::HashMap,
         sync::{Arc, RwLock},
     },
+    tisc::linker::LinkAddr,
 };
 
 #[derive(Clone, Debug)]
@@ -19,7 +20,8 @@ pub enum SymbolDef {
     Procedure {
         in_types: Vec<laddertypes::TypeTerm>,
         out_types: Vec<laddertypes::TypeTerm>,
-        link_addr: Option<tisc::VM_Word>,
+        link_addr: LinkAddr,
+        export: bool
     },
 }
 
@@ -35,6 +37,7 @@ impl SymbolDef {
                 in_types,
                 out_types,
                 link_addr: _,
+                export: _,
             } => laddertypes::TypeTerm::App(vec![
                 typectx
                     .write()
@@ -94,6 +97,24 @@ impl Scope {
         Arc::new(RwLock::new(s))
     }
 
+    pub fn export(self) -> Vec<(String, SymbolDef)> {
+        self.symbols
+            .into_iter()
+            .filter(|(name, def)|
+                match def {
+                    SymbolDef::Procedure { in_types:_, out_types:_, link_addr:_, export } => *export,
+                    _ => false
+                }
+            )
+            .collect()
+    }
+
+    pub fn import(&mut self, symbol_imports: Vec<(String, SymbolDef)>) {
+        for (name, def) in symbol_imports {
+            self.symbols.insert( name, def );
+        }
+    }
+
     pub fn get_frame_size(&self) -> usize {
         self.frame_size
     }
@@ -116,20 +137,35 @@ impl Scope {
             }
         }
     }
-    /*
-        pub fn get_link_addr(&self, name: &str) -> Option<tisc::VM_Word> {
-            match self.get(name) {
-                Some(SymbolDef::Procedure{ in_types:_, out_types:_, link_addr }) => {
-                    link_addr
+
+    /// takes the link-addresses from a Linker
+    /// and updates the symbol table to relative addresses
+    /// based on the next super-label
+    pub fn update_link_addresses(
+        &mut self,
+        base_symbol: &String,
+        linker: &tisc::Linker
+    ) {
+        for (name, def) in self.symbols.iter_mut() {
+            if let Some(offset) = linker.get_link_addr( name ) {
+                match def {
+                    SymbolDef::Procedure {
+                        in_types:_,out_types:_,
+                        link_addr,
+                        export:_
+                    } => {
+                        *link_addr = LinkAddr::Relative{
+                            symbol: base_symbol.clone(),
+                            offset
+                        };
+                    },
+                    _ => {}
                 }
-                Some(SymbolDef::StaticRef { typ:_, link_addr }) => {
-                    link_addr
-                }
-                Some(SymbolDef::FrameRef { typ:_, stack_ref:_ }) => None,
-                None => None
             }
-        }
-    */
+        }        
+    }
+
+    
     //<><><><><><>
 
     pub fn declare_proc_parse(
@@ -165,6 +201,7 @@ impl Scope {
                         .expect("parse typeterm")
                 })
                 .collect(),
+            false
         );
     }
 
@@ -173,13 +210,15 @@ impl Scope {
         name: String,
         in_types: Vec<laddertypes::TypeTerm>,
         out_types: Vec<laddertypes::TypeTerm>,
+        export: bool
     ) {
         self.symbols.insert(
-            name,
+            name.clone(),
             SymbolDef::Procedure {
-                link_addr: None, //LinkAddr::Relative{ name, offset: 0 },
+                link_addr: LinkAddr::Relative{ symbol: name, offset: 0 },
                 in_types,
                 out_types,
+                export
             },
         );
     }