summary refs log tree commit diff stats
path: root/nim
diff options
context:
space:
mode:
authorrumpf_a@web.de <>2009-10-21 10:20:15 +0200
committerrumpf_a@web.de <>2009-10-21 10:20:15 +0200
commit053309e60aee1eda594a4817ac8ac2fb8c18fb04 (patch)
tree0f1ce8b0de0b493045eb97eeca6ebf06542de601 /nim
parent581572b28c65bc9fe47974cfd625210a69be0f3f (diff)
downloadNim-053309e60aee1eda594a4817ac8ac2fb8c18fb04.tar.gz
version 0.8.2
Diffstat (limited to 'nim')
-rwxr-xr-xnim/ast.pas87
-rwxr-xr-xnim/ccgexprs.pas4
-rwxr-xr-xnim/ccgtypes.pas3
-rwxr-xr-xnim/cgen.pas8
-rwxr-xr-x[-rw-r--r--]nim/cgmeth.pas0
-rwxr-xr-xnim/commands.pas20
-rwxr-xr-xnim/depends.pas4
-rwxr-xr-xnim/docgen.pas8
-rwxr-xr-xnim/ecmasgen.pas2
-rwxr-xr-xnim/evals.pas2
-rwxr-xr-xnim/extccomp.pas79
-rwxr-xr-xnim/filters.pas137
-rwxr-xr-xnim/importer.pas5
-rwxr-xr-xnim/llstream.pas61
-rwxr-xr-xnim/lookups.pas4
-rwxr-xr-xnim/main.pas31
-rwxr-xr-xnim/msgs.pas15
-rwxr-xr-xnim/nimrod.pas20
-rwxr-xr-xnim/nos.pas18
-rwxr-xr-xnim/nsystem.pas18
-rwxr-xr-xnim/nversion.pas4
-rwxr-xr-xnim/options.pas12
-rwxr-xr-xnim/osproc.pas36
-rwxr-xr-xnim/pasparse.pas14
-rwxr-xr-xnim/passes.pas11
-rwxr-xr-xnim/pbraces.pas1499
-rwxr-xr-xnim/platform.pas68
-rwxr-xr-xnim/pnimsyn.pas528
-rwxr-xr-xnim/pragmas.pas21
-rwxr-xr-xnim/ptmplsyn.pas210
-rwxr-xr-xnim/rnimsyn.pas4
-rwxr-xr-xnim/rodread.pas3
-rwxr-xr-xnim/rst.pas3
-rwxr-xr-xnim/scanner.pas8
-rwxr-xr-xnim/semexprs.pas59
-rwxr-xr-xnim/semstmts.pas18
-rwxr-xr-xnim/semtempl.pas2
-rwxr-xr-xnim/semtypes.pas6
-rwxr-xr-xnim/strutils.pas7
-rwxr-xr-xnim/syntaxes.pas240
-rwxr-xr-xnim/transf.pas11
-rwxr-xr-xnim/wordrecg.pas8
42 files changed, 2576 insertions, 722 deletions
diff --git a/nim/ast.pas b/nim/ast.pas
index cbe5b37fd..8927fc862 100755
--- a/nim/ast.pas
+++ b/nim/ast.pas
@@ -78,27 +78,26 @@ type
     nkBracket, nkBracketExpr, nkPragmaExpr, nkRange, 
     nkDotExpr, nkCheckedFieldExpr, nkDerefExpr, nkIfExpr, 
     nkElifExpr, nkElseExpr, nkLambda, nkAccQuoted, 
-    nkTableConstr, nkQualified, nkBind, nkSymChoice, 
-    nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv, nkConv, 
-    nkCast, nkAddr, nkHiddenAddr, nkHiddenDeref, 
-    nkObjDownConv, nkObjUpConv, nkChckRangeF, nkChckRange64, 
-    nkChckRange, nkStringToCString, nkCStringToString, nkPassAsOpenArray, 
-    nkAsgn, nkFastAsgn, nkGenericParams, nkFormalParams, 
-    nkOfInherit, nkModule, nkProcDef, nkMethodDef, 
-    nkConverterDef, nkMacroDef, nkTemplateDef, nkIteratorDef, 
-    nkOfBranch, nkElifBranch, nkExceptBranch, nkElse, 
-    nkMacroStmt, nkAsmStmt, nkPragma, nkIfStmt, 
-    nkWhenStmt, nkForStmt, nkWhileStmt, nkCaseStmt, 
-    nkVarSection, nkConstSection, nkConstDef, nkTypeSection, 
-    nkTypeDef, nkYieldStmt, nkTryStmt, nkFinally, 
-    nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt, 
-    nkBlockStmt, nkDiscardStmt, nkStmtList, nkImportStmt, 
-    nkFromStmt, nkIncludeStmt, nkCommentStmt, nkStmtListExpr, 
-    nkBlockExpr, nkStmtListType, nkBlockType, nkTypeOfExpr, 
-    nkObjectTy, nkTupleTy, nkRecList, nkRecCase, 
-    nkRecWhen, nkRefTy, nkPtrTy, nkVarTy, 
-    nkDistinctTy, nkProcTy, nkEnumTy, nkEnumFieldDef, 
-    nkReturnToken);
+    nkTableConstr, nkBind, nkSymChoice, nkHiddenStdConv, 
+    nkHiddenSubConv, nkHiddenCallConv, nkConv, nkCast, 
+    nkAddr, nkHiddenAddr, nkHiddenDeref, nkObjDownConv, 
+    nkObjUpConv, nkChckRangeF, nkChckRange64, nkChckRange, 
+    nkStringToCString, nkCStringToString, nkPassAsOpenArray, nkAsgn, 
+    nkFastAsgn, nkGenericParams, nkFormalParams, nkOfInherit, 
+    nkModule, nkProcDef, nkMethodDef, nkConverterDef, 
+    nkMacroDef, nkTemplateDef, nkIteratorDef, nkOfBranch, 
+    nkElifBranch, nkExceptBranch, nkElse, nkMacroStmt, 
+    nkAsmStmt, nkPragma, nkIfStmt, nkWhenStmt, 
+    nkForStmt, nkWhileStmt, nkCaseStmt, nkVarSection, 
+    nkConstSection, nkConstDef, nkTypeSection, nkTypeDef, 
+    nkYieldStmt, nkTryStmt, nkFinally, nkRaiseStmt, 
+    nkReturnStmt, nkBreakStmt, nkContinueStmt, nkBlockStmt, 
+    nkDiscardStmt, nkStmtList, nkImportStmt, nkFromStmt, 
+    nkIncludeStmt, nkCommentStmt, nkStmtListExpr, nkBlockExpr, 
+    nkStmtListType, nkBlockType, nkTypeOfExpr, nkObjectTy, 
+    nkTupleTy, nkRecList, nkRecCase, nkRecWhen, 
+    nkRefTy, nkPtrTy, nkVarTy, nkDistinctTy, 
+    nkProcTy, nkEnumTy, nkEnumFieldDef, nkReturnToken);
   TNodeKinds = set of TNodeKind;
 const
   NodeKindToStr: array [TNodeKind] of string = (
@@ -113,27 +112,26 @@ const
     'nkBracket', 'nkBracketExpr', 'nkPragmaExpr', 'nkRange', 
     'nkDotExpr', 'nkCheckedFieldExpr', 'nkDerefExpr', 'nkIfExpr', 
     'nkElifExpr', 'nkElseExpr', 'nkLambda', 'nkAccQuoted', 
-    'nkTableConstr', 'nkQualified', 'nkBind', 'nkSymChoice', 
-    'nkHiddenStdConv', 'nkHiddenSubConv', 'nkHiddenCallConv', 'nkConv', 
-    'nkCast', 'nkAddr', 'nkHiddenAddr', 'nkHiddenDeref', 
-    'nkObjDownConv', 'nkObjUpConv', 'nkChckRangeF', 'nkChckRange64', 
-    'nkChckRange', 'nkStringToCString', 'nkCStringToString', 'nkPassAsOpenArray', 
-    'nkAsgn', 'nkFastAsgn', 'nkGenericParams', 'nkFormalParams', 
-    'nkOfInherit', 'nkModule', 'nkProcDef', 'nkMethodDef', 
-    'nkConverterDef', 'nkMacroDef', 'nkTemplateDef', 'nkIteratorDef', 
-    'nkOfBranch', 'nkElifBranch', 'nkExceptBranch', 'nkElse', 
-    'nkMacroStmt', 'nkAsmStmt', 'nkPragma', 'nkIfStmt', 
-    'nkWhenStmt', 'nkForStmt', 'nkWhileStmt', 'nkCaseStmt', 
-    'nkVarSection', 'nkConstSection', 'nkConstDef', 'nkTypeSection', 
-    'nkTypeDef', 'nkYieldStmt', 'nkTryStmt', 'nkFinally', 
-    'nkRaiseStmt', 'nkReturnStmt', 'nkBreakStmt', 'nkContinueStmt', 
-    'nkBlockStmt', 'nkDiscardStmt', 'nkStmtList', 'nkImportStmt', 
-    'nkFromStmt', 'nkIncludeStmt', 'nkCommentStmt', 'nkStmtListExpr', 
-    'nkBlockExpr', 'nkStmtListType', 'nkBlockType', 'nkTypeOfExpr', 
-    'nkObjectTy', 'nkTupleTy', 'nkRecList', 'nkRecCase', 
-    'nkRecWhen', 'nkRefTy', 'nkPtrTy', 'nkVarTy', 
-    'nkDistinctTy', 'nkProcTy', 'nkEnumTy', 'nkEnumFieldDef', 
-    'nkReturnToken');
+    'nkTableConstr', 'nkBind', 'nkSymChoice', 'nkHiddenStdConv', 
+    'nkHiddenSubConv', 'nkHiddenCallConv', 'nkConv', 'nkCast', 
+    'nkAddr', 'nkHiddenAddr', 'nkHiddenDeref', 'nkObjDownConv', 
+    'nkObjUpConv', 'nkChckRangeF', 'nkChckRange64', 'nkChckRange', 
+    'nkStringToCString', 'nkCStringToString', 'nkPassAsOpenArray', 'nkAsgn', 
+    'nkFastAsgn', 'nkGenericParams', 'nkFormalParams', 'nkOfInherit', 
+    'nkModule', 'nkProcDef', 'nkMethodDef', 'nkConverterDef', 
+    'nkMacroDef', 'nkTemplateDef', 'nkIteratorDef', 'nkOfBranch', 
+    'nkElifBranch', 'nkExceptBranch', 'nkElse', 'nkMacroStmt', 
+    'nkAsmStmt', 'nkPragma', 'nkIfStmt', 'nkWhenStmt', 
+    'nkForStmt', 'nkWhileStmt', 'nkCaseStmt', 'nkVarSection', 
+    'nkConstSection', 'nkConstDef', 'nkTypeSection', 'nkTypeDef', 
+    'nkYieldStmt', 'nkTryStmt', 'nkFinally', 'nkRaiseStmt', 
+    'nkReturnStmt', 'nkBreakStmt', 'nkContinueStmt', 'nkBlockStmt', 
+    'nkDiscardStmt', 'nkStmtList', 'nkImportStmt', 'nkFromStmt', 
+    'nkIncludeStmt', 'nkCommentStmt', 'nkStmtListExpr', 'nkBlockExpr', 
+    'nkStmtListType', 'nkBlockType', 'nkTypeOfExpr', 'nkObjectTy', 
+    'nkTupleTy', 'nkRecList', 'nkRecCase', 'nkRecWhen', 
+    'nkRefTy', 'nkPtrTy', 'nkVarTy', 'nkDistinctTy', 
+    'nkProcTy', 'nkEnumTy', 'nkEnumFieldDef', 'nkReturnToken');
 type
   TSymFlag = (
     sfUsed, sfStar, sfMinus, sfInInterface, 
@@ -141,7 +139,7 @@ type
     sfExportc, sfVolatile, sfRegister, sfPure, 
     sfResult, sfNoSideEffect, sfSideEffect, sfMainModule, 
     sfSystemModule, sfNoReturn, sfAddrTaken, sfCompilerProc, 
-    sfCppMethod, sfDiscriminant, sfDeprecated, sfInClosure, 
+    sfProcvar, sfDiscriminant, sfDeprecated, sfInClosure, 
     sfTypeCheck, sfCompileTime, sfThreadVar, sfMerge, 
     sfDeadCodeElim, sfBorrow);
   TSymFlags = set of TSymFlag;
@@ -152,7 +150,7 @@ const
     'sfExportc', 'sfVolatile', 'sfRegister', 'sfPure', 
     'sfResult', 'sfNoSideEffect', 'sfSideEffect', 'sfMainModule', 
     'sfSystemModule', 'sfNoReturn', 'sfAddrTaken', 'sfCompilerProc', 
-    'sfCppMethod', 'sfDiscriminant', 'sfDeprecated', 'sfInClosure', 
+    'sfProcvar', 'sfDiscriminant', 'sfDeprecated', 'sfInClosure', 
     'sfTypeCheck', 'sfCompileTime', 'sfThreadVar', 'sfMerge', 
     'sfDeadCodeElim', 'sfBorrow');
 type
@@ -340,6 +338,7 @@ type
     lfNoDeepCopy,  // no need for a deep copy
     lfNoDecl,      // do not declare it in C
     lfDynamicLib,  // link symbol to dynamic library
+    lfExportLib,   // export symbol for dynamic library generation
     lfHeader       // include header file for symbol
   );
 
diff --git a/nim/ccgexprs.pas b/nim/ccgexprs.pas
index 99d36da2d..a5789487a 100755
--- a/nim/ccgexprs.pas
+++ b/nim/ccgexprs.pas
@@ -1086,6 +1086,8 @@ begin
       app(pl, ', ')
   end;
   if (typ.sons[0] <> nil) and invalidRetType then begin
+    // XXX (detected by pegs module 64bit): p(result, result) is not
+    // correct here. Thus we always allocate a temporary:
     if d.k = locNone then getTemp(p, typ.sons[0], d);
     app(pl, addrLoc(d));
   end;
@@ -2212,7 +2214,7 @@ begin
                                 '); unknown symbol')
       end
     end;
-    nkQualified: expr(p, e.sons[1], d);
+    //nkQualified: expr(p, e.sons[1], d);
     nkStrLit..nkTripleStrLit, nkIntLit..nkInt64Lit,
     nkFloatLit..nkFloat64Lit, nkNilLit, nkCharLit: begin
       putIntoDest(p, d, e.typ, genLiteral(p, e));
diff --git a/nim/ccgtypes.pas b/nim/ccgtypes.pas
index db07a6864..1c07fe5c7 100755
--- a/nim/ccgtypes.pas
+++ b/nim/ccgtypes.pas
@@ -221,7 +221,8 @@ begin
   assert(not (sfResult in s.flags));
   case pt.Kind of
     tyObject: begin
-      if (optByRef in s.options) or (getSize(pt) > platform.floatSize) then
+      // XXX quick hack floatSize*2 for the pegs module under 64bit
+      if (optByRef in s.options) or (getSize(pt) > platform.floatSize*2) then
         result := true // requested anyway
       else if (tfFinal in pt.flags) and (pt.sons[0] = nil) then
         result := false // no need, because no subtyping possible
diff --git a/nim/cgen.pas b/nim/cgen.pas
index 17ae8b461..0b74f25b7 100755
--- a/nim/cgen.pas
+++ b/nim/cgen.pas
@@ -659,6 +659,8 @@ var
 begin
   p := newProc(prc, m);
   header := genProcHeader(m, prc);
+  if (gCmd <> cmdCompileToLLVM) and (lfExportLib in prc.loc.flags) then
+    header := con('N_LIB_EXPORT ', header);
   returnStmt := nil;
   assert(prc.ast <> nil);
 
@@ -942,7 +944,11 @@ const
     '  call void @NimMain()$n' +
     '  ret i32 0$n' +
     '}$n';
-  WinNimDllMain = WinNimMain;
+  WinNimDllMain =
+    'N_LIB_EXPORT N_CDECL(void, NimMain)(void) {$n' +
+    '  int dummy[8];$n' +{&}
+    CommonMainBody +{&}
+    '}$n';
   WinCDllMain =
     'BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, $n' +
     '                    LPVOID lpvReserved) {$n' +
diff --git a/nim/cgmeth.pas b/nim/cgmeth.pas
index 6b9335c4c..6b9335c4c 100644..100755
--- a/nim/cgmeth.pas
+++ b/nim/cgmeth.pas
diff --git a/nim/commands.pas b/nim/commands.pas
index b281552c9..1663b6b93 100755
--- a/nim/commands.pas
+++ b/nim/commands.pas
@@ -1,7 +1,7 @@
 //

 //

 //           The Nimrod Compiler

-//        (c) Copyright 2008 Andreas Rumpf

+//        (c) Copyright 2009 Andreas Rumpf

 //

 //    See the file "copying.txt", included in this

 //    distribution, for details about the copyright.

@@ -85,7 +85,7 @@ const
 +{&} '  -a, --assertions:on|off   code generation for assertions ON|OFF' +{&} nl
 +{&} '  --dead_code_elim:on|off   whole program dead code elimination ON|OFF' +{&} nl
 +{&} '  --opt:none|speed|size     optimize not at all or for speed|size' +{&} nl
-+{&} '  --app:console|gui         generate a console|GUI application' +{&} nl
++{&} '  --app:console|gui|lib     generate a console|GUI application|dynamic library' +{&} nl
 +{&} '  -r, --run                 run the compiled program with given arguments' +{&} nl
 +{&} '  --advanced                show advanced command line switches' +{&} nl
 +{&} '  -h, --help                show this help' +{&} nl
@@ -127,10 +127,12 @@ const
 +{&} '  --checkpoints:on|off      turn on|off checkpoints; for debugging Nimrod' +{&} nl
 +{&} '  --skip_cfg                do not read the general configuration file' +{&} nl
 +{&} '  --skip_proj_cfg           do not read the project''s configuration file' +{&} nl
-+{&} '  --gc:refc|boehm           use Nimrod''s native GC|Boehm GC' +{&} nl
++{&} '  --gc:refc|boehm|none      use Nimrod''s native GC|Boehm GC|no GC' +{&} nl
 +{&} '  --index:FILE              use FILE to generate a documenation index file' +{&} nl
 +{&} '  --putenv:key=value        set an environment variable' +{&} nl
 +{&} '  --list_cmd                list the commands used to execute external programs' +{&} nl
++{&} '  --parallel_build=0|1|...  perform a parallel build' +{&} nl
++{&} '                            value = number of processors (0 for auto-detect)' +{&} nl
 +{&} '  --verbosity:0|1|2|3       set Nimrod''s verbosity level (0 is default)' +{&} nl
 +{&} '  -v, --version             show detailed version information' +{&} nl
 //[[[end]]]

@@ -152,7 +154,7 @@ begin
   if (pass = passCmd1) and not helpWritten then begin

     // BUGFIX 19

     MessageOut(getCommandLineDesc());

-    helpWritten := true;
+    helpWritten := true;

     halt(0);

   end

 end;

@@ -362,10 +364,10 @@ begin
     wNoLinking: begin

       expectNoArg(switch, arg, pass, info);

       include(gGlobalOptions, optNoLinking);

-    end;
-    wNoMain: begin
+    end;

+    wNoMain: begin

       expectNoArg(switch, arg, pass, info);

-      include(gGlobalOptions, optNoMain);    
+      include(gGlobalOptions, optNoMain);    

     end;

     wForceBuild, wF: begin

       expectNoArg(switch, arg, pass, info);

@@ -523,6 +525,10 @@ begin
       expectArg(switch, arg, pass, info);

       gVerbosity := parseInt(arg);

     end;

+    wParallelBuild: begin

+      expectArg(switch, arg, pass, info);      

+      gNumberOfProcessors := parseInt(arg);

+    end;

     wVersion, wV: begin

       expectNoArg(switch, arg, pass, info);

       writeVersionInfo(pass);

diff --git a/nim/depends.pas b/nim/depends.pas
index d8b978142..c5b844044 100755
--- a/nim/depends.pas
+++ b/nim/depends.pas
@@ -51,12 +51,12 @@ begin
   case n.kind of
     nkImportStmt: begin
       for i := 0 to sonsLen(n)-1 do begin
-        imported := getFileTrunk(getModuleFile(n.sons[i]));
+        imported := extractFileTrunk(getModuleFile(n.sons[i]));
         addDependencyAux(g.module.name.s, imported);
       end
     end;
     nkFromStmt: begin
-      imported := getFileTrunk(getModuleFile(n.sons[0]));
+      imported := extractFileTrunk(getModuleFile(n.sons[0]));
       addDependencyAux(g.module.name.s, imported);
     end;
     nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr: begin
diff --git a/nim/docgen.pas b/nim/docgen.pas
index 4d94a2a68..468dd1bc9 100755
--- a/nim/docgen.pas
+++ b/nim/docgen.pas
@@ -19,7 +19,7 @@ interface
 
 uses
   nsystem, charsets, ast, astalgo, strutils, nhashes, options, nversion, msgs,
-  nos, ropes, idents, wordrecg, nmath, pnimsyn, rnimsyn, scanner, rst, ntime,
+  nos, ropes, idents, wordrecg, nmath, syntaxes, rnimsyn, scanner, rst, ntime,
   highlite;
 
 procedure CommandDoc(const filename: string);
@@ -85,7 +85,7 @@ var
   dummyHasToc: bool;
 begin
   if gIndexFile = '' then exit;
-  gIndexFile := appendFileExt(gIndexFile, 'txt');
+  gIndexFile := addFileExt(gIndexFile, 'txt');
   d.indexValFilename := changeFileExt(extractFilename(d.filename), HtmlExt);
   if ExistsFile(gIndexFile) then begin
     d.indexFile := rstParse(readFile(gIndexFile), false, gIndexFile, 0, 1,
@@ -1135,7 +1135,7 @@ var
   ast: PNode;
   d: PDoc;
 begin
-  ast := parseFile(appendFileExt(filename, nimExt));
+  ast := parseFile(addFileExt(filename, nimExt));
   if ast = nil then exit;
   d := newDocumentor(filename);
   initIndexFile(d);
@@ -1152,7 +1152,7 @@ var
   rst: PRstNode;
   code: PRope;
 begin
-  filen := appendFileExt(filename, 'txt');
+  filen := addFileExt(filename, 'txt');
   d := newDocumentor(filen);
   initIndexFile(d);
   rst := rstParse(readFile(filen), false, filen, 0, 1, d.hasToc);
diff --git a/nim/ecmasgen.pas b/nim/ecmasgen.pas
index 8edd2605a..59cb3c330 100755
--- a/nim/ecmasgen.pas
+++ b/nim/ecmasgen.pas
@@ -1096,7 +1096,7 @@ begin
       end;
     end;
     nkCheckedFieldExpr: genCheckedFieldAddr(p, n, r);
-    nkDotExpr, nkQualified: genFieldAddr(p, n, r);
+    nkDotExpr: genFieldAddr(p, n, r);
     nkBracketExpr: genArrayAddr(p, n, r);
     else InternalError(n.info, 'genAddr');
   end
diff --git a/nim/evals.pas b/nim/evals.pas
index 3787ff371..bb6c8a2b1 100755
--- a/nim/evals.pas
+++ b/nim/evals.pas
@@ -1324,7 +1324,7 @@ begin
     nkTemplateDef, nkConstSection, nkIteratorDef, nkConverterDef,
     nkIncludeStmt, nkImportStmt, nkFromStmt: begin end;
     nkIdentDefs, nkCast, nkYieldStmt, nkAsmStmt, nkForStmt, nkPragmaExpr,
-    nkQualified, nkLambda, nkContinueStmt, nkIdent:
+    nkLambda, nkContinueStmt, nkIdent:
       stackTrace(c, n, errCannotInterpretNodeX, nodeKindToStr[n.kind]);
     else InternalError(n.info, 'evalAux: ' + nodekindToStr[n.kind]);
   end;
diff --git a/nim/extccomp.pas b/nim/extccomp.pas
index 9e7c7e4cc..aab4febb7 100755
--- a/nim/extccomp.pas
+++ b/nim/extccomp.pas
@@ -1,7 +1,7 @@
 //
 //
 //           The Nimrod Compiler
-//        (c) Copyright 2008 Andreas Rumpf
+//        (c) Copyright 2009 Andreas Rumpf
 //
 //    See the file "copying.txt", included in this
 //    distribution, for details about the copyright.
@@ -304,10 +304,10 @@ procedure setCC(const ccname: string);
 var
   i: TSystemCC;
 begin
-  linkOptions := '';
   ccompiler := nameToCC(ccname);
   if ccompiler = ccNone then rawMessage(errUnknownCcompiler, ccname);
   compileOptions := getConfigVar(CC[ccompiler].name + '.options.always');
+  linkOptions := getConfigVar(CC[ccompiler].name + '.options.linker');
   ccompilerpath := getConfigVar(CC[ccompiler].name + '.path');
   for i := low(CC) to high(CC) do undefSymbol(CC[i].name);
   defineSymbol(CC[ccompiler].name);
@@ -323,6 +323,7 @@ begin
   if gCmd = cmdCompileToCpp then
     cExt := '.cpp';
   addCompileOption(getConfigVar(CC[ccompiler].name + '.options.always'));
+  addLinkOption(getConfigVar(CC[ccompiler].name + '.options.linker'));
   if length(ccompilerPath) = 0 then
     ccompilerpath := getConfigVar(CC[ccompiler].name + '.path');
 end;
@@ -387,8 +388,8 @@ end;
 procedure execExternalProgram(const cmd: string);
 begin
   if (optListCmd in gGlobalOptions) or (gVerbosity > 0) then
-    MessageOut('Executing: ' +{&} nl +{&} cmd);
-  if executeCommand(cmd) <> 0 then
+    MessageOut(cmd);
+  if execCmd(cmd) <> 0 then
     rawMessage(errExecutionOfProgramFailed);
 end;
 
@@ -398,7 +399,7 @@ var
 begin
   splitPath(projectFile, path, scriptname);
   SplitFilename(scriptname, name, ext);
-  name := appendFileExt('compile_' + name, platform.os[targetOS].scriptExt);
+  name := addFileExt('compile_' + name, platform.os[targetOS].scriptExt);
   WriteRope(script, joinPath(path, name));
 end;
 
@@ -437,7 +438,7 @@ var
 begin
   c := ccompiler;
   options := compileOptions;
-  trunk := getFileTrunk(cfilename);
+  trunk := extractFileTrunk(cfilename);
   if optCDebug in gGlobalOptions then begin
     key := trunk + '.debug';
     if existsConfigVar(key) then
@@ -468,7 +469,7 @@ begin
   key := cc[c].name + '.exe';
   if existsConfigVar(key) then
     exe := getConfigVar(key);
-  if targetOS = osWindows then exe := appendFileExt(exe, 'exe');
+  if targetOS = osWindows then exe := addFileExt(exe, 'exe');
 
   if (optGenDynLib in gGlobalOptions)
   and (ospNeedsPIC in platform.OS[targetOS].props) then
@@ -494,7 +495,7 @@ begin
     objfile := toObjFile(cfile)
   else
     objfile := completeCFilePath(toObjFile(cfile));
-  cfile := quoteIfContainsWhite(AppendFileExt(cfile, cExt));
+  cfile := quoteIfContainsWhite(AddFileExt(cfile, cExt));
   objfile := quoteIfContainsWhite(objfile);
   
   result := quoteIfContainsWhite(format(compilePattern,
@@ -517,7 +518,9 @@ begin
 end;
 
 procedure CompileCFile(const list: TLinkedList;
-                       var script: PRope; isExternal: Boolean);
+                       var script: PRope; 
+                       var cmds: TStringSeq;
+                       isExternal: Boolean);
 var
   it: PStrEntry;
   compileCmd: string;
@@ -528,7 +531,7 @@ begin
     // call the C compiler for the .c file:
     compileCmd := getCompileCFileCmd(it.data, isExternal);
     if not (optCompileOnly in gGlobalOptions) then
-      execExternalProgram(compileCmd);
+      add(cmds, compileCmd); //execExternalProgram(compileCmd);
     if (optGenScript in gGlobalOptions) then begin
       app(script, compileCmd);
       app(script, tnl);
@@ -543,6 +546,8 @@ var
   linkCmd, objfiles, exefile, buildgui, builddll, linkerExe: string;
   c: TSystemCC; // an alias to ccompiler
   script: PRope;
+  cmds: TStringSeq;
+  res, i: int;
 begin
   if (gGlobalOptions * [optCompileOnly, optGenScript] = [optCompileOnly]) then
     exit; // speed up that call if only compiling and no script shall be
@@ -551,41 +556,53 @@ begin
   fileCounter := 0;
   c := ccompiler;
   script := nil;
-  CompileCFile(toCompile, script, false);
-  CompileCFile(externalToCompile, script, true);
-
+  cmds := {@ignore} nil {@emit @[]};
+  CompileCFile(toCompile, script, cmds, false);
+  CompileCFile(externalToCompile, script, cmds, true);
+  if not (optCompileOnly in gGlobalOptions) then begin
+    if gNumberOfProcessors = 0 then 
+      gNumberOfProcessors := countProcessors();
+    if gNumberOfProcessors <= 1 then begin
+      res := 0;
+      for i := 0 to high(cmds) do res := max(execCmd(cmds[i]), res);
+    end
+    else if (optListCmd in gGlobalOptions) or (gVerbosity > 0) then
+      res := execProcesses(cmds, {@set}[poEchoCmd, poUseShell, poParentStreams], 
+                           gNumberOfProcessors)
+    else
+      res := execProcesses(cmds, {@set}[poUseShell, poParentStreams],
+                           gNumberOfProcessors);
+    if res <> 0 then
+      rawMessage(errExecutionOfProgramFailed);
+  end;
+  
   if not (optNoLinking in gGlobalOptions) then begin
     // call the linker:
     linkerExe := getConfigVar(cc[c].name + '.linkerexe');
     if length(linkerExe) = 0 then linkerExe := cc[c].linkerExe;
-    if targetOS = osWindows then linkerExe := appendFileExt(linkerExe, 'exe');
+    if targetOS = osWindows then linkerExe := addFileExt(linkerExe, 'exe');
 
     if (platform.hostOS <> targetOS) then
       linkCmd := quoteIfContainsWhite(linkerExe)
     else
       linkCmd := quoteIfContainsWhite(JoinPath(ccompilerpath, linkerExe));
 
-    if optGenDynLib in gGlobalOptions then
-      buildDll := cc[c].buildDll
-    else
-      buildDll := '';
     if optGenGuiApp in gGlobalOptions then
       buildGui := cc[c].buildGui
     else
       buildGui := '';
-
-    if optGenDynLib in gGlobalOptions then
-      exefile := platform.os[targetOS].dllPrefix
-    else
-      exefile := '';
+      
+    if optGenDynLib in gGlobalOptions then begin
+      exefile := format(platform.os[targetOS].dllFrmt,
+                        [extractFileTrunk(projectFile)]);
+      buildDll := cc[c].buildDll;
+    end
+    else begin
+      exefile := extractFileTrunk(projectFile) +{&} platform.os[targetOS].exeExt;
+      buildDll := '';
+    end;
     if targetOS = platform.hostOS then
-      add(exefile, projectFile)
-    else
-      add(exefile, extractFileName(projectFile));
-    if optGenDynLib in gGlobalOptions then
-      add(exefile, platform.os[targetOS].dllExt)
-    else
-      add(exefile, platform.os[targetOS].exeExt);
+      exefile := joinPath(extractDir(projectFile), exefile);
     exefile := quoteIfContainsWhite(exefile);
 
     it := PStrEntry(toLink.head);
@@ -639,7 +656,7 @@ begin
   result := nil;
   it := PStrEntry(list.head);
   while it <> nil do begin
-    appf(result, '--file:r"$1"$n', [toRope(AppendFileExt(it.data, cExt))]);
+    appf(result, '--file:r"$1"$n', [toRope(AddFileExt(it.data, cExt))]);
     it := PStrEntry(it.next);
   end;
 end;
diff --git a/nim/filters.pas b/nim/filters.pas
new file mode 100755
index 000000000..95f628fe2
--- /dev/null
+++ b/nim/filters.pas
@@ -0,0 +1,137 @@
+//
+//
+//           The Nimrod Compiler
+//        (c) Copyright 2009 Andreas Rumpf
+//
+//    See the file "copying.txt", included in this
+//    distribution, for details about the copyright.
+//
+unit filters;
+
+// This module implements Nimrod's simple filters and helpers for filters.
+
+{$include config.inc}
+
+interface
+
+uses
+  nsystem, llstream, nos, charsets, wordrecg, idents, strutils,
+  ast, astalgo, msgs, options, rnimsyn;
+
+function filterReplace(input: PLLStream; const filename: string;
+                       call: PNode): PLLStream;
+function filterStrip(input: PLLStream; const filename: string;
+                     call: PNode): PLLStream;
+
+// helpers to retrieve arguments:
+function charArg(n: PNode; const name: string; pos: int; default: Char): Char;
+function strArg(n: PNode; const name: string; pos: int;
+                const default: string): string;
+function boolArg(n: PNode; const name: string; pos: int; default: bool): bool;
+
+implementation
+
+procedure invalidPragma(n: PNode);
+begin
+  liMessage(n.info, errXNotAllowedHere, renderTree(n, {@set}[renderNoComments]));
+end;
+
+function getArg(n: PNode; const name: string; pos: int): PNode;
+var
+  i: int;
+begin
+  result := nil;
+  if n.kind in [nkEmpty..nkNilLit] then exit;
+  for i := 1 to sonsLen(n)-1 do
+    if n.sons[i].kind = nkExprEqExpr then begin
+      if n.sons[i].sons[0].kind <> nkIdent then invalidPragma(n);
+      if IdentEq(n.sons[i].sons[0].ident, name) then begin
+        result := n.sons[i].sons[1];
+        exit
+      end
+    end
+    else if i = pos then begin
+      result := n.sons[i]; exit
+    end
+end;
+
+function charArg(n: PNode; const name: string; pos: int; default: Char): Char;
+var
+  x: PNode;
+begin
+  x := getArg(n, name, pos);
+  if x = nil then result := default
+  else if x.kind = nkCharLit then result := chr(int(x.intVal))
+  else invalidPragma(n);
+end;
+
+function strArg(n: PNode; const name: string; pos: int;
+                const default: string): string;
+var
+  x: PNode;
+begin
+  x := getArg(n, name, pos);
+  if x = nil then result := default
+  else if x.kind in [nkStrLit..nkTripleStrLit] then result := x.strVal
+  else invalidPragma(n);
+end;
+
+function boolArg(n: PNode; const name: string; pos: int; default: bool): bool;
+var
+  x: PNode;
+begin
+  x := getArg(n, name, pos);
+  if x = nil then result := default
+  else if (x.kind = nkIdent) and IdentEq(x.ident, 'true') then result := true
+  else if (x.kind = nkIdent) and IdentEq(x.ident, 'false') then result := false
+  else invalidPragma(n);
+end;
+
+// -------------------------- strip filter -----------------------------------
+
+function filterStrip(input: PLLStream; const filename: string;
+                     call: PNode): PLLStream;
+var
+  line, pattern, stripped: string;
+  leading, trailing: bool;
+begin
+  pattern := strArg(call, 'startswith', 1, '');
+  leading := boolArg(call, 'leading', 2, true);
+  trailing := boolArg(call, 'trailing', 3, true);
+  
+  result := LLStreamOpen('');
+  while not LLStreamAtEnd(input) do begin
+    line := LLStreamReadLine(input);
+  {@ignore}
+    stripped := strip(line);
+  {@emit
+    stripped := strip(line, leading, trailing);
+  }
+    if (length(pattern) = 0) or startsWith(stripped, pattern) then 
+      LLStreamWriteln(result, stripped)
+    else
+      LLStreamWriteln(result, line)
+  end;
+  LLStreamClose(input);
+end;
+
+// -------------------------- replace filter ---------------------------------
+
+function filterReplace(input: PLLStream; const filename: string;
+                       call: PNode): PLLStream;
+var
+  line, sub, by: string;
+begin
+  sub := strArg(call, 'sub', 1, '');
+  if length(sub) = 0 then invalidPragma(call);
+  by := strArg(call, 'by', 2, '');
+
+  result := LLStreamOpen('');  
+  while not LLStreamAtEnd(input) do begin
+    line := LLStreamReadLine(input);
+    LLStreamWriteln(result, replace(line, sub, by))
+  end;
+  LLStreamClose(input);    
+end;
+
+end.
diff --git a/nim/importer.pas b/nim/importer.pas
index d031ffe3a..a1ed57978 100755
--- a/nim/importer.pas
+++ b/nim/importer.pas
@@ -29,9 +29,8 @@ implementation
 function findModule(const info: TLineInfo; const modulename: string): string;
 // returns path to module
 begin
-  result := options.FindFile(AppendFileExt(modulename, nimExt));
-  if result = '' then
-    liMessage(info, errCannotOpenFile, modulename);
+  result := options.FindFile(AddFileExt(modulename, nimExt));
+  if result = '' then liMessage(info, errCannotOpenFile, modulename);
 end;
 
 function getModuleFile(n: PNode): string;
diff --git a/nim/llstream.pas b/nim/llstream.pas
index df4c823a6..30d9c0287 100755
--- a/nim/llstream.pas
+++ b/nim/llstream.pas
@@ -1,7 +1,7 @@
 //
 //
 //           The Nimrod Compiler
-//        (c) Copyright 2008 Andreas Rumpf
+//        (c) Copyright 2009 Andreas Rumpf
 //
 //    See the file "copying.txt", included in this
 //    distribution, for details about the copyright.
@@ -25,7 +25,7 @@ type
     kind: TLLStreamKind; // accessible for low-level access (lexbase uses this)
     f: TBinaryFile;
     s: string;
-    pos: int; // for string streams
+    rd, wr: int; // for string streams
   end;
   PLLStream = ^TLLStream;
   
@@ -46,6 +46,8 @@ procedure LLStreamWrite(s: PLLStream; const data: string); overload;
 procedure LLStreamWrite(s: PLLStream; data: Char); overload;
 procedure LLStreamWrite(s: PLLStream; buf: pointer; buflen: int); overload;
 
+procedure LLStreamWriteln(s: PLLStream; const data: string);
+
 function LLStreamAtEnd(s: PLLStream): bool;
 
 implementation
@@ -97,7 +99,6 @@ begin
   {@emit}
   result.kind := llsStdIn;
   result.s := '';
-  result.pos := -1;
 end;
 
 procedure LLStreamClose(s: PLLStream);
@@ -114,7 +115,7 @@ var
   L: int;
 begin
   s.s := '';
-  s.pos := 0;
+  s.rd := 0;
   while true do begin
     write(output, 'Nimrod> ');
     line := readLine(input);
@@ -123,10 +124,10 @@ begin
     add(s.s, nl);
     if (L > 0) and (line[L-1+strStart] = '#') then break;
   end;
-  result := min(bufLen, length(s.s)-s.pos);
+  result := min(bufLen, length(s.s)-s.rd);
   if result > 0 then begin
-    copyMem(buf, addr(s.s[strStart+s.pos]), result);
-    inc(s.pos, result)
+    copyMem(buf, addr(s.s[strStart+s.rd]), result);
+    inc(s.rd, result)
   end
 end;
 
@@ -135,10 +136,10 @@ begin
   case s.kind of 
     llsNone: result := 0;
     llsString: begin
-      result := min(bufLen, length(s.s)-s.pos);
+      result := min(bufLen, length(s.s)-s.rd);
       if result > 0 then begin
-        copyMem(buf, addr(s.s[strStart+s.pos]), result);
-        inc(s.pos, result)
+        copyMem(buf, addr(s.s[strStart+s.rd]), result);
+        inc(s.rd, result)
       end
     end;
     llsFile:  result := readBuffer(s.f, buf, bufLen);
@@ -152,20 +153,20 @@ begin
     llsNone: result := '';
     llsString: begin
       result := '';
-      while s.pos < length(s.s) do begin
-        case s.s[s.pos+strStart] of 
+      while s.rd < length(s.s) do begin
+        case s.s[s.rd+strStart] of 
           #13: begin 
-            inc(s.pos); 
-            if s.s[s.pos+strStart] = #10 then inc(s.pos);
+            inc(s.rd); 
+            if s.s[s.rd+strStart] = #10 then inc(s.rd);
             break
           end;
-          #10: begin inc(s.pos); break end;
+          #10: begin inc(s.rd); break end;
           else begin
-            addChar(result, s.s[s.pos+strStart]);
-            inc(s.pos);
+            addChar(result, s.s[s.rd+strStart]);
+            inc(s.rd);
           end
         end
-      end    
+      end
     end;
     llsFile: result := readLine(s.f);
     llsStdIn: result := readLine(input);
@@ -176,7 +177,7 @@ function LLStreamAtEnd(s: PLLStream): bool;
 begin
   case s.kind of
     llsNone: result := true;
-    llsString: result := s.pos < length(s.s);
+    llsString: result := s.rd >= length(s.s);
     llsFile: result := endOfFile(s.f);
     llsStdIn: result := false;
   end
@@ -186,9 +187,15 @@ procedure LLStreamWrite(s: PLLStream; const data: string); overload;
 begin
   case s.kind of 
     llsNone, llsStdIn: begin end;
-    llsString: add(s.s, data);
+    llsString: begin add(s.s, data); inc(s.wr, length(data)) end;
     llsFile: nimWrite(s.f, data);
-  end
+  end;
+end;
+
+procedure LLStreamWriteln(s: PLLStream; const data: string);
+begin
+  LLStreamWrite(s, data);
+  LLStreamWrite(s, nl);
 end;
 
 procedure LLStreamWrite(s: PLLStream; data: Char); overload;
@@ -197,7 +204,7 @@ var
 begin
   case s.kind of 
     llsNone, llsStdIn: begin end;
-    llsString: addChar(s.s, data);
+    llsString: begin addChar(s.s, data); inc(s.wr); end;
     llsFile: begin
       c := data;
       {@discard} writeBuffer(s.f, addr(c), sizeof(c));
@@ -212,8 +219,8 @@ begin
     llsString: begin
       if bufLen > 0 then begin
         setLength(s.s, length(s.s) + bufLen);
-        copyMem(addr(s.s[strStart+s.pos]), buf, bufLen);
-        inc(s.pos, bufLen);
+        copyMem(addr(s.s[strStart+s.wr]), buf, bufLen);
+        inc(s.wr, bufLen);
       end
     end;
     llsFile: {@discard} writeBuffer(s.f, buf, bufLen);
@@ -229,9 +236,9 @@ begin
   case s.kind of 
     llsNone, llsStdIn: result := '';
     llsString: begin
-      if s.pos = 0 then result := s.s
-      else result := ncopy(s.s, s.pos+strStart);
-      s.pos := length(s.s);
+      if s.rd = 0 then result := s.s
+      else result := ncopy(s.s, s.rd+strStart);
+      s.rd := length(s.s);
     end;
     llsFile: begin
       result := newString(bufSize);
diff --git a/nim/lookups.pas b/nim/lookups.pas
index d68095635..e4c07224f 100755
--- a/nim/lookups.pas
+++ b/nim/lookups.pas
@@ -177,7 +177,7 @@ begin
       if ambiguousCheck and IntSetContains(c.AmbiguousSymbols, result.id) then
         liMessage(n.info, errUseQualifier, n.sym.name.s)
     end;
-    nkDotExpr, nkQualified: begin
+    nkDotExpr: begin
       result := nil;
       m := qualifiedLookUp(c, n.sons[0], false);
       if (m <> nil) and (m.kind = skModule) then begin
@@ -237,7 +237,7 @@ begin
         result := InitIdentIter(o.it, c.tab.stack[o.stackPtr], n.sym.name);
       end; *)
     end; 
-    nkDotExpr, nkQualified: begin
+    nkDotExpr: begin
       o.mode := oimOtherModule;
       o.m := qualifiedLookUp(c, n.sons[0], false);
       if (o.m <> nil) and (o.m.kind = skModule) then begin
diff --git a/nim/main.pas b/nim/main.pas
index 1bb2ce586..c3f2cbd85 100755
--- a/nim/main.pas
+++ b/nim/main.pas
@@ -15,10 +15,10 @@ unit main;
 interface
 
 uses
-  nsystem, llstream, strutils, ast, astalgo, scanner, pnimsyn, rnimsyn, 
+  nsystem, llstream, strutils, ast, astalgo, scanner, syntaxes, rnimsyn, 
   options, msgs, nos, lists, condsyms, paslex, pasparse, rodread, rodwrite,
   ropes, trees, wordrecg, sem, semdata, idents, passes, docgen,
-  extccomp, cgen, ecmasgen, platform, ptmplsyn, interact, nimconf, importer,
+  extccomp, cgen, ecmasgen, platform, interact, nimconf, importer,
   passaux, depends, transf, evals, types;
 
 procedure MainCommand(const cmd, filename: string);
@@ -69,7 +69,7 @@ begin
 {@emit}
   result.id := -1; // for better error checking
   result.kind := skModule;
-  result.name := getIdent(getFileTrunk(filename));
+  result.name := getIdent(extractFileTrunk(filename));
   result.owner := result; // a module belongs to itself
   result.info := newLineInfo(filename, 1, 1);
   include(result.flags, sfUsed);
@@ -101,7 +101,7 @@ var
   f: string;
 begin
   rd := nil;
-  f := appendFileExt(filename, nimExt);
+  f := addFileExt(filename, nimExt);
   result := newModule(filename);
   if isMainFile then include(result.flags, sfMainModule);
   if isSystemFile then include(result.flags, sfSystemModule);
@@ -118,8 +118,8 @@ end;
 procedure CompileProject(const filename: string);
 begin
   {@discard} CompileModule(
-    JoinPath(options.libpath, appendFileExt('system', nimExt)), false, true);
-  {@discard} CompileModule(appendFileExt(filename, nimExt), true, false);
+    JoinPath(options.libpath, addFileExt('system', nimExt)), false, true);
+  {@discard} CompileModule(addFileExt(filename, nimExt), true, false);
 end;
 
 procedure semanticPasses;
@@ -137,7 +137,7 @@ begin
   compileProject(filename);
   generateDot(filename);
   execExternalProgram('dot -Tpng -o' +{&} changeFileExt(filename, 'png') +{&}
-                      ' ' +{&} changeFileExt(filename, 'dot'));
+                                 ' ' +{&} changeFileExt(filename, 'dot'));
 end;
 
 procedure CommandCheck(const filename: string);
@@ -185,7 +185,7 @@ begin
   
   // load system module:
   {@discard} CompileModule(
-    JoinPath(options.libpath, appendFileExt('system', nimExt)), false, true);
+    JoinPath(options.libpath, addFileExt('system', nimExt)), false, true);
 
   m := newModule('stdin');
   m.id := getID();
@@ -228,7 +228,7 @@ procedure CommandExportSymbols(const filename: string);
 var
   module: PNode;
 begin
-  module := parseFile(appendFileExt(filename, NimExt));
+  module := parseFile(addFileExt(filename, NimExt));
   if module <> nil then begin
     exSymbols(module);
     renderModule(module, getOutFile(filename, 'pretty.'+NimExt));
@@ -239,7 +239,7 @@ procedure CommandPretty(const filename: string);
 var
   module: PNode;
 begin
-  module := parseFile(appendFileExt(filename, NimExt));
+  module := parseFile(addFileExt(filename, NimExt));
   if module <> nil then
     renderModule(module, getOutFile(filename, 'pretty.'+NimExt));
 end;
@@ -255,7 +255,7 @@ begin
   fillChar(tok, sizeof(tok), 0);
   fillChar(L, sizeof(L), 0);
 {@emit}
-  f := appendFileExt(filename, 'pas');
+  f := addFileExt(filename, 'pas');
   stream := LLStreamOpen(f, fmRead);
   if stream <> nil then begin
     OpenLexer(L, f, stream);
@@ -277,7 +277,7 @@ var
   f: string;
   stream: PLLStream;
 begin
-  f := appendFileExt(filename, 'pas');
+  f := addFileExt(filename, 'pas');
   stream := LLStreamOpen(f, fmRead);
   if stream <> nil then begin
     OpenPasParser(p, f, stream);
@@ -300,7 +300,7 @@ begin
 {@ignore}
   fillChar(tok^, sizeof(tok^), 0);
 {@emit}
-  f := appendFileExt(filename, nimExt);
+  f := addFileExt(filename, nimExt);
   stream := LLStreamOpen(f, fmRead);
   if stream <> nil then begin 
     openLexer(L, f, stream);
@@ -331,8 +331,7 @@ begin
     prependStr(searchPaths, dir);
   end;
   setID(100);
-  passes.gIncludeFile := parseFile;
-  passes.gIncludeTmplFile := ptmplsyn.parseTmplFile;
+  passes.gIncludeFile := syntaxes.parseFile;
   passes.gImportModule := importModule;
 
   case whichKeyword(cmd) of
@@ -408,7 +407,7 @@ begin
     wParse: begin
       gCmd := cmdParse;
       wantFile(filename);
-      {@discard} parseFile(appendFileExt(filename, nimExt));
+      {@discard} parseFile(addFileExt(filename, nimExt));
     end;
     wScan: begin
       gCmd := cmdScan;
diff --git a/nim/msgs.pas b/nim/msgs.pas
index 9d421a5bf..f1a3a200a 100755
--- a/nim/msgs.pas
+++ b/nim/msgs.pas
@@ -127,7 +127,7 @@ type
     errOverOrUnderflow,
     errCannotEvalXBecauseIncompletelyDefined,
     errChrExpectsRange0_255,
-    errDotRequiresRecordOrObjectType,
+    errDynlibRequiresExportc,
     errUndeclaredFieldX,
     errNilAccess,
     errIndexOutOfBounds,
@@ -182,7 +182,7 @@ type
     errButExpectedX,
     errAmbiguousCallXYZ,
     errWrongNumberOfArguments,
-    errInlineProcHasNoAddress,
+    errXCannotBePassedToProcVar,
     errXCannotBeInParamDecl,
     errPragmaOnlyInHeaderOfProc,
     errImplOfXNotAllowed,
@@ -215,7 +215,6 @@ type
     errATypeHasNoValue,
     errXisNoType,
     errCircumNeedsPointer,
-    errInvalidContextForBuiltinX,
     errInvalidExpression,
     errInvalidExpressionX,
     errEnumHasNoValueX,
@@ -272,6 +271,7 @@ type
     warnUnknownSubstitutionX,
     warnLanguageXNotSupported,
     warnCommentXIgnored,
+    warnXisPassedToProcVar,
     warnUser,
     hintSuccess,
     hintSuccessX,
@@ -365,7 +365,7 @@ const
     'over- or underflow',
     'cannot evalutate ''$1'' because type is not defined completely',
     '''chr'' expects an int in the range 0..255',
-    '''.'' requires a record or object type',
+    '''dynlib'' requires ''exportc''',
     'undeclared field: ''$1''',
     'attempt to access a nil address',
     'index out of bounds',
@@ -420,7 +420,7 @@ const
     'but expected ''$1''',
     'ambiguous call; both $1 and $2 match for: $3',
     'wrong number of arguments',
-    'an inline proc has no address',
+    '''$1'' cannot be passed to a procvar',
     '$1 cannot be declared in parameter declaration',
     'pragmas are only in the header of a proc allowed',
     'implementation of ''$1'' is not allowed',
@@ -453,7 +453,6 @@ const
     'a type has no value',
     'invalid type: ''$1''',
     '''^'' needs a pointer or reference type',
-    'invalid context for builtin ''$1''',
     'invalid expression',
     'invalid expression: ''$1''',
     'enum has no value ''$1''',
@@ -510,6 +509,7 @@ const
     'unknown substitution ''$1'' [UnknownSubstitutionX]',
     'language ''$1'' not supported [LanguageXNotSupported]',
     'comment ''$1'' ignored [CommentXIgnored]',
+    '''$1'' is passed to a procvar; deprecated [XisPassedToProcVar]',
     '$1 [User]',
     'operation successful [Success]',
     'operation successful ($1 lines compiled; $2 sec total) [SuccessX]',
@@ -526,7 +526,7 @@ const
     '$1 [User]'
   );
 const
-  WarningsToStr: array [0..13] of string = (
+  WarningsToStr: array [0..14] of string = (
     'CannotOpenFile',
     'OctalEscape',
     'XIsNeverRead',
@@ -540,6 +540,7 @@ const
     'UnknownSubstitutionX',
     'LanguageXNotSupported',
     'CommentXIgnored',
+    'XisPassedToProcVar',
     'User'
   );
 const
diff --git a/nim/nimrod.pas b/nim/nimrod.pas
index 728325ccc..b3247bff0 100755
--- a/nim/nimrod.pas
+++ b/nim/nimrod.pas
@@ -1,7 +1,7 @@
 //
 //
 //           The Nimrod Compiler
-//        (c) Copyright 2006 Andreas Rumpf
+//        (c) Copyright 2009 Andreas Rumpf
 //
 //    See the file "copying.txt", included in this
 //    distribution, for details about the copyright.
@@ -28,15 +28,27 @@ var
 procedure ProcessCmdLine(pass: TCmdLinePass; var command, filename: string);
 var
   p: TOptParser;
+  bracketLe: int;
+  key, val: string;
 begin
   p := parseopt.init();
   while true do begin
     parseopt.next(p);
     case p.kind of
       cmdEnd: break;
-      cmdLongOption, cmdShortOption:
-        ProcessSwitch(p.key, p.val, pass, cmdLineInfo);
-      cmdArgument: begin
+      cmdLongOption, cmdShortOption: begin
+        // hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off")
+        // we fix this here
+        bracketLe := strutils.find(p.key, '[');
+        if bracketLe >= strStart then begin
+          key := ncopy(p.key, strStart, bracketLe-1);
+          val := ncopy(p.key, bracketLe+1) +{&} ':' +{&} p.val;
+          ProcessSwitch(key, val, pass, cmdLineInfo);
+        end
+        else
+          ProcessSwitch(p.key, p.val, pass, cmdLineInfo);
+      end;
+      cmdArgument: begin  
         if command = '' then command := p.key
         else if filename = '' then begin
           filename := unixToNativePath(p.key);
diff --git a/nim/nos.pas b/nim/nos.pas
index 2edb0864e..7b9d2ee09 100755
--- a/nim/nos.pas
+++ b/nim/nos.pas
@@ -74,7 +74,7 @@ function GetConfigDir(): string;
 procedure SplitFilename(const filename: string; out name, extension: string);
 
 function ExistsFile(const filename: string): Boolean;
-function AppendFileExt(const filename, ext: string): string;
+function AddFileExt(const filename, ext: string): string;
 function ChangeFileExt(const filename, ext: string): string;
 
 procedure createDir(const dir: string);
@@ -84,8 +84,20 @@ function UnixToNativePath(const path: string): string;
 
 function sameFile(const path1, path2: string): boolean;
 
+
+function extractFileTrunk(const filename: string): string;
+
+
 implementation
 
+function extractFileTrunk(const filename: string): string;
+var
+  f, e, dir: string;
+begin
+  splitPath(filename, dir, f);
+  splitFilename(f, result, e);
+end;
+
 function GetConfigDir(): string;
 begin
 {$ifdef windows}
@@ -103,7 +115,7 @@ end;
 function UnixToNativePath(const path: string): string;
 begin
   if dirSep <> '/' then
-    result := replaceStr(path, '/', dirSep)
+    result := replace(path, '/', dirSep)
   else
     result := path;
 end;
@@ -150,7 +162,7 @@ begin
     result := extSep + ext
 end;
 
-function AppendFileExt(const filename, ext: string): string;
+function AddFileExt(const filename, ext: string): string;
 var
   extPos: int;
 begin
diff --git a/nim/nsystem.pas b/nim/nsystem.pas
index 49d17b172..4cdfade93 100755
--- a/nim/nsystem.pas
+++ b/nim/nsystem.pas
@@ -56,6 +56,11 @@ const
   snil = '';
 
 type
+  TStringSeq = array of string;
+  TCharSet = set of Char;
+
+
+type
   Natural = 0..high(int);
   Positive = 1..high(int);
   NObject = object // base type for all objects, cannot use
@@ -214,9 +219,11 @@ function readFile(const filename: string): string;
 
 procedure nimWrite(var f: tBinaryFile; const str: string); overload;
 
-procedure add(var x: string; const y: string);
+procedure add(var x: string; const y: string); overload;
 // Pascal version of string appending. Terminating zero is ignored.
 
+procedure add(var s: TStringSeq; const y: string); overload;
+
 function isNil(s: string): bool;
 
 implementation
@@ -238,6 +245,15 @@ begin
     else x := x + y;
   end
 end;
+
+procedure add(var s: TStringSeq; const y: string); overload;
+var
+  L: int;
+begin
+  L := length(s);
+  setLength(s, L+1);
+  s[L] := y;
+end;
 {@emit}
 
 function alloc(size: int): Pointer;
diff --git a/nim/nversion.pas b/nim/nversion.pas
index b2ba371f6..20ab5cc77 100755
--- a/nim/nversion.pas
+++ b/nim/nversion.pas
@@ -31,10 +31,10 @@ const
   //cog.outl('VersionMinor = %s;' % ver[1])

   //cog.outl('VersionPatch = %s;' % ver[2])

   //]]]

-  VersionAsString = '0.8.1';
+  VersionAsString = '0.8.2';
   VersionMajor = 0;
   VersionMinor = 8;
-  VersionPatch = 1;
+  VersionPatch = 2;
   //[[[[end]]]]

 

 implementation

diff --git a/nim/options.pas b/nim/options.pas
index d210f3b44..d03a24f2a 100755
--- a/nim/options.pas
+++ b/nim/options.pas
@@ -101,6 +101,7 @@ var
   gCmd: TCommands = cmdNone; // the command
 
   gVerbosity: int; // how verbose the compiler is
+  gNumberOfProcessors: int; // number of processors
 
 function FindFile(const f: string): string;
 
@@ -111,7 +112,6 @@ const
   HtmlExt = 'html';
   TexExt = 'tex';
   IniExt = 'ini';
-  TmplExt = 'tmpl';
   DocConfig = 'nimdoc.cfg';
   DocTexConfig = 'nimdoc.tex.cfg';
 
@@ -124,8 +124,6 @@ function toGeneratedFile(const path, ext: string): string;
 function getPrefixDir: string;
 // gets the application directory
 
-function getFileTrunk(const filename: string): string;
-
 // additional configuration variables:
 var
   gConfigVars: PStringTable;
@@ -185,14 +183,6 @@ begin
   SplitPath(appdir, result, bin);
 end;
 
-function getFileTrunk(const filename: string): string;
-var
-  f, e, dir: string;
-begin
-  splitPath(filename, dir, f);
-  splitFilename(f, result, e);
-end;
-
 function shortenDir(const dir: string): string;
 var 
   prefix: string;
diff --git a/nim/osproc.pas b/nim/osproc.pas
index dd6bd10f0..485daaf67 100755
--- a/nim/osproc.pas
+++ b/nim/osproc.pas
@@ -17,14 +17,42 @@ interface
 

 uses

   nsystem, nos;

-

-function executeCommand(const cmd: string): int;

+
+type
+  TProcessOption = (poEchoCmd, poUseShell, poStdErrToStdOut, poParentStreams);
+  TProcessOptions = set of TProcessOption;
+

+function execCmd(const cmd: string): int;

+function execProcesses(const cmds: array of string;
+                       options: TProcessOptions;
+                       n: int): int;
+
+function countProcessors(): int;
 

 implementation

 

-function executeCommand(const cmd: string): int;

-begin

+function execCmd(const cmd: string): int;

+begin
+  writeln(output, cmd);

   result := executeShellCommand(cmd);

 end;

+
+function execProcesses(const cmds: array of string;
+                       options: TProcessOptions;
+                       n: int): int;
+var
+  i: int;
+begin
+  result := 0;
+  for i := 0 to high(cmds) do begin
+    //if poEchoCmd in options then writeln(output, cmds[i]);
+    result := max(result, execCmd(cmds[i]))
+  end
+end;
+
+function countProcessors(): int;
+begin
+  result := 1;
+end;
 

 end.

diff --git a/nim/pasparse.pas b/nim/pasparse.pas
index c44c735d6..dbfbf0437 100755
--- a/nim/pasparse.pas
+++ b/nim/pasparse.pas
@@ -61,7 +61,7 @@ const
     ('len',          'length'),
     ('setlength',    'setlen')
   );
-  nimReplacements: array [1..34] of TReplaceTuple = (
+  nimReplacements: array [1..35] of TReplaceTuple = (
     ('nimread',      'read'),
     ('nimwrite',     'write'),
     ('nimclosefile', 'close'),
@@ -98,7 +98,8 @@ const
     ('ttextfile', 'tfile'),
     ('tbinaryfile', 'tfile'),
     ('strstart', '0'+''),
-    ('nl', '"\n"')
+    ('nl', '"\n"'),
+    ('tostring', '$'+'')
     {,
     ('NL', '"\n"'),
     ('tabulator', '''\t'''),
@@ -455,7 +456,7 @@ begin
     skipCom(p, result);
     if p.tok.xkind = pxSymbol then begin
       a := result;
-      result := newNodeI(nkQualified, a.info);
+      result := newNodeI(nkDotExpr, a.info);
       addSon(result, a);
       addSon(result, createIdentNodeP(p.tok.ident, p));
       getTok(p);
@@ -1279,6 +1280,13 @@ begin
         noBody := true;
         getTok(p); opt(p, pxSemicolon);
       end;
+      wProcVar: begin
+        // This is a fake for the Nimrod compiler. There is no ``procvar``
+        // directive in Pascal.
+        if result = nil then result := newNodeP(nkPragma, p);
+        addSon(result, newIdentNodeP(getIdent('procvar'), p));
+        getTok(p); opt(p, pxSemicolon);
+      end;
       wVarargs: begin
         if result = nil then result := newNodeP(nkPragma, p);
         addSon(result, newIdentNodeP(getIdent('varargs'), p));
diff --git a/nim/passes.pas b/nim/passes.pas
index 8d961e5d3..c280a75b1 100755
--- a/nim/passes.pas
+++ b/nim/passes.pas
@@ -1,7 +1,7 @@
 //
 //
 //           The Nimrod Compiler
-//        (c) Copyright 2008 Andreas Rumpf
+//        (c) Copyright 2009 Andreas Rumpf
 //
 //    See the file "copying.txt", included in this
 //    distribution, for details about the copyright.
@@ -19,7 +19,7 @@ uses
   nsystem, charsets, strutils,
   lists, options, ast, astalgo, llstream,
   msgs, platform, nos, condsyms, idents, rnimsyn, types,
-  extccomp, nmath, magicsys, nversion, nimsets, pnimsyn, ntime, rodread;
+  extccomp, nmath, magicsys, nversion, nimsets, syntaxes, ntime, rodread;
 
 type
   TPassContext = object(NObject) // the pass's context
@@ -61,7 +61,6 @@ function astNeeded(s: PSym): bool;
 var
   gImportModule: function (const filename: string): PSym;
   gIncludeFile: function (const filename: string): PNode;
-  gIncludeTmplFile: function (const filename: string): PNode;
 
 implementation
 
@@ -165,7 +164,7 @@ end;
 procedure processModule(module: PSym; const filename: string;
                         stream: PLLStream; rd: PRodReader);
 var
-  p: TParser;
+  p: TParsers;
   n: PNode;
   a: TPassContextArray;
   s: PLLStream;
@@ -183,13 +182,13 @@ begin
     else
       s := stream;
     while true do begin
-      openParser(p, filename, s); 
+      openParsers(p, filename, s); 
       while true do begin
         n := parseTopLevelStmt(p);
         if n = nil then break;
         processTopLevelStmt(n, a)
       end;
-      closeParser(p);
+      closeParsers(p);
       if s.kind <> llsStdIn then break;
     end;
     closePasses(a);
diff --git a/nim/pbraces.pas b/nim/pbraces.pas
new file mode 100755
index 000000000..d362fac65
--- /dev/null
+++ b/nim/pbraces.pas
@@ -0,0 +1,1499 @@
+//
+//
+//           The Nimrod Compiler
+//        (c) Copyright 2009 Andreas Rumpf
+//
+//    See the file "copying.txt", included in this
+//    distribution, for details about the copyright.
+//
+unit pbraces;
+
+{$include config.inc}
+
+interface
+
+uses
+  nsystem, llstream, scanner, idents, strutils, ast, msgs, pnimsyn;
+
+function ParseAll(var p: TParser): PNode;
+
+function parseTopLevelStmt(var p: TParser): PNode;
+// implements an iterator. Returns the next top-level statement or nil if end
+// of stream.
+
+implementation
+
+// ------------------- Expression parsing ------------------------------------
+
+function parseExpr(var p: TParser): PNode; forward;
+function parseStmt(var p: TParser): PNode; forward;
+
+function parseTypeDesc(var p: TParser): PNode; forward;
+function parseParamList(var p: TParser): PNode; forward;
+
+function optExpr(var p: TParser): PNode; // [expr]
+begin
+  if (p.tok.tokType <> tkComma) and (p.tok.tokType <> tkBracketRi)
+  and (p.tok.tokType <> tkDotDot) then
+    result := parseExpr(p)
+  else
+    result := nil;
+end;
+
+function dotdotExpr(var p: TParser; first: PNode = nil): PNode;
+begin
+  result := newNodeP(nkRange, p);
+  addSon(result, first);
+  getTok(p);
+  optInd(p, result);
+  addSon(result, optExpr(p));
+end;
+
+function indexExpr(var p: TParser): PNode;
+// indexExpr ::= '..' [expr] | expr ['=' expr | '..' expr]
+var
+  a, b: PNode;
+begin
+  if p.tok.tokType = tkDotDot then
+    result := dotdotExpr(p)
+  else begin
+    a := parseExpr(p);
+    case p.tok.tokType of
+      tkEquals: begin
+        result := newNodeP(nkExprEqExpr, p);
+        addSon(result, a);
+        getTok(p);
+        if p.tok.tokType = tkDotDot then
+          addSon(result, dotdotExpr(p))
+        else begin
+          b := parseExpr(p);
+          if p.tok.tokType = tkDotDot then b := dotdotExpr(p, b);
+          addSon(result, b);
+        end
+      end;
+      tkDotDot: result := dotdotExpr(p, a);
+      else result := a
+    end
+  end
+end;
+
+function indexExprList(var p: TParser; first: PNode): PNode;
+var
+  a: PNode;
+begin
+  result := newNodeP(nkBracketExpr, p);
+  addSon(result, first);
+  getTok(p);
+  optInd(p, result);
+  while (p.tok.tokType <> tkBracketRi) and (p.tok.tokType <> tkEof)
+  and (p.tok.tokType <> tkSad) do begin
+    a := indexExpr(p);
+    addSon(result, a);
+    if p.tok.tokType <> tkComma then break;
+    getTok(p);
+    optInd(p, a)
+  end;
+  optSad(p);
+  eat(p, tkBracketRi);
+end;
+
+function exprColonEqExpr(var p: TParser; kind: TNodeKind;
+                         tok: TTokType): PNode;
+var
+  a: PNode;
+begin
+  a := parseExpr(p);
+  if p.tok.tokType = tok then begin
+    result := newNodeP(kind, p);
+    getTok(p);
+    //optInd(p, result);
+    addSon(result, a);
+    addSon(result, parseExpr(p));
+  end
+  else
+    result := a
+end;
+
+procedure exprListAux(var p: TParser; elemKind: TNodeKind;
+                      endTok, sepTok: TTokType; result: PNode);
+var
+  a: PNode;
+begin
+  getTok(p);
+  optInd(p, result);
+  while (p.tok.tokType <> endTok) and (p.tok.tokType <> tkEof) do begin
+    a := exprColonEqExpr(p, elemKind, sepTok);
+    addSon(result, a);
+    if p.tok.tokType <> tkComma then break;
+    getTok(p);
+    optInd(p, a)
+  end;
+  eat(p, endTok);
+end;
+
+function qualifiedIdent(var p: TParser): PNode;
+var
+  a: PNode;
+begin
+  result := parseSymbol(p);
+  if p.tok.tokType = tkDot then begin
+    getTok(p);
+    optInd(p, result);
+    a := result;
+    result := newNodeI(nkDotExpr, a.info);
+    addSon(result, a);
+    addSon(result, parseSymbol(p));
+  end;
+end;
+
+procedure qualifiedIdentListAux(var p: TParser; endTok: TTokType;
+                                result: PNode);
+var
+  a: PNode;
+begin
+  getTok(p);
+  optInd(p, result);
+  while (p.tok.tokType <> endTok) and (p.tok.tokType <> tkEof) do begin
+    a := qualifiedIdent(p);
+    addSon(result, a);
+    if p.tok.tokType <> tkComma then break;
+    getTok(p);
+    optInd(p, a)
+  end;
+  eat(p, endTok);
+end;
+
+procedure exprColonEqExprListAux(var p: TParser; elemKind: TNodeKind;
+                                 endTok, sepTok: TTokType; result: PNode);
+var
+  a: PNode;
+begin
+  getTok(p);
+  optInd(p, result);
+  while (p.tok.tokType <> endTok) and (p.tok.tokType <> tkEof)
+  and (p.tok.tokType <> tkSad) do begin
+    a := exprColonEqExpr(p, elemKind, sepTok);
+    addSon(result, a);
+    if p.tok.tokType <> tkComma then break;
+    getTok(p);
+    optInd(p, a)
+  end;
+  optSad(p);
+  eat(p, endTok);
+end;
+
+function exprColonEqExprList(var p: TParser; kind, elemKind: TNodeKind;
+                             endTok, sepTok: TTokType): PNode;
+begin
+  result := newNodeP(kind, p);
+  exprColonEqExprListAux(p, elemKind, endTok, sepTok, result);
+end;
+
+function parseCast(var p: TParser): PNode;
+begin
+  result := newNodeP(nkCast, p);
+  getTok(p);
+  eat(p, tkBracketLe);
+  optInd(p, result);
+  addSon(result, parseTypeDesc(p));
+  optSad(p);
+  eat(p, tkBracketRi);
+  eat(p, tkParLe);
+  optInd(p, result);
+  addSon(result, parseExpr(p));
+  optSad(p);
+  eat(p, tkParRi);
+end;
+
+function parseAddr(var p: TParser): PNode;
+begin
+  result := newNodeP(nkAddr, p);
+  getTok(p);
+  eat(p, tkParLe);
+  optInd(p, result);
+  addSon(result, parseExpr(p));
+  optSad(p);
+  eat(p, tkParRi);
+end;
+
+procedure setBaseFlags(n: PNode; base: TNumericalBase);
+begin
+  case base of
+    base10: begin end;
+    base2: include(n.flags, nfBase2);
+    base8: include(n.flags, nfBase8);
+    base16: include(n.flags, nfBase16);
+  end
+end;
+
+function identOrLiteral(var p: TParser): PNode;
+begin
+  case p.tok.tokType of
+    tkSymbol: begin
+      result := newIdentNodeP(p.tok.ident, p);
+      getTok(p)
+    end;
+    tkAccent: result := accExpr(p);
+    // literals
+    tkIntLit: begin
+      result := newIntNodeP(nkIntLit, p.tok.iNumber, p);
+      setBaseFlags(result, p.tok.base);
+      getTok(p);
+    end;
+    tkInt8Lit: begin
+      result := newIntNodeP(nkInt8Lit, p.tok.iNumber, p);
+      setBaseFlags(result, p.tok.base);
+      getTok(p);
+    end;
+    tkInt16Lit: begin
+      result := newIntNodeP(nkInt16Lit, p.tok.iNumber, p);
+      setBaseFlags(result, p.tok.base);
+      getTok(p);
+    end;
+    tkInt32Lit: begin
+      result := newIntNodeP(nkInt32Lit, p.tok.iNumber, p);
+      setBaseFlags(result, p.tok.base);
+      getTok(p);
+    end;
+    tkInt64Lit: begin
+      result := newIntNodeP(nkInt64Lit, p.tok.iNumber, p);
+      setBaseFlags(result, p.tok.base);
+      getTok(p);
+    end;
+    tkFloatLit: begin
+      result := newFloatNodeP(nkFloatLit, p.tok.fNumber, p);
+      setBaseFlags(result, p.tok.base);
+      getTok(p);
+    end;
+    tkFloat32Lit: begin
+      result := newFloatNodeP(nkFloat32Lit, p.tok.fNumber, p);
+      setBaseFlags(result, p.tok.base);
+      getTok(p);
+    end;
+    tkFloat64Lit: begin
+      result := newFloatNodeP(nkFloat64Lit, p.tok.fNumber, p);
+      setBaseFlags(result, p.tok.base);
+      getTok(p);
+    end;
+    tkStrLit: begin
+      result := newStrNodeP(nkStrLit, p.tok.literal, p);
+      getTok(p);
+    end;
+    tkRStrLit: begin
+      result := newStrNodeP(nkRStrLit, p.tok.literal, p);
+      getTok(p);
+    end;
+    tkTripleStrLit: begin
+      result := newStrNodeP(nkTripleStrLit, p.tok.literal, p);
+      getTok(p);
+    end;
+    tkCallRStrLit: begin
+      result := newNodeP(nkCallStrLit, p);
+      addSon(result, newIdentNodeP(p.tok.ident, p));
+      addSon(result, newStrNodeP(nkRStrLit, p.tok.literal, p));
+      getTok(p);
+    end;
+    tkCallTripleStrLit: begin
+      result := newNodeP(nkCallStrLit, p);
+      addSon(result, newIdentNodeP(p.tok.ident, p));
+      addSon(result, newStrNodeP(nkTripleStrLit, p.tok.literal, p));
+      getTok(p);
+    end;
+    tkCharLit: begin
+      result := newIntNodeP(nkCharLit, ord(p.tok.literal[strStart]), p);
+      getTok(p);
+    end;
+    tkNil: begin
+      result := newNodeP(nkNilLit, p);
+      getTok(p);
+    end;
+    tkParLe: begin // () constructor
+      result := exprColonEqExprList(p, nkPar, nkExprColonExpr, tkParRi,
+                                    tkColon);
+    end;
+    tkCurlyLe: begin // {} constructor
+      result := exprColonEqExprList(p, nkCurly, nkRange, tkCurlyRi, tkDotDot);
+    end;
+    tkBracketLe: begin // [] constructor
+      result := exprColonEqExprList(p, nkBracket, nkExprColonExpr, tkBracketRi,
+                                    tkColon);
+    end;
+    tkCast: result := parseCast(p);
+    tkAddr: result := parseAddr(p);
+    else begin
+      parMessage(p, errExprExpected, tokToStr(p.tok));
+      getTok(p); // we must consume a token here to prevend endless loops!
+      result := nil
+    end
+  end
+end;
+
+function primary(var p: TParser): PNode;
+var
+  a: PNode;
+begin
+  // prefix operator?
+  if (p.tok.tokType = tkNot) or (p.tok.tokType = tkOpr) then begin
+    result := newNodeP(nkPrefix, p);
+    a := newIdentNodeP(p.tok.ident, p);
+    addSon(result, a);
+    getTok(p);
+    optInd(p, a);
+    addSon(result, primary(p));
+    exit
+  end
+  else if p.tok.tokType = tkBind then begin
+    result := newNodeP(nkBind, p);
+    getTok(p);
+    optInd(p, result);
+    addSon(result, primary(p));
+    exit
+  end;
+  result := identOrLiteral(p);
+  while true do begin
+    case p.tok.tokType of
+      tkParLe: begin
+        a := result;
+        result := newNodeP(nkCall, p);
+        addSon(result, a);
+        exprColonEqExprListAux(p, nkExprEqExpr, tkParRi, tkEquals, result);
+      end;
+      tkDot: begin
+        a := result;
+        result := newNodeP(nkDotExpr, p);
+        addSon(result, a);
+        getTok(p); // skip '.'
+        optInd(p, result);
+        addSon(result, parseSymbol(p));
+      end;
+      tkHat: begin
+        a := result;
+        result := newNodeP(nkDerefExpr, p);
+        addSon(result, a);
+        getTok(p);
+      end;
+      tkBracketLe: result := indexExprList(p, result);
+      else break
+    end
+  end
+end;
+
+function lowestExprAux(var p: TParser; out v: PNode; limit: int): PToken;
+var
+  op, nextop: PToken;
+  opPred: int;
+  v2, node, opNode: PNode;
+begin
+  v := primary(p);
+  // expand while operators have priorities higher than 'limit'
+  op := p.tok;
+  opPred := getPrecedence(p.tok);
+  while (opPred > limit) do begin
+    node := newNodeP(nkInfix, p);
+    opNode := newIdentNodeP(op.ident, p);
+    // skip operator:
+    getTok(p);
+    optInd(p, opNode);
+
+    // read sub-expression with higher priority
+    nextop := lowestExprAux(p, v2, opPred);
+    addSon(node, opNode);
+    addSon(node, v);
+    addSon(node, v2);
+    v := node;
+    op := nextop;
+    opPred := getPrecedence(nextop);
+  end;
+  result := op;  // return first untreated operator
+end;
+
+function lowestExpr(var p: TParser): PNode;
+begin
+{@discard} lowestExprAux(p, result, -1);
+end;
+
+function parseIfExpr(var p: TParser): PNode;
+// if (expr) expr else expr
+var
+  branch: PNode;
+begin
+  result := newNodeP(nkIfExpr, p);
+  while true do begin
+    getTok(p); // skip `if`, `elif`
+    branch := newNodeP(nkElifExpr, p);
+    eat(p, tkParLe);
+    addSon(branch, parseExpr(p));
+    eat(p, tkParRi);
+    addSon(branch, parseExpr(p));
+    addSon(result, branch);
+    if p.tok.tokType <> tkElif then break
+  end;
+  branch := newNodeP(nkElseExpr, p);
+  eat(p, tkElse);
+  addSon(branch, parseExpr(p));
+  addSon(result, branch);
+end;
+
+function parsePragma(var p: TParser): PNode;
+var
+  a: PNode;
+begin
+  result := newNodeP(nkPragma, p);
+  getTok(p);
+  optInd(p, result);
+  while (p.tok.tokType <> tkCurlyDotRi) and (p.tok.tokType <> tkCurlyRi)
+  and (p.tok.tokType <> tkEof) and (p.tok.tokType <> tkSad) do begin
+    a := exprColonEqExpr(p, nkExprColonExpr, tkColon);
+    addSon(result, a);
+    if p.tok.tokType = tkComma then begin
+      getTok(p);
+      optInd(p, a)
+    end
+  end;
+  optSad(p);
+  if (p.tok.tokType = tkCurlyDotRi) or (p.tok.tokType = tkCurlyRi) then
+    getTok(p)
+  else
+    parMessage(p, errTokenExpected, '.}');
+end;
+
+function identVis(var p: TParser): PNode; // identifier with visability
+var
+  a: PNode;
+begin
+  a := parseSymbol(p);
+  if p.tok.tokType = tkOpr then begin
+    result := newNodeP(nkPostfix, p);
+    addSon(result, newIdentNodeP(p.tok.ident, p));
+    addSon(result, a);
+    getTok(p);
+  end
+  else
+    result := a;
+end;
+
+function identWithPragma(var p: TParser): PNode;
+var
+  a: PNode;
+begin
+  a := identVis(p);
+  if p.tok.tokType = tkCurlyDotLe then begin
+    result := newNodeP(nkPragmaExpr, p);
+    addSon(result, a);
+    addSon(result, parsePragma(p));
+  end
+  else
+    result := a
+end;
+
+type
+  TDeclaredIdentFlag = (
+    withPragma,                // identifier may have pragma
+    withBothOptional           // both ':' and '=' parts are optional
+  );
+  TDeclaredIdentFlags = set of TDeclaredIdentFlag;
+
+function parseIdentColonEquals(var p: TParser;
+                               flags: TDeclaredIdentFlags): PNode;
+var
+  a: PNode;
+begin
+  result := newNodeP(nkIdentDefs, p);
+  while true do begin
+    case p.tok.tokType of
+      tkSymbol, tkAccent: begin
+        if withPragma in flags then
+          a := identWithPragma(p)
+        else
+          a := parseSymbol(p);
+        if a = nil then exit;
+      end;
+      else break;
+    end;
+    addSon(result, a);
+    if p.tok.tokType <> tkComma then break;
+    getTok(p);
+    optInd(p, a)
+  end;
+  if p.tok.tokType = tkColon then begin
+    getTok(p); optInd(p, result);
+    addSon(result, parseTypeDesc(p));
+  end
+  else begin
+    addSon(result, nil);
+    if (p.tok.tokType <> tkEquals) and not (withBothOptional in flags) then
+      parMessage(p, errColonOrEqualsExpected, tokToStr(p.tok))
+  end;
+  if p.tok.tokType = tkEquals then begin
+    getTok(p); optInd(p, result);
+    addSon(result, parseExpr(p));
+  end
+  else
+    addSon(result, nil);
+end;
+
+function parseTuple(var p: TParser): PNode;
+var
+  a: PNode;
+begin
+  result := newNodeP(nkTupleTy, p);
+  getTok(p);
+  eat(p, tkBracketLe);
+  optInd(p, result);
+  while (p.tok.tokType = tkSymbol) or (p.tok.tokType = tkAccent) do begin
+    a := parseIdentColonEquals(p, {@set}[]);
+    addSon(result, a);        
+    if p.tok.tokType <> tkComma then break;
+    getTok(p);
+    optInd(p, a)
+  end;
+  optSad(p);
+  eat(p, tkBracketRi);
+end;
+
+function parseParamList(var p: TParser): PNode;
+var
+  a: PNode;
+begin
+  result := newNodeP(nkFormalParams, p);
+  addSon(result, nil); // return type
+  if p.tok.tokType = tkParLe then begin
+    getTok(p);
+    optInd(p, result);
+    while true do begin
+      case p.tok.tokType of
+        tkSymbol, tkAccent: a := parseIdentColonEquals(p, {@set}[]);
+        tkParRi: break;
+        else begin parMessage(p, errTokenExpected, ')'+''); break; end;
+      end;
+      addSon(result, a);
+      if p.tok.tokType <> tkComma then break;
+      getTok(p);
+      optInd(p, a)
+    end;
+    optSad(p);
+    eat(p, tkParRi);
+  end;
+  if p.tok.tokType = tkColon then begin
+    getTok(p);
+    optInd(p, result);
+    result.sons[0] := parseTypeDesc(p)
+  end
+end;
+
+function parseProcExpr(var p: TParser; isExpr: bool): PNode;
+// either a proc type or a anonymous proc
+var
+  pragmas, params: PNode;
+  info: TLineInfo;
+begin
+  info := parLineInfo(p);
+  getTok(p);
+  params := parseParamList(p);
+  if p.tok.tokType = tkCurlyDotLe then pragmas := parsePragma(p)
+  else pragmas := nil;
+  if (p.tok.tokType = tkCurlyLe) and isExpr then begin
+    result := newNodeI(nkLambda, info);
+    addSon(result, nil); // no name part
+    addSon(result, nil); // no generic parameters
+    addSon(result, params);
+    addSon(result, pragmas);
+    //getTok(p); skipComment(p, result);
+    addSon(result, parseStmt(p));
+  end
+  else begin
+    result := newNodeI(nkProcTy, info);
+    addSon(result, params);
+    addSon(result, pragmas);
+  end
+end;
+
+function parseTypeDescKAux(var p: TParser; kind: TNodeKind): PNode;
+begin
+  result := newNodeP(kind, p);
+  getTok(p);
+  optInd(p, result);
+  addSon(result, parseTypeDesc(p));
+end;
+
+function parseExpr(var p: TParser): PNode;
+(*
+expr ::= lowestExpr
+     | 'if' expr ':' expr ('elif' expr ':' expr)* 'else' ':' expr
+     | 'var' expr
+     | 'ref' expr
+     | 'ptr' expr
+     | 'type' expr
+     | 'tuple' tupleDesc
+     | 'proc' paramList [pragma] ['=' stmt] 
+*)
+begin
+  case p.tok.toktype of
+    tkVar:   result := parseTypeDescKAux(p, nkVarTy);
+    tkRef:   result := parseTypeDescKAux(p, nkRefTy);
+    tkPtr:   result := parseTypeDescKAux(p, nkPtrTy);
+    tkType:  result := parseTypeDescKAux(p, nkTypeOfExpr);
+    tkTuple: result := parseTuple(p);
+    tkProc:  result := parseProcExpr(p, true);
+    tkIf:    result := parseIfExpr(p);
+    else     result := lowestExpr(p);
+  end
+end;
+
+function parseTypeDesc(var p: TParser): PNode;
+begin
+  if p.tok.toktype = tkProc then result := parseProcExpr(p, false)
+  else result := parseExpr(p);
+end;
+
+// ---------------------- statement parser ------------------------------------
+function isExprStart(const p: TParser): bool;
+begin
+  case p.tok.tokType of
+    tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, tkProc, tkBind,
+    tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit,
+    tkVar, tkRef, tkPtr, tkTuple, tkType: result := true;
+    else result := false;
+  end;
+end;
+
+function parseExprStmt(var p: TParser): PNode;
+var
+  a, b, e: PNode;
+begin
+  a := lowestExpr(p);
+  if p.tok.tokType = tkEquals then begin
+    getTok(p);
+    optInd(p, result);
+    b := parseExpr(p);
+    result := newNodeI(nkAsgn, a.info);
+    addSon(result, a);
+    addSon(result, b);
+  end
+  else begin
+    result := newNodeP(nkCommand, p);
+    result.info := a.info;
+    addSon(result, a);
+    while true do begin
+      if not isExprStart(p) then break;
+      e := parseExpr(p);
+      addSon(result, e);
+      if p.tok.tokType <> tkComma then break;
+      getTok(p);
+      optInd(p, a);
+    end;
+    if sonsLen(result) <= 1 then result := a
+    else a := result;
+    if p.tok.tokType = tkCurlyLe then begin // macro statement
+      result := newNodeP(nkMacroStmt, p);
+      result.info := a.info;
+      addSon(result, a);
+      getTok(p);
+      skipComment(p, result);
+      if (p.tok.tokType = tkInd)
+           or not (p.tok.TokType in [tkOf, tkElif, tkElse, tkExcept]) then
+        addSon(result, parseStmt(p));
+      while true do begin
+        if p.tok.tokType = tkSad then getTok(p);
+        case p.tok.tokType of
+          tkOf: begin
+            b := newNodeP(nkOfBranch, p);
+            exprListAux(p, nkRange, tkCurlyLe, tkDotDot, b);
+          end;
+          tkElif: begin
+            b := newNodeP(nkElifBranch, p);
+            getTok(p);
+            optInd(p, b);
+            addSon(b, parseExpr(p));
+            eat(p, tkCurlyLe);
+          end;
+          tkExcept: begin
+            b := newNodeP(nkExceptBranch, p);
+            qualifiedIdentListAux(p, tkCurlyLe, b);
+            skipComment(p, b);
+          end;
+          tkElse: begin
+            b := newNodeP(nkElse, p);
+            getTok(p);
+            eat(p, tkCurlyLe);
+          end;
+          else break;
+        end;
+        addSon(b, parseStmt(p));
+        eat(p, tkCurlyRi);
+        addSon(result, b);
+        if b.kind = nkElse then break;
+      end;
+      eat(p, tkCurlyRi);
+    end
+  end
+end;
+
+function parseImportStmt(var p: TParser): PNode;
+var
+  a: PNode;
+begin
+  result := newNodeP(nkImportStmt, p);
+  getTok(p); // skip `import`
+  optInd(p, result);
+  while true do begin
+    case p.tok.tokType of
+      tkEof, tkSad, tkDed: break;
+      tkSymbol, tkAccent: a := parseSymbol(p);
+      tkRStrLit: begin
+        a := newStrNodeP(nkRStrLit, p.tok.literal, p);
+        getTok(p)
+      end;
+      tkStrLit: begin
+        a := newStrNodeP(nkStrLit, p.tok.literal, p);
+        getTok(p);
+      end;
+      tkTripleStrLit: begin
+        a := newStrNodeP(nkTripleStrLit, p.tok.literal, p);
+        getTok(p)
+      end;
+      else begin
+        parMessage(p, errIdentifierExpected, tokToStr(p.tok));
+        break
+      end
+    end;
+    addSon(result, a);
+    if p.tok.tokType <> tkComma then break;
+    getTok(p);
+    optInd(p, a)
+  end;
+end;
+
+function parseIncludeStmt(var p: TParser): PNode;
+var
+  a: PNode;
+begin
+  result := newNodeP(nkIncludeStmt, p);
+  getTok(p); // skip `include`
+  optInd(p, result);
+  while true do begin
+    case p.tok.tokType of
+      tkEof, tkSad, tkDed: break;
+      tkSymbol, tkAccent:   a := parseSymbol(p);
+      tkRStrLit:  begin
+        a := newStrNodeP(nkRStrLit, p.tok.literal, p);
+        getTok(p)
+      end;
+      tkStrLit: begin
+        a := newStrNodeP(nkStrLit, p.tok.literal, p);
+        getTok(p);
+      end;
+      tkTripleStrLit: begin
+        a := newStrNodeP(nkTripleStrLit, p.tok.literal, p);
+        getTok(p)
+      end;
+      else begin
+        parMessage(p, errIdentifierExpected, tokToStr(p.tok));
+        break
+      end;
+    end;
+    addSon(result, a);
+    if p.tok.tokType <> tkComma then break;
+    getTok(p);
+    optInd(p, a)
+  end;
+end;
+
+function parseFromStmt(var p: TParser): PNode;
+var
+  a: PNode;
+begin
+  result := newNodeP(nkFromStmt, p);
+  getTok(p); // skip `from`
+  optInd(p, result);
+  case p.tok.tokType of
+    tkSymbol, tkAccent: a := parseSymbol(p);
+    tkRStrLit:  begin
+      a := newStrNodeP(nkRStrLit, p.tok.literal, p);
+      getTok(p)
+    end;
+    tkStrLit: begin
+      a := newStrNodeP(nkStrLit, p.tok.literal, p);
+      getTok(p);
+    end;
+    tkTripleStrLit: begin
+      a := newStrNodeP(nkTripleStrLit, p.tok.literal, p);
+      getTok(p)
+    end;
+    else begin
+      parMessage(p, errIdentifierExpected, tokToStr(p.tok)); exit
+    end
+  end;
+  addSon(result, a);
+  //optInd(p, a);
+  eat(p, tkImport);
+  optInd(p, result);
+  while true do begin
+    case p.tok.tokType of
+      tkEof, tkSad, tkDed: break;
+      tkSymbol, tkAccent: a := parseSymbol(p);
+      else begin
+        parMessage(p, errIdentifierExpected, tokToStr(p.tok));
+        break
+      end;
+    end;
+    //optInd(p, a);
+    addSon(result, a);
+    if p.tok.tokType <> tkComma then break;
+    getTok(p);
+    optInd(p, a)
+  end;
+end;
+
+function parseReturnOrRaise(var p: TParser; kind: TNodeKind): PNode;
+begin
+  result := newNodeP(kind, p);
+  getTok(p);
+  optInd(p, result);
+  case p.tok.tokType of
+    tkEof, tkSad, tkDed: addSon(result, nil);
+    else addSon(result, parseExpr(p));
+  end;
+end;
+
+function parseYieldOrDiscard(var p: TParser; kind: TNodeKind): PNode;
+begin
+  result := newNodeP(kind, p);
+  getTok(p);
+  optInd(p, result);
+  addSon(result, parseExpr(p));
+end;
+
+function parseBreakOrContinue(var p: TParser; kind: TNodeKind): PNode;
+begin
+  result := newNodeP(kind, p);
+  getTok(p);
+  optInd(p, result);
+  case p.tok.tokType of
+    tkEof, tkSad, tkDed: addSon(result, nil);
+    else addSon(result, parseSymbol(p));
+  end;
+end;
+
+function parseIfOrWhen(var p: TParser; kind: TNodeKind): PNode;
+var
+  branch: PNode;
+begin
+  result := newNodeP(kind, p);
+  while true do begin
+    getTok(p); // skip `if`, `when`, `elif`
+    branch := newNodeP(nkElifBranch, p);
+    optInd(p, branch);
+    eat(p, tkParLe);
+    addSon(branch, parseExpr(p));
+    eat(p, tkParRi);
+    skipComment(p, branch);
+    addSon(branch, parseStmt(p));
+    skipComment(p, branch);
+    addSon(result, branch);
+    if p.tok.tokType <> tkElif then break
+  end;
+  if p.tok.tokType = tkElse then begin
+    branch := newNodeP(nkElse, p);
+    eat(p, tkElse);
+    skipComment(p, branch);
+    addSon(branch, parseStmt(p));
+    addSon(result, branch);
+  end
+end;
+
+function parseWhile(var p: TParser): PNode;
+begin
+  result := newNodeP(nkWhileStmt, p);
+  getTok(p);
+  optInd(p, result);
+  eat(p, tkParLe);
+  addSon(result, parseExpr(p));
+  eat(p, tkParRi);
+  skipComment(p, result);
+  addSon(result, parseStmt(p));
+end;
+
+function parseCase(var p: TParser): PNode;
+var
+  b: PNode;
+  inElif: bool;
+begin
+  result := newNodeP(nkCaseStmt, p);
+  getTok(p);
+  eat(p, tkParLe);
+  addSon(result, parseExpr(p));
+  eat(p, tkParRi);
+  skipComment(p, result);
+  inElif := false;
+  while true do begin
+    if p.tok.tokType = tkSad then getTok(p);
+    case p.tok.tokType of
+      tkOf: begin
+        if inElif then break;
+        b := newNodeP(nkOfBranch, p);
+        exprListAux(p, nkRange, tkColon, tkDotDot, b);
+      end;
+      tkElif: begin
+        inElif := true;
+        b := newNodeP(nkElifBranch, p);
+        getTok(p);
+        optInd(p, b);
+        addSon(b, parseExpr(p));
+        eat(p, tkColon);
+      end;
+      tkElse: begin
+        b := newNodeP(nkElse, p);
+        getTok(p);
+        eat(p, tkColon);
+      end;
+      else break;
+    end;
+    skipComment(p, b);
+    addSon(b, parseStmt(p));
+    addSon(result, b);
+    if b.kind = nkElse then break;
+  end
+end;
+
+function parseTry(var p: TParser): PNode;
+var
+  b: PNode;
+begin
+  result := newNodeP(nkTryStmt, p);
+  getTok(p);
+  eat(p, tkColon);
+  skipComment(p, result);
+  addSon(result, parseStmt(p));
+  b := nil;
+  while true do begin
+    if p.tok.tokType = tkSad then getTok(p);
+    case p.tok.tokType of
+      tkExcept: begin
+        b := newNodeP(nkExceptBranch, p);
+        qualifiedIdentListAux(p, tkColon, b);
+      end;
+      tkFinally: begin
+        b := newNodeP(nkFinally, p);
+        getTok(p);
+        eat(p, tkColon);
+      end;
+      else break;
+    end;
+    skipComment(p, b);
+    addSon(b, parseStmt(p));
+    addSon(result, b);
+    if b.kind = nkFinally then break;
+  end;
+  if b = nil then parMessage(p, errTokenExpected, 'except');
+end;
+
+function parseFor(var p: TParser): PNode;
+var
+  a: PNode;
+begin
+  result := newNodeP(nkForStmt, p);
+  getTok(p);
+  optInd(p, result);
+  a := parseSymbol(p);
+  addSon(result, a);
+  while p.tok.tokType = tkComma do begin
+    getTok(p);
+    optInd(p, a);
+    a := parseSymbol(p);
+    addSon(result, a);    
+  end;
+  eat(p, tkIn);
+  addSon(result, exprColonEqExpr(p, nkRange, tkDotDot));
+  eat(p, tkColon);
+  skipComment(p, result);
+  addSon(result, parseStmt(p))
+end;
+
+function parseBlock(var p: TParser): PNode;
+begin
+  result := newNodeP(nkBlockStmt, p);
+  getTok(p);
+  optInd(p, result);
+  case p.tok.tokType of
+    tkEof, tkSad, tkDed, tkColon: addSon(result, nil);
+    else addSon(result, parseSymbol(p));
+  end;
+  eat(p, tkColon);
+  skipComment(p, result);
+  addSon(result, parseStmt(p));
+end;
+
+function parseAsm(var p: TParser): PNode;
+begin
+  result := newNodeP(nkAsmStmt, p);
+  getTok(p);
+  optInd(p, result);
+  if p.tok.tokType = tkCurlyDotLe then addSon(result, parsePragma(p))
+  else addSon(result, nil);
+  case p.tok.tokType of
+    tkStrLit: addSon(result, newStrNodeP(nkStrLit, p.tok.literal, p));
+    tkRStrLit: addSon(result, newStrNodeP(nkRStrLit, p.tok.literal, p));
+    tkTripleStrLit:
+      addSon(result, newStrNodeP(nkTripleStrLit, p.tok.literal, p));
+    else begin
+      parMessage(p, errStringLiteralExpected);
+      addSon(result, nil); exit
+    end;
+  end;
+  getTok(p);
+end;
+
+function parseGenericParamList(var p: TParser): PNode;
+var
+  a: PNode;
+begin
+  result := newNodeP(nkGenericParams, p);
+  getTok(p);
+  optInd(p, result);
+  while (p.tok.tokType = tkSymbol) or (p.tok.tokType = tkAccent) do begin
+    a := parseIdentColonEquals(p, {@set}[withBothOptional]);
+    addSon(result, a);
+    if p.tok.tokType <> tkComma then break;
+    getTok(p);
+    optInd(p, a)
+  end;
+  optSad(p);
+  eat(p, tkBracketRi);
+end;
+
+function parseRoutine(var p: TParser; kind: TNodeKind): PNode;
+begin
+  result := newNodeP(kind, p);
+  getTok(p);
+  optInd(p, result);
+  addSon(result, identVis(p));
+  if p.tok.tokType = tkBracketLe then addSon(result, parseGenericParamList(p))
+  else addSon(result, nil);
+  addSon(result, parseParamList(p));
+  if p.tok.tokType = tkCurlyDotLe then addSon(result, parsePragma(p))
+  else addSon(result, nil);
+  if p.tok.tokType = tkEquals then begin
+    getTok(p); skipComment(p, result);
+    addSon(result, parseStmt(p));
+  end
+  else
+    addSon(result, nil);
+  indAndComment(p, result); // XXX: document this in the grammar!
+end;
+
+function newCommentStmt(var p: TParser): PNode;
+begin
+  result := newNodeP(nkCommentStmt, p);
+  result.info.line := result.info.line - int16(1);
+end;
+
+type
+  TDefParser = function (var p: TParser): PNode;
+
+function parseSection(var p: TParser; kind: TNodeKind;
+                      defparser: TDefParser): PNode;
+var
+  a: PNode;
+begin
+  result := newNodeP(kind, p);
+  getTok(p);
+  skipComment(p, result);
+  case p.tok.tokType of
+    tkInd: begin
+      pushInd(p.lex^, p.tok.indent);
+      getTok(p); skipComment(p, result);
+      while true do begin
+        case p.tok.tokType of
+          tkSad: getTok(p);
+          tkSymbol, tkAccent: begin
+            a := defparser(p);
+            skipComment(p, a);
+            addSon(result, a);
+          end;
+          tkDed: begin getTok(p); break end;
+          tkEof: break; // BUGFIX
+          tkComment: begin
+            a := newCommentStmt(p);
+            skipComment(p, a);
+            addSon(result, a);
+          end;
+          else begin
+            parMessage(p, errIdentifierExpected, tokToStr(p.tok));
+            break
+          end
+        end
+      end;
+      popInd(p.lex^);
+    end;
+    tkSymbol, tkAccent, tkParLe: begin
+      // tkParLe is allowed for ``var (x, y) = ...`` tuple parsing
+      addSon(result, defparser(p));
+    end
+    else parMessage(p, errIdentifierExpected, tokToStr(p.tok));
+  end
+end;
+
+function parseConstant(var p: TParser): PNode;
+begin
+  result := newNodeP(nkConstDef, p);
+  addSon(result, identWithPragma(p));
+  if p.tok.tokType = tkColon then begin
+    getTok(p); optInd(p, result);
+    addSon(result, parseTypeDesc(p));
+  end
+  else
+    addSon(result, nil);
+  eat(p, tkEquals);
+  optInd(p, result);
+  addSon(result, parseExpr(p));
+  indAndComment(p, result); // XXX: special extension!
+end;
+
+function parseEnum(var p: TParser): PNode;
+var
+  a, b: PNode;
+begin
+  result := newNodeP(nkEnumTy, p);
+  a := nil;
+  getTok(p);
+  optInd(p, result);
+  if p.tok.tokType = tkOf then begin
+    a := newNodeP(nkOfInherit, p);
+    getTok(p); optInd(p, a);
+    addSon(a, parseTypeDesc(p));
+    addSon(result, a)
+  end
+  else addSon(result, nil);
+
+  while true do begin
+    case p.tok.tokType of
+      tkEof, tkSad, tkDed: break;
+      else a := parseSymbol(p);
+    end;
+    optInd(p, a);
+    if p.tok.tokType = tkEquals then begin
+      getTok(p);
+      optInd(p, a);
+      b := a;
+      a := newNodeP(nkEnumFieldDef, p);
+      addSon(a, b);
+      addSon(a, parseExpr(p));
+      skipComment(p, a);
+    end;
+    if p.tok.tokType = tkComma then begin
+      getTok(p);
+      optInd(p, a)
+    end;
+    addSon(result, a);
+  end
+end;
+
+function parseObjectPart(var p: TParser): PNode; forward;
+
+function parseObjectWhen(var p: TParser): PNode;
+var
+  branch: PNode;
+begin
+  result := newNodeP(nkRecWhen, p);
+  while true do begin
+    getTok(p); // skip `when`, `elif`
+    branch := newNodeP(nkElifBranch, p);
+    optInd(p, branch);
+    addSon(branch, parseExpr(p));
+    eat(p, tkColon);
+    skipComment(p, branch);
+    addSon(branch, parseObjectPart(p));
+    skipComment(p, branch);
+    addSon(result, branch);
+    if p.tok.tokType <> tkElif then break
+  end;
+  if p.tok.tokType = tkElse then begin
+    branch := newNodeP(nkElse, p);
+    eat(p, tkElse); eat(p, tkColon);
+    skipComment(p, branch);
+    addSon(branch, parseObjectPart(p));
+    addSon(result, branch);
+  end
+end;
+
+function parseObjectCase(var p: TParser): PNode;
+var
+  a, b: PNode;
+begin
+  result := newNodeP(nkRecCase, p);
+  getTok(p);
+  a := newNodeP(nkIdentDefs, p);
+  addSon(a, identWithPragma(p));
+  eat(p, tkColon);
+  addSon(a, parseTypeDesc(p));
+  addSon(a, nil);
+  addSon(result, a);
+  skipComment(p, result);
+  while true do begin
+    if p.tok.tokType = tkSad then getTok(p);
+    case p.tok.tokType of
+      tkOf: begin
+        b := newNodeP(nkOfBranch, p);
+        exprListAux(p, nkRange, tkColon, tkDotDot, b);
+      end;
+      tkElse: begin
+        b := newNodeP(nkElse, p);
+        getTok(p);
+        eat(p, tkColon);
+      end;
+      else break;
+    end;
+    skipComment(p, b);
+    addSon(b, parseObjectPart(p));
+    addSon(result, b);
+    if b.kind = nkElse then break;
+  end
+end;
+
+function parseObjectPart(var p: TParser): PNode;
+begin
+  case p.tok.tokType of
+    tkInd: begin
+      result := newNodeP(nkRecList, p);
+      pushInd(p.lex^, p.tok.indent);
+      getTok(p); skipComment(p, result);
+      while true do begin
+        case p.tok.tokType of
+          tkSad: getTok(p);
+          tkCase, tkWhen, tkSymbol, tkAccent, tkNil: begin
+            addSon(result, parseObjectPart(p));
+          end;
+          tkDed: begin getTok(p); break end;
+          tkEof: break;
+          else begin
+            parMessage(p, errIdentifierExpected, tokToStr(p.tok));
+            break
+          end
+        end
+      end;
+      popInd(p.lex^);
+    end;
+    tkWhen: result := parseObjectWhen(p);
+    tkCase: result := parseObjectCase(p);
+    tkSymbol, tkAccent: begin
+      result := parseIdentColonEquals(p, {@set}[withPragma]);
+      skipComment(p, result);
+    end;
+    tkNil: begin
+      result := newNodeP(nkNilLit, p);
+      getTok(p);
+    end;
+    else result := nil
+  end
+end;
+
+function parseObject(var p: TParser): PNode;
+var
+  a: PNode;
+begin
+  result := newNodeP(nkObjectTy, p);
+  getTok(p);
+  if p.tok.tokType = tkCurlyDotLe then addSon(result, parsePragma(p))
+  else addSon(result, nil);
+  if p.tok.tokType = tkOf then begin
+    a := newNodeP(nkOfInherit, p);
+    getTok(p);
+    addSon(a, parseTypeDesc(p));
+    addSon(result, a);
+  end
+  else addSon(result, nil);
+  skipComment(p, result);
+  addSon(result, parseObjectPart(p));
+end;
+
+function parseDistinct(var p: TParser): PNode;
+begin
+  result := newNodeP(nkDistinctTy, p);
+  getTok(p);
+  optInd(p, result);
+  addSon(result, parseTypeDesc(p));
+end;
+
+function parseTypeDef(var p: TParser): PNode;
+var
+  a: PNode;
+begin
+  result := newNodeP(nkTypeDef, p);
+  addSon(result, identWithPragma(p));
+  if p.tok.tokType = tkBracketLe then addSon(result, parseGenericParamList(p))
+  else addSon(result, nil);
+  if p.tok.tokType = tkEquals then begin
+    getTok(p); optInd(p, result);
+    case p.tok.tokType of
+      tkObject: a := parseObject(p);
+      tkEnum: a := parseEnum(p);
+      tkDistinct: a := parseDistinct(p);
+      else a := parseTypeDesc(p);
+    end;
+    addSon(result, a);
+  end
+  else
+    addSon(result, nil);
+  indAndComment(p, result); // special extension!
+end;
+
+function parseVarTuple(var p: TParser): PNode;
+var
+  a: PNode;
+begin
+  result := newNodeP(nkVarTuple, p);
+  getTok(p); // skip '('
+  optInd(p, result);
+  while (p.tok.tokType = tkSymbol) or (p.tok.tokType = tkAccent) do begin
+    a := identWithPragma(p);
+    addSon(result, a);
+    if p.tok.tokType <> tkComma then break;
+    getTok(p);
+    optInd(p, a)
+  end;
+  addSon(result, nil); // no type desc
+  optSad(p);
+  eat(p, tkParRi);
+  eat(p, tkEquals);
+  optInd(p, result);
+  addSon(result, parseExpr(p));
+end;
+
+function parseVariable(var p: TParser): PNode;
+begin
+  if p.tok.tokType = tkParLe then 
+    result := parseVarTuple(p)
+  else
+    result := parseIdentColonEquals(p, {@set}[withPragma]);
+  indAndComment(p, result); // special extension!
+end;
+
+function simpleStmt(var p: TParser): PNode;
+begin
+  case p.tok.tokType of
+    tkReturn:   result := parseReturnOrRaise(p, nkReturnStmt);
+    tkRaise:    result := parseReturnOrRaise(p, nkRaiseStmt);
+    tkYield:    result := parseYieldOrDiscard(p, nkYieldStmt);
+    tkDiscard:  result := parseYieldOrDiscard(p, nkDiscardStmt);
+    tkBreak:    result := parseBreakOrContinue(p, nkBreakStmt);
+    tkContinue: result := parseBreakOrContinue(p, nkContinueStmt);
+    tkCurlyDotLe: result := parsePragma(p);
+    tkImport: result := parseImportStmt(p);
+    tkFrom: result := parseFromStmt(p);
+    tkInclude: result := parseIncludeStmt(p);
+    tkComment: result := newCommentStmt(p);
+    else begin
+      if isExprStart(p) then 
+        result := parseExprStmt(p)
+      else 
+        result := nil;
+    end
+  end;
+  if result <> nil then
+    skipComment(p, result);
+end;
+
+function complexOrSimpleStmt(var p: TParser): PNode;
+begin
+  case p.tok.tokType of
+    tkIf:        result := parseIfOrWhen(p, nkIfStmt);
+    tkWhile:     result := parseWhile(p);
+    tkCase:      result := parseCase(p);
+    tkTry:       result := parseTry(p);
+    tkFor:       result := parseFor(p);
+    tkBlock:     result := parseBlock(p);
+    tkAsm:       result := parseAsm(p);
+    tkProc:      result := parseRoutine(p, nkProcDef);
+    tkMethod:    result := parseRoutine(p, nkMethodDef);
+    tkIterator:  result := parseRoutine(p, nkIteratorDef);
+    tkMacro:     result := parseRoutine(p, nkMacroDef);
+    tkTemplate:  result := parseRoutine(p, nkTemplateDef);
+    tkConverter: result := parseRoutine(p, nkConverterDef);
+    tkType:      result := parseSection(p, nkTypeSection, parseTypeDef);
+    tkConst:     result := parseSection(p, nkConstSection, parseConstant);
+    tkWhen:      result := parseIfOrWhen(p, nkWhenStmt);
+    tkVar:       result := parseSection(p, nkVarSection, parseVariable);
+    else         result := simpleStmt(p);
+  end
+end;
+
+function parseStmt(var p: TParser): PNode;
+var
+  a: PNode;
+begin
+  if p.tok.tokType = tkInd then begin
+    result := newNodeP(nkStmtList, p);
+    pushInd(p.lex^, p.tok.indent);
+    getTok(p);
+    while true do begin
+      case p.tok.tokType of
+        tkSad: getTok(p);
+        tkEof: break;
+        tkDed: begin getTok(p); break end;
+        else begin
+          a := complexOrSimpleStmt(p);
+          if a = nil then break;
+          addSon(result, a);
+        end
+      end
+    end;
+    popInd(p.lex^);
+  end
+  else begin
+    // the case statement is only needed for better error messages:
+    case p.tok.tokType of
+      tkIf, tkWhile, tkCase, tkTry, tkFor, tkBlock, tkAsm,
+      tkProc, tkIterator, tkMacro, tkType, tkConst, tkWhen, tkVar: begin
+        parMessage(p, errComplexStmtRequiresInd);
+        result := nil
+      end
+      else begin
+        result := simpleStmt(p);
+        if result = nil then parMessage(p, errExprExpected, tokToStr(p.tok));
+        if p.tok.tokType = tkSad then getTok(p);
+      end
+    end
+  end
+end;
+
+function parseAll(var p: TParser): PNode;
+var
+  a: PNode;
+begin
+  result := newNodeP(nkStmtList, p);
+  while true do begin
+    case p.tok.tokType of
+      tkSad: getTok(p);
+      tkDed, tkInd: parMessage(p, errInvalidIndentation);
+      tkEof: break;
+      else begin
+        a := complexOrSimpleStmt(p);
+        if a = nil then parMessage(p, errExprExpected, tokToStr(p.tok));
+        addSon(result, a);
+      end
+    end
+  end
+end;
+
+function parseTopLevelStmt(var p: TParser): PNode;
+begin
+  result := nil;
+  while true do begin
+    case p.tok.tokType of
+      tkSad: getTok(p);
+      tkDed, tkInd: begin
+        parMessage(p, errInvalidIndentation);
+        break;
+      end;
+      tkEof: break;
+      else begin
+        result := complexOrSimpleStmt(p);
+        if result = nil then parMessage(p, errExprExpected, tokToStr(p.tok));
+        break
+      end
+    end
+  end
+end;
+
+end.
diff --git a/nim/platform.pas b/nim/platform.pas
index 9f8d30f60..c2fa711b9 100755
--- a/nim/platform.pas
+++ b/nim/platform.pas
@@ -1,7 +1,7 @@
 //
 //
 //           The Nimrod Compiler
-//        (c) Copyright 2008 Andreas Rumpf
+//        (c) Copyright 2009 Andreas Rumpf
 //
 //    See the file "copying.txt", included in this
 //    distribution, for details about the copyright.
@@ -59,9 +59,8 @@ type
   TInfoOS = record{@tuple}
     name: string;
     parDir: string;
-    dllExt: string;
+    dllFrmt: string;
     altDirSep: string;
-    dllPrefix: string;
     objExt: string;
     newLine: string;
     pathSep: string;
@@ -77,9 +76,8 @@ const
   (
     name: 'DOS';
     parDir: '..';
-    dllExt: '.dll';
+    dllFrmt: '$1.dll';
     altDirSep: '/'+'';
-    dllPrefix: '';
     objExt: '.obj';
     newLine: #13#10;
     pathSep: ';'+'';
@@ -93,9 +91,8 @@ const
   (
     name: 'Windows';
     parDir: '..';
-    dllExt: '.dll';
+    dllFrmt: '$1.dll';
     altDirSep: '/'+'';
-    dllPrefix: '';
     objExt: '.obj';
     newLine: #13#10;
     pathSep: ';'+'';
@@ -109,9 +106,8 @@ const
   (
     name: 'OS2';
     parDir: '..';
-    dllExt: '.dll';
+    dllFrmt: '$1.dll';
     altDirSep: '/'+'';
-    dllPrefix: '';
     objExt: '.obj';
     newLine: #13#10;
     pathSep: ';'+'';
@@ -125,9 +121,8 @@ const
   (
     name: 'Linux';
     parDir: '..';
-    dllExt: '.so';
+    dllFrmt: 'lib$1.so';
     altDirSep: '/'+'';
-    dllPrefix: 'lib';
     objExt: '.o';
     newLine: #10+'';
     pathSep: ':'+'';
@@ -141,9 +136,8 @@ const
   (
     name: 'MorphOS';
     parDir: '..';
-    dllExt: '.so';
+    dllFrmt: 'lib$1.so';
     altDirSep: '/'+'';
-    dllPrefix: 'lib';
     objExt: '.o';
     newLine: #10+'';
     pathSep: ':'+'';
@@ -157,9 +151,8 @@ const
   (
     name: 'SkyOS';
     parDir: '..';
-    dllExt: '.so';
+    dllFrmt: 'lib$1.so';
     altDirSep: '/'+'';
-    dllPrefix: 'lib';
     objExt: '.o';
     newLine: #10+'';
     pathSep: ':'+'';
@@ -173,9 +166,8 @@ const
   (
     name: 'Solaris';
     parDir: '..';
-    dllExt: '.so';
+    dllFrmt: 'lib$1.so';
     altDirSep: '/'+'';
-    dllPrefix: 'lib';
     objExt: '.o';
     newLine: #10+'';
     pathSep: ':'+'';
@@ -189,9 +181,8 @@ const
   (
     name: 'Irix';
     parDir: '..';
-    dllExt: '.so';
+    dllFrmt: 'lib$1.so';
     altDirSep: '/'+'';
-    dllPrefix: 'lib';
     objExt: '.o';
     newLine: #10+'';
     pathSep: ':'+'';
@@ -205,9 +196,8 @@ const
   (
     name: 'NetBSD';
     parDir: '..';
-    dllExt: '.so';
+    dllFrmt: 'lib$1.so';
     altDirSep: '/'+'';
-    dllPrefix: 'lib';
     objExt: '.o';
     newLine: #10+'';
     pathSep: ':'+'';
@@ -221,9 +211,8 @@ const
   (
     name: 'FreeBSD';
     parDir: '..';
-    dllExt: '.so';
+    dllFrmt: 'lib$1.so';
     altDirSep: '/'+'';
-    dllPrefix: 'lib';
     objExt: '.o';
     newLine: #10+'';
     pathSep: ':'+'';
@@ -237,9 +226,8 @@ const
   (
     name: 'OpenBSD';
     parDir: '..';
-    dllExt: '.so';
+    dllFrmt: 'lib$1.so';
     altDirSep: '/'+'';
-    dllPrefix: 'lib';
     objExt: '.o';
     newLine: #10+'';
     pathSep: ':'+'';
@@ -253,9 +241,8 @@ const
   (
     name: 'AIX';
     parDir: '..';
-    dllExt: '.so';
+    dllFrmt: 'lib$1.so';
     altDirSep: '/'+'';
-    dllPrefix: 'lib';
     objExt: '.o';
     newLine: #10+'';
     pathSep: ':'+'';
@@ -269,9 +256,8 @@ const
   (
     name: 'PalmOS';
     parDir: '..';
-    dllExt: '.so';
+    dllFrmt: 'lib$1.so';
     altDirSep: '/'+'';
-    dllPrefix: 'lib';
     objExt: '.o';
     newLine: #10+'';
     pathSep: ':'+'';
@@ -285,9 +271,8 @@ const
   (
     name: 'QNX';
     parDir: '..';
-    dllExt: '.so';
+    dllFrmt: 'lib$1.so';
     altDirSep: '/'+'';
-    dllPrefix: 'lib';
     objExt: '.o';
     newLine: #10+'';
     pathSep: ':'+'';
@@ -301,9 +286,8 @@ const
   (
     name: 'Amiga';
     parDir: '..';
-    dllExt: '.library';
+    dllFrmt: '$1.library';
     altDirSep: '/'+'';
-    dllPrefix: '';
     objExt: '.o';
     newLine: #10+'';
     pathSep: ':'+'';
@@ -317,9 +301,8 @@ const
   (
     name: 'Atari';
     parDir: '..';
-    dllExt: '.dll';
+    dllFrmt: '$1.dll';
     altDirSep: '/'+'';
-    dllPrefix: '';
     objExt: '.o';
     newLine: #10+'';
     pathSep: ':'+'';
@@ -333,9 +316,8 @@ const
   (
     name: 'Netware';
     parDir: '..';
-    dllExt: '.nlm';
+    dllFrmt: '$1.nlm';
     altDirSep: '/'+'';
-    dllPrefix: '';
     objExt: '';
     newLine: #13#10;
     pathSep: ':'+'';
@@ -349,9 +331,8 @@ const
   (
     name: 'MacOS';
     parDir: '::';
-    dllExt: 'Lib';
+    dllFrmt: '$1Lib';
     altDirSep: ':'+'';
-    dllPrefix: '';
     objExt: '.o';
     newLine: #13+'';
     pathSep: ','+'';
@@ -365,9 +346,8 @@ const
   (
     name: 'MacOSX';
     parDir: '..';
-    dllExt: '.dylib';
+    dllFrmt: 'lib$1.dylib';
     altDirSep: ':'+'';
-    dllPrefix: 'lib';
     objExt: '.o';
     newLine: #10+'';
     pathSep: ':'+'';
@@ -381,9 +361,8 @@ const
   (
     name: 'EcmaScript';
     parDir: '..';
-    dllExt: '.so';
+    dllFrmt: 'lib$1.so';
     altDirSep: '/'+'';
-    dllPrefix: 'lib';
     objExt: '.o';
     newLine: #10+'';
     pathSep: ':'+'';
@@ -397,9 +376,8 @@ const
   (
     name: 'NimrodVM';
     parDir: '..';
-    dllExt: '.so';
+    dllFrmt: 'lib$1.so';
     altDirSep: '/'+'';
-    dllPrefix: 'lib';
     objExt: '.o';
     newLine: #10+'';
     pathSep: ':'+'';
diff --git a/nim/pnimsyn.pas b/nim/pnimsyn.pas
index 724a85a38..bf964fda1 100755
--- a/nim/pnimsyn.pas
+++ b/nim/pnimsyn.pas
@@ -22,7 +22,7 @@ interface
 uses
   nsystem, llstream, scanner, idents, strutils, ast, msgs;
 
-function ParseFile(const filename: string): PNode;
+// function ParseFile(const filename: string): PNode;
 
 type
   TParser = record               // a TParser object represents a module that
@@ -31,10 +31,7 @@ type
     tok: PToken;                 // the current token
   end;
 
-function ParseModule(var p: TParser): PNode;
-// Note: The module's tree must always be valid.
-function parseExpr(var p: TParser): PNode;
-function parseStmt(var p: TParser): PNode;
+function ParseAll(var p: TParser): PNode;
 
 procedure openParser(var p: TParser; const filename: string;
                      inputstream: PLLStream);
@@ -44,21 +41,43 @@ function parseTopLevelStmt(var p: TParser): PNode;
 // implements an iterator. Returns the next top-level statement or nil if end
 // of stream.
 
-implementation
 
-function ParseFile(const filename: string): PNode;
-var
-  p: TParser;
-  f: TBinaryFile;
-begin
-  if not OpenFile(f, filename) then begin
-    rawMessage(errCannotOpenFile, filename);
-    exit
-  end;
-  OpenParser(p, filename, LLStreamOpen(f));
-  result := ParseModule(p);
-  CloseParser(p);
-end;
+// helpers for the other parsers
+function getPrecedence(tok: PToken): int;
+function isOperator(tok: PToken): bool;
+
+procedure getTok(var p: TParser);
+
+procedure parMessage(const p: TParser; const msg: TMsgKind;
+                     const arg: string = '');
+procedure skipComment(var p: TParser; node: PNode);
+
+function newNodeP(kind: TNodeKind; const p: TParser): PNode;
+function newIntNodeP(kind: TNodeKind; const intVal: BiggestInt;
+                     const p: TParser): PNode;
+function newFloatNodeP(kind: TNodeKind; const floatVal: BiggestFloat;
+                       const p: TParser): PNode;
+function newStrNodeP(kind: TNodeKind; const strVal: string;
+                     const p: TParser): PNode;
+function newIdentNodeP(ident: PIdent; const p: TParser): PNode;
+
+procedure expectIdentOrKeyw(const p: TParser);
+procedure ExpectIdent(const p: TParser);
+procedure expectIdentOrOpr(const p: TParser);
+function parLineInfo(const p: TParser): TLineInfo;
+procedure Eat(var p: TParser; TokType: TTokType);
+
+procedure skipInd(var p: TParser);
+procedure optSad(var p: TParser);
+procedure optInd(var p: TParser; n: PNode);
+procedure indAndComment(var p: TParser; n: PNode);
+
+
+function parseSymbol(var p: TParser): PNode;
+function accExpr(var p: TParser): PNode;
+
+
+implementation
 
 procedure initParser(var p: TParser);
 begin
@@ -211,6 +230,9 @@ end;
 
 // ------------------- Expression parsing ------------------------------------
 
+function parseExpr(var p: TParser): PNode; forward;
+function parseStmt(var p: TParser): PNode; forward;
+
 function parseTypeDesc(var p: TParser): PNode; forward;
 function parseParamList(var p: TParser): PNode; forward;
 
@@ -364,43 +386,35 @@ begin
   addSon(result, optExpr(p));
 end;
 
-function parseTypeDescK(var p: TParser): PNode; forward;
-
-function namedTypeOrExpr(var p: TParser): PNode;
+function indexExpr(var p: TParser): PNode;
+// indexExpr ::= '..' [expr] | expr ['=' expr | '..' expr]
 var
   a, b: PNode;
 begin
-  case p.tok.tokType of
-    tkDotDot: result := dotdotExpr(p);
-    tkVar, tkRef, tkPtr, tkProc, tkTuple, tkType: result := parseTypeDescK(p);
-    else begin
-      a := parseExpr(p);
-      case p.tok.tokType of
-        tkEquals: begin
-          result := newNodeP(nkExprEqExpr, p);
-          addSon(result, a);
-          getTok(p);
-          //optInd(p, result);
-          case p.tok.tokType of
-            tkVar, tkRef, tkPtr, tkProc:
-              addSon(result, parseTypeDescK(p));
-            tkDotDot: addSon(result, dotdotExpr(p));
-            else begin
-              b := parseExpr(p);
-              if p.tok.tokType = tkDotDot then
-                b := dotdotExpr(p, b);
-              addSon(result, b);
-            end
-          end
-        end;
-        tkDotDot: result := dotdotExpr(p, a);
-        else result := a
-      end
+  if p.tok.tokType = tkDotDot then
+    result := dotdotExpr(p)
+  else begin
+    a := parseExpr(p);
+    case p.tok.tokType of
+      tkEquals: begin
+        result := newNodeP(nkExprEqExpr, p);
+        addSon(result, a);
+        getTok(p);
+        if p.tok.tokType = tkDotDot then
+          addSon(result, dotdotExpr(p))
+        else begin
+          b := parseExpr(p);
+          if p.tok.tokType = tkDotDot then b := dotdotExpr(p, b);
+          addSon(result, b);
+        end
+      end;
+      tkDotDot: result := dotdotExpr(p, a);
+      else result := a
     end
   end
 end;
 
-function namedTypeOrExprList(var p: TParser; first: PNode): PNode;
+function indexExprList(var p: TParser; first: PNode): PNode;
 var
   a: PNode;
 begin
@@ -410,7 +424,7 @@ begin
   optInd(p, result);
   while (p.tok.tokType <> tkBracketRi) and (p.tok.tokType <> tkEof)
   and (p.tok.tokType <> tkSad) do begin
-    a := namedTypeOrExpr(p);
+    a := indexExpr(p);
     addSon(result, a);
     if p.tok.tokType <> tkComma then break;
     getTok(p);
@@ -464,7 +478,7 @@ begin
     getTok(p);
     optInd(p, result);
     a := result;
-    result := newNodeI(nkQualified, a.info);
+    result := newNodeI(nkDotExpr, a.info);
     addSon(result, a);
     addSon(result, parseSymbol(p));
   end;
@@ -632,7 +646,6 @@ begin
       result := newNodeP(nkNilLit, p);
       getTok(p);
     end;
-
     tkParLe: begin // () constructor
       result := exprColonEqExprList(p, nkPar, nkExprColonExpr, tkParRi,
                                     tkColon);
@@ -698,7 +711,7 @@ begin
         addSon(result, a);
         getTok(p);
       end;
-      tkBracketLe: result := namedTypeOrExprList(p, result);
+      tkBracketLe: result := indexExprList(p, result);
       else break
     end
   end
@@ -712,11 +725,6 @@ var
 begin
   v := primary(p);
   // expand while operators have priorities higher than 'limit'
-  (*if p.tok.tokType = tkInd then begin // BUGFIX: parser allowed too much
-    getTok(p);
-    if getPrecedence(p.tok) < 0 then
-      parMessage(p, errOperatorExpected, tokToStr(p.tok));
-  end; *)
   op := p.tok;
   opPred := getPrecedence(p.tok);
   while (opPred > limit) do begin
@@ -724,8 +732,6 @@ begin
     opNode := newIdentNodeP(op.ident, p);
     // skip operator:
     getTok(p);
-    //skipComment(p, opNode);
-    //skipInd(p);
     optInd(p, opNode);
 
     // read sub-expression with higher priority
@@ -745,8 +751,6 @@ begin
 {@discard} lowestExprAux(p, result, -1);
 end;
 
-function parseLambda(var p: TParser): PNode; forward;
-
 function parseIfExpr(var p: TParser): PNode;
 var
   branch: PNode;
@@ -755,12 +759,9 @@ begin
   while true do begin
     getTok(p); // skip `if`, `elif`
     branch := newNodeP(nkElifExpr, p);
-    //optInd(p, branch);
     addSon(branch, parseExpr(p));
     eat(p, tkColon);
-    //optInd(p, branch);
     addSon(branch, parseExpr(p));
-    //optInd(p, branch);
     addSon(result, branch);
     if p.tok.tokType <> tkElif then break
   end;
@@ -770,16 +771,6 @@ begin
   addSon(result, branch);
 end;
 
-function parseExpr(var p: TParser): PNode;
-begin
-  case p.tok.toktype of
-    tkLambda: result := parseLambda(p);
-    tkIf:     result := parseIfExpr(p);
-    else      result := lowestExpr(p);
-  end
-end;
-
-// ------------------------- pragma parser -----------------------------------
 function parsePragma(var p: TParser): PNode;
 var
   a: PNode;
@@ -803,12 +794,203 @@ begin
     parMessage(p, errTokenExpected, '.}');
 end;
 
+function identVis(var p: TParser): PNode; // identifier with visability
+var
+  a: PNode;
+begin
+  a := parseSymbol(p);
+  if p.tok.tokType = tkOpr then begin
+    result := newNodeP(nkPostfix, p);
+    addSon(result, newIdentNodeP(p.tok.ident, p));
+    addSon(result, a);
+    getTok(p);
+  end
+  else
+    result := a;
+end;
+
+function identWithPragma(var p: TParser): PNode;
+var
+  a: PNode;
+begin
+  a := identVis(p);
+  if p.tok.tokType = tkCurlyDotLe then begin
+    result := newNodeP(nkPragmaExpr, p);
+    addSon(result, a);
+    addSon(result, parsePragma(p));
+  end
+  else
+    result := a
+end;
+
+type
+  TDeclaredIdentFlag = (
+    withPragma,                // identifier may have pragma
+    withBothOptional           // both ':' and '=' parts are optional
+  );
+  TDeclaredIdentFlags = set of TDeclaredIdentFlag;
+
+function parseIdentColonEquals(var p: TParser;
+                               flags: TDeclaredIdentFlags): PNode;
+var
+  a: PNode;
+begin
+  result := newNodeP(nkIdentDefs, p);
+  while true do begin
+    case p.tok.tokType of
+      tkSymbol, tkAccent: begin
+        if withPragma in flags then
+          a := identWithPragma(p)
+        else
+          a := parseSymbol(p);
+        if a = nil then exit;
+      end;
+      else break;
+    end;
+    addSon(result, a);
+    if p.tok.tokType <> tkComma then break;
+    getTok(p);
+    optInd(p, a)
+  end;
+  if p.tok.tokType = tkColon then begin
+    getTok(p); optInd(p, result);
+    addSon(result, parseTypeDesc(p));
+  end
+  else begin
+    addSon(result, nil);
+    if (p.tok.tokType <> tkEquals) and not (withBothOptional in flags) then
+      parMessage(p, errColonOrEqualsExpected, tokToStr(p.tok))
+  end;
+  if p.tok.tokType = tkEquals then begin
+    getTok(p); optInd(p, result);
+    addSon(result, parseExpr(p));
+  end
+  else
+    addSon(result, nil);
+end;
+
+function parseTuple(var p: TParser): PNode;
+var
+  a: PNode;
+begin
+  result := newNodeP(nkTupleTy, p);
+  getTok(p);
+  eat(p, tkBracketLe);
+  optInd(p, result);
+  while (p.tok.tokType = tkSymbol) or (p.tok.tokType = tkAccent) do begin
+    a := parseIdentColonEquals(p, {@set}[]);
+    addSon(result, a);        
+    if p.tok.tokType <> tkComma then break;
+    getTok(p);
+    optInd(p, a)
+  end;
+  optSad(p);
+  eat(p, tkBracketRi);
+end;
+
+function parseParamList(var p: TParser): PNode;
+var
+  a: PNode;
+begin
+  result := newNodeP(nkFormalParams, p);
+  addSon(result, nil); // return type
+  if p.tok.tokType = tkParLe then begin
+    getTok(p);
+    optInd(p, result);
+    while true do begin
+      case p.tok.tokType of
+        tkSymbol, tkAccent: a := parseIdentColonEquals(p, {@set}[]);
+        tkParRi: break;
+        else begin parMessage(p, errTokenExpected, ')'+''); break; end;
+      end;
+      //optInd(p, a);
+      addSon(result, a);
+      if p.tok.tokType <> tkComma then break;
+      getTok(p);
+      optInd(p, a)
+    end;
+    optSad(p);
+    eat(p, tkParRi);
+  end;
+  if p.tok.tokType = tkColon then begin
+    getTok(p);
+    optInd(p, result);
+    result.sons[0] := parseTypeDesc(p)
+  end
+end;
+
+function parseProcExpr(var p: TParser; isExpr: bool): PNode;
+// either a proc type or a anonymous proc
+var
+  pragmas, params: PNode;
+  info: TLineInfo;
+begin
+  info := parLineInfo(p);
+  getTok(p);
+  params := parseParamList(p);
+  if p.tok.tokType = tkCurlyDotLe then pragmas := parsePragma(p)
+  else pragmas := nil;
+  if (p.tok.tokType = tkEquals) and isExpr then begin
+    result := newNodeI(nkLambda, info);
+    addSon(result, nil); // no name part
+    addSon(result, nil); // no generic parameters
+    addSon(result, params);
+    addSon(result, pragmas);
+    getTok(p); skipComment(p, result);
+    addSon(result, parseStmt(p));
+  end
+  else begin
+    result := newNodeI(nkProcTy, info);
+    addSon(result, params);
+    addSon(result, pragmas);
+  end
+end;
+
+function parseTypeDescKAux(var p: TParser; kind: TNodeKind): PNode;
+begin
+  result := newNodeP(kind, p);
+  getTok(p);
+  optInd(p, result);
+  addSon(result, parseTypeDesc(p));
+end;
+
+function parseExpr(var p: TParser): PNode;
+(*
+expr ::= lowestExpr
+     | 'if' expr ':' expr ('elif' expr ':' expr)* 'else' ':' expr
+     | 'var' expr
+     | 'ref' expr
+     | 'ptr' expr
+     | 'type' expr
+     | 'tuple' tupleDesc
+     | 'proc' paramList [pragma] ['=' stmt] 
+*)
+begin
+  case p.tok.toktype of
+    tkVar:   result := parseTypeDescKAux(p, nkVarTy);
+    tkRef:   result := parseTypeDescKAux(p, nkRefTy);
+    tkPtr:   result := parseTypeDescKAux(p, nkPtrTy);
+    tkType:  result := parseTypeDescKAux(p, nkTypeOfExpr);
+    tkTuple: result := parseTuple(p);
+    tkProc:  result := parseProcExpr(p, true);
+    tkIf:    result := parseIfExpr(p);
+    else     result := lowestExpr(p);
+  end
+end;
+
+function parseTypeDesc(var p: TParser): PNode;
+begin
+  if p.tok.toktype = tkProc then result := parseProcExpr(p, false)
+  else result := parseExpr(p);
+end;
+
 // ---------------------- statement parser ------------------------------------
 function isExprStart(const p: TParser): bool;
 begin
   case p.tok.tokType of
-    tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, tkLambda, tkBind,
-    tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit: result := true;
+    tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, tkProc, tkBind,
+    tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit,
+    tkVar, tkRef, tkPtr, tkTuple, tkType: result := true;
     else result := false;
   end;
 end;
@@ -1051,7 +1233,6 @@ begin
     addSon(result, branch);
     if p.tok.tokType <> tkElif then break
   end;
-  //PrintTok(p.tok);
   if p.tok.tokType = tkElse then begin
     branch := newNodeP(nkElse, p);
     eat(p, tkElse); eat(p, tkColon);
@@ -1201,175 +1382,6 @@ begin
   getTok(p);
 end;
 
-function identVis(var p: TParser): PNode; // identifier with visability
-var
-  a: PNode;
-begin
-  a := parseSymbol(p);
-  if p.tok.tokType = tkOpr then begin
-    result := newNodeP(nkPostfix, p);
-    addSon(result, newIdentNodeP(p.tok.ident, p));
-    addSon(result, a);
-    getTok(p);
-  end
-  else
-    result := a;
-end;
-
-function identWithPragma(var p: TParser): PNode;
-var
-  a: PNode;
-begin
-  a := identVis(p);
-  if p.tok.tokType = tkCurlyDotLe then begin
-    result := newNodeP(nkPragmaExpr, p);
-    addSon(result, a);
-    addSon(result, parsePragma(p));
-  end
-  else
-    result := a
-end;
-
-type
-  TDeclaredIdentFlag = (
-    withPragma,                // identifier may have pragma
-    withBothOptional           // both ':' and '=' parts are optional
-  );
-  TDeclaredIdentFlags = set of TDeclaredIdentFlag;
-
-function parseIdentColonEquals(var p: TParser;
-                               flags: TDeclaredIdentFlags): PNode;
-var
-  a: PNode;
-begin
-  result := newNodeP(nkIdentDefs, p);
-  while true do begin
-    case p.tok.tokType of
-      tkSymbol, tkAccent: begin
-        if withPragma in flags then
-          a := identWithPragma(p)
-        else
-          a := parseSymbol(p);
-        if a = nil then exit;
-      end;
-      else break;
-    end;
-    addSon(result, a);
-    if p.tok.tokType <> tkComma then break;
-    getTok(p);
-    optInd(p, a)
-  end;
-  if p.tok.tokType = tkColon then begin
-    getTok(p); optInd(p, result);
-    addSon(result, parseTypeDesc(p));
-  end
-  else begin
-    addSon(result, nil);
-    if (p.tok.tokType <> tkEquals) and not (withBothOptional in flags) then
-      parMessage(p, errColonOrEqualsExpected, tokToStr(p.tok))
-  end;
-  if p.tok.tokType = tkEquals then begin
-    getTok(p); optInd(p, result);
-    addSon(result, parseExpr(p));
-  end
-  else
-    addSon(result, nil);
-end;
-
-function parseParamList(var p: TParser): PNode;
-var
-  a: PNode;
-begin
-  result := newNodeP(nkFormalParams, p);
-  addSon(result, nil); // return type
-  if p.tok.tokType = tkParLe then begin
-    getTok(p);
-    optInd(p, result);
-    while true do begin
-      case p.tok.tokType of
-        tkSymbol, tkAccent: a := parseIdentColonEquals(p, {@set}[]);
-        tkParRi: break;
-        else begin parMessage(p, errTokenExpected, ')'+''); break; end;
-      end;
-      //optInd(p, a);
-      addSon(result, a);
-      if p.tok.tokType <> tkComma then break;
-      getTok(p);
-      optInd(p, a)
-    end;
-    optSad(p);
-    eat(p, tkParRi);
-  end;
-  if p.tok.tokType = tkColon then begin
-    getTok(p);
-    optInd(p, result);
-    result.sons[0] := parseTypeDesc(p)
-  end
-end;
-
-function parseTypeDescKAux(var p: TParser; kind: TNodeKind): PNode;
-begin
-  result := newNodeP(kind, p);
-  getTok(p);
-  optInd(p, result);
-  addSon(result, parseTypeDesc(p));
-end;
-
-function parseTypeDescK(var p: TParser): PNode;
-var
-  a: PNode;
-begin
-  case p.tok.tokType of
-    tkVar: result := parseTypeDescKAux(p, nkVarTy);
-    tkRef: result := parseTypeDescKAux(p, nkRefTy);
-    tkPtr: result := parseTypeDescKAux(p, nkPtrTy);
-    tkType: begin
-      result := newNodeP(nkTypeOfExpr, p);
-      getTok(p);
-      optInd(p, result);
-      addSon(result, parseExpr(p))
-    end;
-    tkProc: begin
-      result := newNodeP(nkProcTy, p);
-      getTok(p);
-      optInd(p, result);
-      addSon(result, parseParamList(p));
-      if p.tok.tokType = tkCurlyDotLe then
-        addSon(result, parsePragma(p))
-      else
-        addSon(result, nil);
-    end;
-    tkTuple: begin
-      result := newNodeP(nkTupleTy, p);
-      getTok(p);
-      eat(p, tkBracketLe);
-      optInd(p, result);
-      while (p.tok.tokType = tkSymbol) or (p.tok.tokType = tkAccent) do begin
-        a := parseIdentColonEquals(p, {@set}[]);
-        addSon(result, a);        
-        if p.tok.tokType <> tkComma then break;
-        getTok(p);
-        optInd(p, a)
-      end;
-      optSad(p);
-      eat(p, tkBracketRi);
-    end;
-    else begin
-      InternalError(parLineInfo(p), 'pnimsyn.parseTypeDescK');
-      result := nil
-    end
-  end
-end;
-
-function parseTypeDesc(var p: TParser): PNode;
-begin
-  case p.tok.tokType of
-    tkVar, tkRef, tkPtr, tkProc, tkType, tkTuple:
-      result := parseTypeDescK(p);
-    else result := primary(p)
-  end
-end;
-
 function parseGenericParamList(var p: TParser): PNode;
 var
   a: PNode;
@@ -1408,26 +1420,6 @@ begin
   indAndComment(p, result); // XXX: document this in the grammar!
 end;
 
-function parseLambda(var p: TParser): PNode;
-begin
-  result := newNodeP(nkLambda, p);
-  getTok(p);
-  optInd(p, result);
-  addSon(result, nil); // no name part
-  addSon(result, nil); // no generic parameters
-  addSon(result, parseParamList(p));
-  if p.tok.tokType = tkCurlyDotLe then addSon(result, parsePragma(p))
-  else addSon(result, nil);
-  if p.tok.tokType = tkEquals then begin
-    getTok(p); skipComment(p, result);
-    addSon(result, parseStmt(p));
-  end
-  else begin
-    addSon(result, nil);
-    parMessage(p, errTokenExpected, tokTypeToStr[tkEquals]);
-  end
-end;
-
 function newCommentStmt(var p: TParser): PNode;
 begin
   result := newNodeP(nkCommentStmt, p);
@@ -1803,7 +1795,7 @@ begin
   end
 end;
 
-function parseModule(var p: TParser): PNode;
+function parseAll(var p: TParser): PNode;
 var
   a: PNode;
 begin
diff --git a/nim/pragmas.pas b/nim/pragmas.pas
index fc354cd2c..e8d07d52d 100755
--- a/nim/pragmas.pas
+++ b/nim/pragmas.pas
@@ -27,7 +27,7 @@ const
   procPragmas = {@set}[FirstCallConv..LastCallConv,
     wImportc, wExportc, wNodecl, wMagic, wNosideEffect, wSideEffect,
     wNoreturn, wDynLib, wHeader, wCompilerProc, wPure,
-    wCppMethod, wDeprecated, wVarargs, wCompileTime, wMerge,
+    wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
     wBorrow];
   converterPragmas = procPragmas;
   methodPragmas = procPragmas;
@@ -258,11 +258,13 @@ begin
   if (sym = nil) or (sym.kind = skModule) then
     POptionEntry(c.optionStack.tail).dynlib := getLib(c, libDynamic,
                                                       expectStrLit(c, n))
-  else begin
+  else if n.kind = nkExprColonExpr then begin
     lib := getLib(c, libDynamic, expectStrLit(c, n));
     addToLib(lib, sym);
     include(sym.loc.flags, lfDynamicLib)
   end
+  else 
+    include(sym.loc.flags, lfExportLib)
 end;
 
 procedure processNote(c: PContext; n: PNode);
@@ -475,12 +477,7 @@ begin
   if n = nil then exit;
   for i := 0 to sonsLen(n)-1 do begin
     it := n.sons[i];
-    if it.kind = nkExprColonExpr then begin
-      key := it.sons[0];
-    end
-    else begin
-      key := it;
-    end;
+    if it.kind = nkExprColonExpr then key := it.sons[0] else key := it;
     if key.kind = nkIdent then begin
       k := whichKeyword(key.ident);
       if k in validPragmas then begin
@@ -540,9 +537,9 @@ begin
             include(sym.flags, sfUsed); // suppress all those stupid warnings
             registerCompilerProc(sym);
           end;
-          wCppMethod: begin
-            makeExternImport(sym, getOptionalStr(c, it, sym.name.s));
-            include(sym.flags, sfCppMethod);
+          wProcvar: begin
+            noVal(it);
+            include(sym.flags, sfProcVar);
           end;
           wDeprecated: begin
             noVal(it);
@@ -615,6 +612,8 @@ begin
     end;
   end;
   if (sym <> nil) and (sym.kind <> skModule) then begin
+    if (lfExportLib in sym.loc.flags) and not (sfExportc in sym.flags) then
+      liMessage(n.info, errDynlibRequiresExportc);
     lib := POptionEntry(c.optionstack.tail).dynlib;
     if ([lfDynamicLib, lfHeader] * sym.loc.flags = []) and
          (sfImportc in sym.flags) and
diff --git a/nim/ptmplsyn.pas b/nim/ptmplsyn.pas
index 2368b22c7..717da6ee0 100755
--- a/nim/ptmplsyn.pas
+++ b/nim/ptmplsyn.pas
@@ -1,28 +1,31 @@
 //
 //
 //           The Nimrod Compiler
-//        (c) Copyright 2008 Andreas Rumpf
+//        (c) Copyright 2009 Andreas Rumpf
 //
 //    See the file "copying.txt", included in this
 //    distribution, for details about the copyright.
 //
 unit ptmplsyn;
 
-// This module implements the parser of the Nimrod Template files.
+// This module implements Nimrod's standard template filter.
 
 {$include config.inc}
 
 interface
 
 uses
-  nsystem, llstream, nos, charsets, wordrecg, strutils,
-  ast, astalgo, msgs, options, pnimsyn;
+  nsystem, llstream, nos, charsets, wordrecg, idents, strutils,
+  ast, astalgo, msgs, options, rnimsyn, filters;
 
-function ParseTmplFile(const filename: string): PNode;
+function filterTmpl(input: PLLStream; const filename: string;
+                    call: PNode): PLLStream;
+// #! template(subsChar='$', metaChar='#') | standard(version="0.7.2")
 
+implementation
 
 type
-  TParseState = (psDirective, psMultiDir, psTempl);
+  TParseState = (psDirective, psTempl);
   TTmplParser = record
     inp: PLLStream;
     state: TParseState;
@@ -30,19 +33,11 @@ type
     indent, par: int;
     x: string; // the current input line
     outp: PLLStream; // the ouput will be parsed by pnimsyn
-    subsChar: Char;
+    subsChar, NimDirective: Char;
+    emit, conc, toStr: string;
   end;
 
-function ParseTmpl(var p: TTmplParser): PNode;
-
-procedure openTmplParser(var p: TTmplParser; const filename: string;
-                         inputStream: PLLStream);
-procedure closeTmplParser(var p: TTmplParser);
-
-implementation
-
 const
-  NimDirective = '#';
   PatternChars = ['a'..'z', 'A'..'Z', '0'..'9', #128..#255, '.', '_'];
 
 procedure newLine(var p: TTmplParser);
@@ -59,73 +54,45 @@ var
 begin
   j := strStart;
   while p.x[j] = ' ' do inc(j);
-  if p.state = psMultiDir then begin
-    newLine(p);
-    if p.x[j] = '*' then begin
-      inc(j);
-      if p.x[j] = NimDirective then p.state := psTempl;
-      // ignore the rest of the line
-    end
-    else
-      LLStreamWrite(p.outp, p.x); // simply add the whole line
-  end
-  else if p.x[j] = NimDirective then begin
+  if (p.x[strStart] = p.NimDirective) and (p.x[strStart+1] = '!') then
+    newLine(p)
+  else if (p.x[j] = p.NimDirective) then begin
     newLine(p);
     inc(j);
     while p.x[j] = ' ' do inc(j);
     d := j;
-    if p.x[j] = '*' then begin
+    keyw := '';
+    while p.x[j] in PatternChars do begin
+      addChar(keyw, p.x[j]);
       inc(j);
-      p.state := psMultiDir;
-      LLStreamWrite(p.outp, repeatChar(p.indent));
-      LLStreamWrite(p.outp, '#*');
-      LLStreamWrite(p.outp, ncopy(p.x, j)); // simply add the whole line
-    end
-    else begin
-      keyw := '';
-      while p.x[j] in PatternChars do begin
-        addChar(keyw, p.x[j]);
-        inc(j);
-      end;
-      case whichKeyword(keyw) of
-        wEnd: begin
-          if p.indent >= 2 then
-            dec(p.indent, 2)
-          else begin
-            p.info.col := int16(j);
-            liMessage(p.info, errXNotAllowedHere, 'end');
-          end;
-          LLStreamWrite(p.outp, repeatChar(p.indent));
-          LLStreamWrite(p.outp, '#end');
-        end;
-        wSubsChar: begin
-          LLStreamWrite(p.outp, repeatChar(p.indent));
-          LLStreamWrite(p.outp, '#subschar');
-          while p.x[j] = ' ' do inc(j);
-          if p.x[j] in ['+', '-', '*', '/', '<', '>', '!', '?', '^', '.',
-                 '|', '=', '%', '&', '$', '@', '~'] then p.subsChar := p.x[j]
-          else begin
-            p.info.col := int16(j);
-            liMessage(p.info, errXNotAllowedHere, p.x[j]+'');
-          end
-        end;
-        wIf, wWhen, wTry, wWhile, wFor, wBlock, wCase, wProc, wIterator,
-        wConverter, wMacro, wTemplate: begin
-          LLStreamWrite(p.outp, repeatChar(p.indent));
-          LLStreamWrite(p.outp, ncopy(p.x, d));
-          inc(p.indent, 2);
-        end;
-        wElif, wOf, wElse, wExcept, wFinally: begin
-          LLStreamWrite(p.outp, repeatChar(p.indent-2));
-          LLStreamWrite(p.outp, ncopy(p.x, d));
-        end
+    end;
+    case whichKeyword(keyw) of
+      wEnd: begin
+        if p.indent >= 2 then
+          dec(p.indent, 2)
         else begin
-          LLStreamWrite(p.outp, repeatChar(p.indent));
-          LLStreamWrite(p.outp, ncopy(p.x, d));
-        end
+          p.info.col := int16(j);
+          liMessage(p.info, errXNotAllowedHere, 'end');
+        end;
+        LLStreamWrite(p.outp, repeatChar(p.indent));
+        LLStreamWrite(p.outp, '#end');
+      end;
+      wIf, wWhen, wTry, wWhile, wFor, wBlock, wCase, wProc, wIterator,
+      wConverter, wMacro, wTemplate, wMethod: begin
+        LLStreamWrite(p.outp, repeatChar(p.indent));
+        LLStreamWrite(p.outp, ncopy(p.x, d));
+        inc(p.indent, 2);
       end;
-      p.state := psDirective;
-    end
+      wElif, wOf, wElse, wExcept, wFinally: begin
+        LLStreamWrite(p.outp, repeatChar(p.indent-2));
+        LLStreamWrite(p.outp, ncopy(p.x, d));
+      end
+      else begin
+        LLStreamWrite(p.outp, repeatChar(p.indent));
+        LLStreamWrite(p.outp, ncopy(p.x, d));
+      end
+    end;
+    p.state := psDirective
   end
   else begin
     // data line
@@ -133,17 +100,18 @@ begin
     case p.state of
       psTempl: begin
         // next line of string literal:
-        LLStreamWrite(p.outp, ' &'+nl);
+        LLStreamWrite(p.outp, p.conc);
+        LLStreamWrite(p.outp, nl);
         LLStreamWrite(p.outp, repeatChar(p.indent + 2));
         LLStreamWrite(p.outp, '"'+'');
       end;
       psDirective: begin
         newLine(p);
         LLStreamWrite(p.outp, repeatChar(p.indent));
-        LLStreamWrite(p.outp, 'add(result, "');
+        LLStreamWrite(p.outp, p.emit);
+        LLStreamWrite(p.outp, '("');
         inc(p.par);
-      end;
-      else InternalError(p.info, 'parser in invalid state');
+      end
     end;
     p.state := psTempl;
     while true do begin
@@ -162,7 +130,10 @@ begin
           case p.x[j] of
             '{': begin
               p.info.col := int16(j);
-              LLStreamWrite(p.outp, '" & $(');
+              LLStreamWrite(p.outp, '"');
+              LLStreamWrite(p.outp, p.conc);
+              LLStreamWrite(p.outp, p.toStr);
+              LLStreamWrite(p.outp, '(');
               inc(j);
               curly := 0;
               while true do begin
@@ -171,13 +142,13 @@ begin
                   '{': begin
                     inc(j);
                     inc(curly);
-                    LLStreamWrite(p.outp, '{'+'');
+                    LLStreamWrite(p.outp, '{');
                   end;
                   '}': begin
                     inc(j);
                     if curly = 0 then break;
                     if curly > 0 then dec(curly);
-                    LLStreamWrite(p.outp, '}'+'');
+                    LLStreamWrite(p.outp, '}');
                   end;
                   else begin
                     LLStreamWrite(p.outp, p.x[j]);
@@ -185,15 +156,22 @@ begin
                   end
                 end
               end;
-              LLStreamWrite(p.outp, ') & "')
+              LLStreamWrite(p.outp, ')');
+              LLStreamWrite(p.outp, p.conc);
+              LLStreamWrite(p.outp, '"');
             end;
-            'A'..'Z', 'a'..'z', '_': begin
-              LLStreamWrite(p.outp, '" & $');
+            'a'..'z', 'A'..'Z', #128..#255: begin
+              LLStreamWrite(p.outp, '"');
+              LLStreamWrite(p.outp, p.conc);
+              LLStreamWrite(p.outp, p.toStr);
+              LLStreamWrite(p.outp, '(');
               while p.x[j] in PatternChars do begin
                 LLStreamWrite(p.outp, p.x[j]);
                 inc(j)
               end;
-              LLStreamWrite(p.outp, ' & "')
+              LLStreamWrite(p.outp, ')');
+              LLStreamWrite(p.outp, p.conc);
+              LLStreamWrite(p.outp, '"')
             end;
             else if p.x[j] = p.subsChar then begin
               LLStreamWrite(p.outp, p.subsChar);
@@ -203,7 +181,7 @@ begin
               p.info.col := int16(j);
               liMessage(p.info, errInvalidExpression, '$'+'');
             end
-          end;
+          end
         end
         else begin
           LLStreamWrite(p.outp, p.x[j]);
@@ -215,56 +193,30 @@ begin
   end
 end;
 
-function ParseTmpl(var p: TTmplParser): PNode;
+function filterTmpl(input: PLLStream; const filename: string;
+                    call: PNode): PLLStream;
 var
-  q: TParser;
+  p: TTmplParser; 
 begin
+{@ignore}
+  FillChar(p, sizeof(p), 0);
+{@emit}
+  p.info := newLineInfo(filename, 0, 0);
+  p.outp := LLStreamOpen('');
+  p.inp := input;
+  p.subsChar := charArg(call, 'subschar', 1, '$');
+  p.nimDirective := charArg(call, 'metachar', 2, '#');
+  p.emit := strArg(call, 'emit', 3, 'result.add');
+  p.conc := strArg(call, 'conc', 4, ' & ');
+  p.toStr := strArg(call, 'tostring', 5, '$'+'');
   while not LLStreamAtEnd(p.inp) do begin
     p.x := LLStreamReadLine(p.inp) {@ignore} + #0 {@emit};
     p.info.line := p.info.line + int16(1);
     parseLine(p);
   end;
   newLine(p);
-  if gVerbosity >= 2 then begin
-    rawMessage(hintCodeBegin);
-    messageOut(p.outp.s);
-    rawMessage(hintCodeEnd);
-  end;
-  openParser(q, toFilename(p.info), p.outp);
-  result := ParseModule(q);
-  closeParser(q);
-end;
-
-procedure openTmplParser(var p: TTmplParser; const filename: string;
-                         inputStream: PLLStream);
-begin
-{@ignore}
-  FillChar(p, sizeof(p), 0);
-{@emit}
-  p.info := newLineInfo(filename, 0, 0);
-  p.outp := LLStreamOpen('');
-  p.inp := inputStream;
-  p.subsChar := '$';
-end;
-
-procedure CloseTmplParser(var p: TTmplParser);
-begin
+  result := p.outp;
   LLStreamClose(p.inp);
 end;
 
-function ParseTmplFile(const filename: string): PNode;
-var
-  p: TTmplParser;
-  f: TBinaryFile;
-begin
-  if not OpenFile(f, filename) then begin
-    rawMessage(errCannotOpenFile, filename);
-    result := nil;
-    exit
-  end;
-  OpenTmplParser(p, filename, LLStreamOpen(f));
-  result := ParseTmpl(p);
-  CloseTmplParser(p);
-end;
-
 end.
diff --git a/nim/rnimsyn.pas b/nim/rnimsyn.pas
index 1ad1c9408..ec1e9571e 100755
--- a/nim/rnimsyn.pas
+++ b/nim/rnimsyn.pas
@@ -498,7 +498,7 @@ begin
     nkPar, nkCurly, nkBracket: result := lcomma(n)+2;
     nkSymChoice: result := lsons(n) + length('()') + sonsLen(n)-1;
     nkTupleTy: result := lcomma(n)+length('tuple[]');
-    nkQualified, nkDotExpr: result := lsons(n)+1;
+    nkDotExpr: result := lsons(n)+1;
     nkBind: result := lsons(n)+length('bind_');
     nkCheckedFieldExpr: result := lsub(n.sons[0]);
     nkLambda: result := lsons(n)+length('lambda__=_');
@@ -1047,7 +1047,7 @@ begin
       gcomma(g, n, c);
       put(g, tkBracketRi, ']'+'');
     end;
-    nkQualified, nkDotExpr: begin
+    nkDotExpr: begin
       gsub(g, n.sons[0]);
       put(g, tkDot, '.'+'');
       gsub(g, n.sons[1]);
diff --git a/nim/rodread.pas b/nim/rodread.pas
index dc3630a45..457ad6cc2 100755
--- a/nim/rodread.pas
+++ b/nim/rodread.pas
@@ -1057,8 +1057,7 @@ begin
         // NOTE: we need to process the entire module graph so that no ID will
         // be used twice! However, compilation speed does not suffer much from
         // this, since results are cached.
-        res := checkDep(JoinPath(options.libpath, 
-                        appendFileExt('system', nimExt)));
+        res := checkDep(JoinPath(options.libpath, addFileExt('system', nimExt)));
         if res <> rrNone then result := rrModDeps;
         for i := 0 to high(r.modDeps) do begin
           res := checkDep(r.modDeps[i]);
diff --git a/nim/rst.pas b/nim/rst.pas
index d5cde5c7e..fb29b7d9f 100755
--- a/nim/rst.pas
+++ b/nim/rst.pas
@@ -314,6 +314,9 @@ begin
   len := length(tokens);
   L.buf := PChar(buffer);
   L.line := 1;
+  // skip UTF-8 BOM
+  if (L.buf[0] = #239) and (L.buf[1] = #187) and (L.buf[2] = #191) then 
+    inc(L.bufpos, 3);
   L.skipPounds := skipPounds;
   if skipPounds then begin
     if L.buf[L.bufpos] = '#' then inc(L.bufpos);
diff --git a/nim/scanner.pas b/nim/scanner.pas
index 05f903622..c03ae9224 100755
--- a/nim/scanner.pas
+++ b/nim/scanner.pas
@@ -143,19 +143,16 @@ type
                            // or float literals
     literal: string;       // the parsed (string) literal; and
                            // documentation comments are here too
-    next: PToken;          // next token; used for arbitrary look-ahead
+    next: PToken;          // next token; can be used for arbitrary look-ahead
   end;
 
   PLexer = ^TLexer;
   TLexer = object(TBaseLexer)
-    // lexers can be put into a stack through the next pointer;
-    // this feature is currently unused, however
     filename: string;
-    next: PLexer;
     indentStack: array of int; // the indentation stack
     dedent: int;             // counter for DED token generation
     indentAhead: int;        // if > 0 an indendation has already been read
-                             // this is needed because scanning # comments
+                             // this is needed because scanning comments
                              // needs so much look-ahead
   end;
 
@@ -920,7 +917,6 @@ begin
   // got an documentation comment or tkIndent, return that:
   if tok.toktype <> tkInvalid then exit;
 
-  // to the parser
   c := L.buf[L.bufpos];
   if c in SymStartChars - ['r', 'R', 'l'] then // common case first
     getSymbol(L, tok)
diff --git a/nim/semexprs.pas b/nim/semexprs.pas
index 43eb9ac6f..91c909dfd 100755
--- a/nim/semexprs.pas
+++ b/nim/semexprs.pas
@@ -374,15 +374,34 @@ begin
   end
 end;
 
-function isAssignable(n: PNode): bool;
+type
+  TAssignableResult = (
+    arNone,              // no l-value and no discriminant
+    arLValue,            // is an l-value
+    arDiscriminant       // is a discriminant
+  );
+
+function isAssignable(n: PNode): TAssignableResult;
 begin
-  result := false;
+  result := arNone;
   case n.kind of
-    nkSym: result := (n.sym.kind in [skVar, skTemp]);
-    nkDotExpr, nkQualified, nkBracketExpr: begin
+    nkSym: begin
+      if (n.sym.kind in [skVar, skTemp]) then
+        result := arLValue
+    end;
+    nkDotExpr: begin
+      checkMinSonsLen(n, 1);
+      if skipTypes(n.sons[0].typ, abstractInst).kind in [tyVar, tyPtr, tyRef] then
+        result := arLValue
+      else
+        result := isAssignable(n.sons[0]);
+      if (result = arLValue) and (sfDiscriminant in n.sons[1].sym.flags) then
+        result := arDiscriminant
+    end;
+    nkBracketExpr: begin
       checkMinSonsLen(n, 1);
       if skipTypes(n.sons[0].typ, abstractInst).kind in [tyVar, tyPtr, tyRef] then
-        result := true
+        result := arLValue
       else
         result := isAssignable(n.sons[0]);
     end;
@@ -393,7 +412,7 @@ begin
       if skipTypes(n.typ, abstractPtrs).kind in [tyOpenArray, tyTuple, tyObject] then
         result := isAssignable(n.sons[1])
     end;
-    nkHiddenDeref, nkDerefExpr: result := true;
+    nkHiddenDeref, nkDerefExpr: result := arLValue;
     nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
       result := isAssignable(n.sons[0]);
     else begin end
@@ -409,7 +428,7 @@ begin
   else begin
     result := newNodeIT(nkHiddenAddr, n.info, makeVarType(c, n.typ));
     addSon(result, n);
-    if not isAssignable(n) then begin
+    if isAssignable(n) <> arLValue then begin
       liMessage(n.info, errVarForOutParamNeeded);
     end
   end
@@ -425,7 +444,7 @@ begin
         result := newHiddenAddrTaken(c, n);
       end
     end;
-    nkDotExpr, nkQualified: begin
+    nkDotExpr: begin
       checkSonsLen(n, 2);
       if n.sons[1].kind <> nkSym then
         internalError(n.info, 'analyseIfAddressTaken');
@@ -499,7 +518,7 @@ begin
   prc := n.sons[0];
   checkMinSonsLen(n, 1);
   case n.sons[0].kind of
-    nkDotExpr, nkQualified: begin
+    nkDotExpr: begin
       checkSonsLen(n.sons[0], 2);
       n.sons[0] := semDotExpr(c, n.sons[0]);
       if n.sons[0].kind = nkDotCall then begin // it is a static call!
@@ -595,7 +614,7 @@ begin
       else
         result := SymtabGet(c.Tab, n.ident); // no need for stub loading
     end;
-    nkDotExpr, nkQualified: begin
+    nkDotExpr: begin
       result := nil;
       if onlyCurrentScope then exit;
       checkSonsLen(n, 2);
@@ -1174,8 +1193,14 @@ begin
     liMessage(n.info, errATypeHasNoValue);
   case s.kind of
     skProc, skMethod, skIterator, skConverter: begin
-      if (s.magic <> mNone) then
-        liMessage(n.info, errInvalidContextForBuiltinX, s.name.s);
+      if not (sfProcVar in s.flags) 
+      and (s.typ.callConv = ccDefault)
+      and (getModule(s).id <> c.module.id) then
+        liMessage(n.info, warnXisPassedToProcVar, s.name.s);
+      // XXX change this to errXCannotBePassedToProcVar after version 0.8.2
+      // TODO VERSION 0.8.4
+      //if (s.magic <> mNone) then
+      //  liMessage(n.info, errInvalidContextForBuiltinX, s.name.s);
       result := symChoice(c, n, s);
     end;
     skConst: begin
@@ -1253,10 +1278,7 @@ begin
       (*s := n.sym;
       include(s.flags, sfUsed);
       if (s.kind = skType) and not (efAllowType in flags) then
-        liMessage(n.info, errATypeHasNoValue);
-      if (s.magic <> mNone) and
-          (s.kind in [skProc, skMethod, skIterator, skConverter]) then
-        liMessage(n.info, errInvalidContextForBuiltinX, s.name.s); *)
+        liMessage(n.info, errATypeHasNoValue);*)
       // because of the changed symbol binding, this does not mean that we
       // don't have to check the symbol for semantics here again!
       result := semSym(c, n, n.sym, flags);
@@ -1279,7 +1301,7 @@ begin
       if result.typ = nil then result.typ := getSysType(tyString);
     nkCharLit:
       if result.typ = nil then result.typ := getSysType(tyChar);
-    nkQualified, nkDotExpr: begin
+    nkDotExpr: begin
       result := semDotExpr(c, n, flags);
       if result.kind = nkDotCall then begin
         result.kind := nkCall;
@@ -1364,7 +1386,8 @@ begin
       result := n;
       checkSonsLen(n, 1);
       n.sons[0] := semExprWithType(c, n.sons[0]);
-      if not isAssignable(n.sons[0]) then liMessage(n.info, errExprHasNoAddress);
+      if isAssignable(n.sons[0]) <> arLValue then 
+        liMessage(n.info, errExprHasNoAddress);
       n.typ := makePtrType(c, n.sons[0].typ);
     end;
     nkHiddenAddr, nkHiddenDeref: begin
diff --git a/nim/semstmts.pas b/nim/semstmts.pas
index b4b72a25b..1ece72023 100755
--- a/nim/semstmts.pas
+++ b/nim/semstmts.pas
@@ -127,7 +127,7 @@ var
   str, sub: string;
   a, b, c: int;
   e: PSym;
-  marker: Char;
+  marker: char;
 begin
   result := n;
   checkSonsLen(n, 2);
@@ -243,7 +243,7 @@ begin
   checkSonsLen(n, 2);
   a := n.sons[0];
   case a.kind of
-    nkDotExpr, nkQualified: begin
+    nkDotExpr: begin
       // r.f = x
       // --> `f=` (r, x)
       checkSonsLen(a, 2);
@@ -298,7 +298,8 @@ begin
   n.sons[1] := semExprWithType(c, n.sons[1]);
   le := n.sons[0].typ;
   if (skipTypes(le, {@set}[tyGenericInst]).kind <> tyVar) 
-  and not IsAssignable(n.sons[0]) then begin
+  and (IsAssignable(n.sons[0]) = arNone) then begin
+    // Direct assignment to a discriminant is allowed!
     liMessage(n.sons[0].info, errXCannotBeAssignedTo,
               renderTree(n.sons[0], {@set}[renderNoComments]));
   end
@@ -1014,8 +1015,7 @@ end;
 function evalInclude(c: PContext; n: PNode): PNode;
 var
   i, fileIndex: int;
-  x: PNode;
-  f, name, ext: string;
+  f: string;
 begin
   result := newNodeI(nkStmtList, n.info);
   addSon(result, n); // the rodwriter needs include information!
@@ -1024,13 +1024,7 @@ begin
     fileIndex := includeFilename(f);
     if IntSetContainsOrIncl(c.includedFiles, fileIndex) then
       liMessage(n.info, errRecursiveDependencyX, f);
-    SplitFilename(f, name, ext);
-    if cmpIgnoreCase(ext, '.'+TmplExt) = 0 then
-      x := gIncludeTmplFile(f)
-    else
-      x := gIncludeFile(f);
-    x := semStmt(c, x);
-    addSon(result, x);
+    addSon(result, semStmt(c, gIncludeFile(f)));
     IntSetExcl(c.includedFiles, fileIndex);
   end;
 end;
diff --git a/nim/semtempl.pas b/nim/semtempl.pas
index 8e37a1ea3..e639960d3 100755
--- a/nim/semtempl.pas
+++ b/nim/semtempl.pas
@@ -34,7 +34,7 @@ begin
   if n = nil then begin result := false; exit end;
   case n.kind of
     nkIdent, nkSym, nkType: result := true;
-    nkDotExpr, nkQualified, nkBracketExpr: begin
+    nkDotExpr, nkBracketExpr: begin
       for i := 0 to sonsLen(n)-1 do
         if not isTypeDesc(n.sons[i]) then begin
           result := false; exit
diff --git a/nim/semtypes.pas b/nim/semtypes.pas
index c0b86be86..e2a0d2185 100755
--- a/nim/semtypes.pas
+++ b/nim/semtypes.pas
@@ -758,6 +758,10 @@ begin
     nkTypeOfExpr: begin
       result := semExprWithType(c, n, {@set}[efAllowType]).typ;
     end;
+    nkPar: begin
+      if sonsLen(n) = 1 then result := semTypeNode(c, n.sons[0], prev)
+      else liMessage(n.info, errTypeExpected);
+    end;
     nkBracketExpr: begin
       checkMinSonsLen(n, 2);
       s := semTypeIdent(c, n.sons[0]);
@@ -771,7 +775,7 @@ begin
         else result := semGeneric(c, n, s, prev);
       end
     end;
-    nkIdent, nkDotExpr, nkQualified, nkAccQuoted: begin
+    nkIdent, nkDotExpr, nkAccQuoted: begin
       s := semTypeIdent(c, n);
       if s.typ = nil then
         liMessage(n.info, errTypeExpected);
diff --git a/nim/strutils.pas b/nim/strutils.pas
index be20b52b2..afd8b4766 100755
--- a/nim/strutils.pas
+++ b/nim/strutils.pas
@@ -50,7 +50,7 @@ function ToString(b: PChar): string; overload;
 function IntToStr(i: BiggestInt; minChars: int): string;
 
 function find(const s, sub: string; start: int = 1): int; overload;
-function replaceStr(const s, search, by: string): string;
+function replace(const s, search, by: string): string;
 procedure deleteStr(var s: string; first, last: int);
 
 function ToLower(const s: string): string;
@@ -63,9 +63,6 @@ function ParseFloat(const s: string; checkEnd: Boolean = True): Real;
 
 function repeatChar(count: int; c: Char = ' '): string;
 
-type
-  TStringSeq = array of string;
-  TCharSet = set of Char;
 function split(const s: string; const seps: TCharSet): TStringSeq;
 
 function startsWith(const s, prefix: string): bool;
@@ -278,7 +275,7 @@ begin
   end
 end;
 
-function replaceStr(const s, search, by: string): string;
+function replace(const s, search, by: string): string;
 var
   i, j: int;
 begin
diff --git a/nim/syntaxes.pas b/nim/syntaxes.pas
index 1068064ce..19035028e 100755
--- a/nim/syntaxes.pas
+++ b/nim/syntaxes.pas
@@ -1,64 +1,234 @@
 //
 //
 //           The Nimrod Compiler
-//        (c) Copyright 2008 Andreas Rumpf
+//        (c) Copyright 2009 Andreas Rumpf
 //
 //    See the file "copying.txt", included in this
 //    distribution, for details about the copyright.
 //
 unit syntaxes;
 
-// Defines the common interface of all parsers & renderers.
-// All parsers and renderers need to register here!
-// This file is currently unused.
+// Implements the dispatcher for the different parsers.
 {$include 'config.inc'}
 
 interface
 
 uses
-  nsystem, strutils, ast, scanner, pnimsyn, rnimsyn, options, msgs,
-  nos, lists, condsyms, paslex, pasparse, rodgen, ropes, trees;
-
-// how to handle the different keyword sets?
-// PIdent does not support multiple ids! But I want to allow
-// constant expressions, else the case-statement wouldn't work
-// resulting in ugly code -> let the build system deal with it!
-// IDEA: the scanner changes the IDs for its keywords: Won't work!
-// How to deal with the `` operator?
+  nsystem, strutils, llstream, ast, astalgo, idents, scanner, options, msgs, 
+  pnimsyn, ptmplsyn, filters, rnimsyn;
 
 type
-  TSyntaxes = (synStandard, synCurly, synLisp);
+  TFilterKind = (filtNone, filtTemplate, filtReplace, filtStrip);
+  TParserKind = (skinStandard, skinBraces, skinEndX);
+  
+const
+  parserNames: array [TParserKind] of string = ('standard', 'braces', 'endx');
+  filterNames: array [TFilterKind] of string = ('none', 'stdtmpl', 'replace',
+                                                'strip');
+  
+type
+  TParsers = record
+    skin: TParserKind;
+    parser: TParser;
+  end;
+
+{@ignore} 
+function ParseFile(const filename: string): PNode;
+{@emit
+function ParseFile(const filename: string): PNode; procvar;
+}
+
+procedure openParsers(var p: TParsers; const filename: string;
+                     inputstream: PLLStream);
+procedure closeParsers(var p: TParsers);
+function parseAll(var p: TParsers): PNode;
+
+function parseTopLevelStmt(var p: TParsers): PNode;
+// implements an iterator. Returns the next top-level statement or nil if end
+// of stream.
 
-function parseFile(const filename: string): PNode;
 
 implementation
 
-type
-  TFileParser = function (const filename: string): PNode;
-  TBufferParser = function (const buf, filename: string; 
-                            line, column: int): PNode;
-  TRenderer = function (n: PNode): string;
-  THeadParser = function (const line: string): bool;
-  TSyntax = record
-    name: string;            // name of the syntax
-    headParser: THeadParser; // the head parser
-    parser: TParser;         // the parser for the syntax
-    renderer: TRenderer;     // renderer of the syntax; may be nil
+function ParseFile(const filename: string): PNode;
+var
+  p: TParsers;
+  f: TBinaryFile;
+begin
+  if not OpenFile(f, filename) then begin
+    rawMessage(errCannotOpenFile, filename);
+    exit
   end;
+  OpenParsers(p, filename, LLStreamOpen(f));
+  result := ParseAll(p);
+  CloseParsers(p);
+end;
 
+function parseAll(var p: TParsers): PNode;
+begin
+  case p.skin of
+    skinStandard: result := pnimsyn.parseAll(p.parser);
+    skinBraces, skinEndX: InternalError('parser to implement');
+    // skinBraces: result := pbraces.parseAll(p.parser);
+    // skinEndX: result := pendx.parseAll(p.parser);
+  end
+end;
+
+function parseTopLevelStmt(var p: TParsers): PNode;
+begin
+  case p.skin of
+    skinStandard: result := pnimsyn.parseTopLevelStmt(p.parser);
+    skinBraces, skinEndX: InternalError('parser to implement');
+    //skinBraces: result := pbraces.parseTopLevelStmt(p.parser);
+    //skinEndX: result := pendx.parseTopLevelStmt(p.parser);
+  end
+end;
+
+function UTF8_BOM(const s: string): int;
+begin
+  if (s[strStart] = #239) and (s[strStart+1] = #187) 
+  and (s[strStart+2] = #191) then result := 3
+  else result := 0
+end;
+
+function containsShebang(const s: string; i: int): bool;
 var
-  syntaxes: array [TSyntaxes] of TSyntax;
+  j: int;
+begin
+  result := false;
+  if (s[i] = '#') and (s[i+1] = '!') then begin
+    j := i+2;
+    while s[j] in WhiteSpace do inc(j);
+    result := s[j] = '/'
+  end
+end;
 
-procedure addSyntax(const s: TSyntax);
+function parsePipe(const filename: string; inputStream: PLLStream): PNode;
 var
-  len: int;
+  line: string;
+  s: PLLStream;
+  i: int;
+  q: TParser;
 begin
-  len := length(syntaxes);
-  setLength(syntaxes, len+1);
-  syntaxes[len] := s;
+  result := nil;
+  s := LLStreamOpen(filename, fmRead);
+  if s <> nil then begin
+    line := LLStreamReadLine(s) {@ignore} + #0 {@emit};
+    i := UTF8_Bom(line) + strStart;
+    if containsShebang(line, i) then begin
+      line := LLStreamReadLine(s) {@ignore} + #0 {@emit};
+      i := strStart;
+    end;
+    if (line[i] = '#') and (line[i+1] = '!') then begin
+      inc(i, 2);
+      while line[i] in WhiteSpace do inc(i);
+      OpenParser(q, filename, LLStreamOpen(ncopy(line, i)));
+      result := pnimsyn.parseAll(q);
+      CloseParser(q);
+    end;
+    LLStreamClose(s);
+  end
+end;
+
+function getFilter(ident: PIdent): TFilterKind;
+var
+  i: TFilterKind;
+begin
+  for i := low(TFilterKind) to high(TFilterKind) do
+    if IdentEq(ident, filterNames[i]) then begin
+      result := i; exit
+    end;
+  result := filtNone
+end;
+
+function getParser(ident: PIdent): TParserKind;
+var
+  i: TParserKind;
+begin
+  for i := low(TParserKind) to high(TParserKind) do
+    if IdentEq(ident, parserNames[i]) then begin
+      result := i; exit
+    end;
+  rawMessage(errInvalidDirectiveX, ident.s);
+end;
+
+function getCallee(n: PNode): PIdent;
+begin
+  if (n.kind = nkCall) and (n.sons[0].kind = nkIdent) then
+    result := n.sons[0].ident
+  else if n.kind = nkIdent then result := n.ident
+  else rawMessage(errXNotAllowedHere, renderTree(n));
+end;
+
+function applyFilter(var p: TParsers; n: PNode; const filename: string; 
+                     input: PLLStream): PLLStream;
+var
+  ident: PIdent;
+  f: TFilterKind;
+begin
+  ident := getCallee(n);
+  f := getFilter(ident); 
+  case f of
+    filtNone: begin
+      p.skin := getParser(ident);
+      result := input
+    end;
+    filtTemplate: result := filterTmpl(input, filename, n);
+    filtStrip: result := filterStrip(input, filename, n);
+    filtReplace: result := filterReplace(input, filename, n);
+  end;
+  if f <> filtNone then begin
+    if gVerbosity >= 2 then begin
+      rawMessage(hintCodeBegin);
+      messageOut(result.s);
+      rawMessage(hintCodeEnd);
+    end
+  end
+end;
+
+function evalPipe(var p: TParsers; n: PNode; const filename: string;
+                  start: PLLStream): PLLStream;
+var 
+  i: int;
+begin
+  result := start;
+  if n = nil then exit;
+  if (n.kind = nkInfix) and (n.sons[0].kind = nkIdent)
+  and IdentEq(n.sons[0].ident, '|'+'') then begin
+    for i := 1 to 2 do begin
+      if n.sons[i].kind = nkInfix then
+        result := evalPipe(p, n.sons[i], filename, result)
+      else
+        result := applyFilter(p, n.sons[i], filename, result)
+    end
+  end
+  else if n.kind = nkStmtList then 
+    result := evalPipe(p, n.sons[0], filename, result)
+  else
+    result := applyFilter(p, n, filename, result)
+end;
+
+procedure openParsers(var p: TParsers; const filename: string;
+                     inputstream: PLLStream);
+var
+  pipe: PNode;
+  s: PLLStream;
+begin
+  p.skin := skinStandard;
+  pipe := parsePipe(filename, inputStream);
+  if pipe <> nil then 
+    s := evalPipe(p, pipe, filename, inputStream)
+  else
+    s := inputStream;
+  case p.skin of
+    skinStandard, skinBraces, skinEndX:
+      pnimsyn.openParser(p.parser, filename, s);
+  end
+end;
+
+procedure closeParsers(var p: TParsers);
+begin
+  pnimsyn.closeParser(p.parser);
 end;
 
-initialization
-  syntaxes[synStandard].name = 'Standard';
-  
 end.
diff --git a/nim/transf.pas b/nim/transf.pas
index d5b0bb6f8..192d76a84 100755
--- a/nim/transf.pas
+++ b/nim/transf.pas
@@ -652,7 +652,7 @@ end;
       f: proc (x: int, c: PClosure): int
 
   proc map(f: PClosure, a: seq[int]): seq[int] =
-    result = []
+    result = @[]
     for elem in a:
       add result, f.f(a, f)
 
@@ -737,6 +737,7 @@ end;
 
 function transformCase(c: PTransf; n: PNode): PNode;
 // removes `elif` branches of a case stmt
+// adds ``else: nil`` if needed for the code generator
 var
   len, i, j: int;
   ifs, elsen: PNode;
@@ -754,6 +755,14 @@ begin
     setLength(n.sons, i+2);
     addSon(elsen, ifs);
     n.sons[i+1] := elsen;
+  end  
+  else if (n.sons[len-1].kind <> nkElse) and 
+           not (skipTypes(n.sons[0].Typ, abstractVarRange).Kind in
+               [tyInt..tyInt64, tyChar, tyEnum]) then begin
+    //MessageOut(renderTree(n));
+    elsen := newNodeI(nkElse, n.info);
+    addSon(elsen, newNodeI(nkNilLit, n.info));
+    addSon(n, elsen)
   end;
   result := n;
   for j := 0 to sonsLen(n)-1 do result.sons[j] := transform(c, n.sons[j]);
diff --git a/nim/wordrecg.pas b/nim/wordrecg.pas
index 9bf3de256..c18969877 100755
--- a/nim/wordrecg.pas
+++ b/nim/wordrecg.pas
@@ -63,9 +63,9 @@ type
     wMagic, wTypeCheck, wFinal, wProfiler,
     wObjChecks, wImportc, wExportc, wAlign, wNodecl, wPure,
     wVolatile, wRegister, wSideeffect, wHeader, wNosideeffect, wNoreturn,
-    wMerge, wLib, wDynlib, wCompilerproc, wCppmethod, wFatal,
+    wMerge, wLib, wDynlib, wCompilerproc, wProcVar, wFatal,
     wError, wWarning, wHint, wLine, wPush, wPop,
-    wDefine, wUndef, wLinedir, wStacktrace, wLinetrace, wPragma,
+    wDefine, wUndef, wLinedir, wStacktrace, wLinetrace, wParallelBuild,
     wLink, wCompile, wLinksys, wDeprecated, wVarargs,
     wByref, wCallconv, wBreakpoint, wDebugger, wNimcall, wStdcall,
     wCdecl, wSafecall, wSyscall, wInline, wNoInline, wFastcall, wClosure,
@@ -136,9 +136,9 @@ const
     'magic', 'typecheck', 'final', 'profiler',
     'objchecks', 'importc', 'exportc', 'align', 'nodecl', 'pure',
     'volatile', 'register', 'sideeffect', 'header', 'nosideeffect', 'noreturn',
-    'merge', 'lib', 'dynlib', 'compilerproc', 'cppmethod', 'fatal',
+    'merge', 'lib', 'dynlib', 'compilerproc', 'procvar', 'fatal',
     'error', 'warning', 'hint', 'line', 'push', 'pop',
-    'define', 'undef', 'linedir', 'stacktrace', 'linetrace', 'pragma',
+    'define', 'undef', 'linedir', 'stacktrace', 'linetrace', 'parallelbuild',
     'link', 'compile', 'linksys', 'deprecated', 'varargs',
     'byref', 'callconv', 'breakpoint', 'debugger', 'nimcall', 'stdcall',
     'cdecl', 'safecall', 'syscall', 'inline', 'noinline', 'fastcall', 'closure',