#define T yylval->newline_ = yyextra->state_ == CYNewLine;
 #define C T yyextra->state_ = CYClear;
 #define R T yyextra->state_ = CYRestricted;
-#define N if (yyextra->state_ != CYNewLine) { bool restricted(yyextra->state_ == CYRestricted); if (restricted) { yyextra->state_ = CYClear; return tk::NewLine; } else yyextra->state_ = CYNewLine; }
+
+#define N \
+    if (yyextra->state_ != CYNewLine) { \
+        bool restricted(yyextra->state_ == CYRestricted); \
+        if (restricted) { \
+            yyextra->state_ = CYClear; \
+            return tk::NewLine; \
+        } else \
+            yyextra->state_ = CYNewLine; \
+    }
+
+#define L { \
+    yylloc->step(); \
+    yylloc->columns(yyleng); \
+}
 
 #define YY_INPUT(data, value, size) { \
     if (yyextra->size_ == 0) \
 \/\/[^\n]* ;
 \/\*(\n|[^\*]|\*[^/])\*\/ if (memchr(yytext, '\n', yyleng) != NULL) N // XXX: supposedly I will be screwed on very very long multi-line comments and need to replace this with a manual lexer. http://websrv.cs.fsu.edu/~engelen/courses/COP5621/Pr2.pdf ; XXX: this rule doesn't work anyway, fucking A :(
 
-"&"    C return tk::Ampersand;
-"&&"   C return tk::AmpersandAmpersand;
-"&="   C return tk::AmpersandEqual;
-"^"    C return tk::Carrot;
-"^="   C return tk::CarrotEqual;
-"="    C return tk::Equal;
-"=="   C return tk::EqualEqual;
-"==="  C return tk::EqualEqualEqual;
-"!"    C return tk::Exclamation;
-"!="   C return tk::ExclamationEqual;
-"!=="  C return tk::ExclamationEqualEqual;
-"-"    C return tk::Hyphen;
-"-="   C return tk::HyphenEqual;
-"--"   C return yylval->newline_ ? tk::HyphenHyphen_ : tk::HyphenHyphen;
-"->"   C return tk::HyphenRight;
-"<"    C return tk::Left;
-"<="   C return tk::LeftEqual;
-"<<"   C return tk::LeftLeft;
-"<<="  C return tk::LeftLeftEqual;
-"%"    C return tk::Percent;
-"%="   C return tk::PercentEqual;
-"."    C return tk::Period;
-"|"    C return tk::Pipe;
-"|="   C return tk::PipeEqual;
-"||"   C return tk::PipePipe;
-"+"    C return tk::Plus;
-"+="   C return tk::PlusEqual;
-"++"   C return yylval->newline_ ? tk::PlusPlus_ : tk::PlusPlus;
-">"    C return tk::Right;
-">="   C return tk::RightEqual;
-">>"   C return tk::RightRight;
-">>="  C return tk::RightRightEqual;
-">>>"  C return tk::RightRightRight;
-">>>=" C return tk::RightRightRightEqual;
-"/"    C return tk::Slash;
-"/="   C return tk::SlashEqual;
-"*"    C return tk::Star;
-"*="   C return tk::StarEqual;
-"~"    C return tk::Tilde;
-
-":"    C return tk::Colon;
-","    C return tk::Comma;
-"?"    C return tk::Question;
-";"    C return tk::SemiColon;
-
-"("    C return tk::OpenParen;
-")"    C return tk::CloseParen;
-
-"{"    C return tk::OpenBrace;
-"}"    C return tk::CloseBrace;
-
-"["    C return tk::OpenBracket;
-"]"    C return tk::CloseBracket;
-
-"@selector"  C return tk::AtSelector;
-
-"break"      R yylval->word_ = new CYWord("break"); return tk::Break;
-"case"       C yylval->word_ = new CYWord("case"); return tk::Case;
-"catch"      C yylval->word_ = new CYWord("catch"); return tk::Catch;
-"continue"   R yylval->word_ = new CYWord("continue"); return tk::Continue;
-"default"    C yylval->word_ = new CYWord("default"); return tk::Default;
-"delete"     C yylval->word_ = new CYWord("delete"); return tk::Delete;
-"do"         C yylval->word_ = new CYWord("do"); return tk::Do;
-"else"       C yylval->word_ = new CYWord("else"); return tk::Else;
-"false"      C yylval->false_ = new CYFalse(); return tk::False;
-"finally"    C yylval->word_ = new CYWord("finally"); return tk::Finally;
-"for"        C yylval->word_ = new CYWord("for"); return tk::For;
-"function"   C yylval->word_ = new CYWord("function"); return tk::Function;
-"if"         C yylval->word_ = new CYWord("if"); return tk::If;
-"in"         C yylval->word_ = new CYWord("in"); return tk::In;
-"instanceof" C yylval->word_ = new CYWord("instanceof"); return tk::InstanceOf;
-"new"        C yylval->word_ = new CYWord("new"); return tk::New;
-"null"       C yylval->null_ = new CYNull(); return tk::Null;
-"return"     R yylval->word_ = new CYWord("return"); return tk::Return;
-"switch"     C yylval->word_ = new CYWord("switch"); return tk::Switch;
-"this"       C yylval->this_ = new CYThis(); return tk::This;
-"throw"      R yylval->word_ = new CYWord("throw"); return tk::Throw;
-"true"       C yylval->true_ = new CYTrue(); return tk::True;
-"try"        C yylval->word_ = new CYWord("try"); return tk::Try;
-"typeof"     C yylval->word_ = new CYWord("typeof"); return tk::TypeOf;
-"var"        C yylval->word_ = new CYWord("var"); return tk::Var;
-"void"       C yylval->word_ = new CYWord("void"); return tk::Void;
-"while"      C yylval->word_ = new CYWord("while"); return tk::While;
-"with"       C yylval->word_ = new CYWord("with"); return tk::With;
-
-[a-zA-Z$_][a-zA-Z$_0-9]* yylval->identifier_ = new CYIdentifier(apr_pstrmemdup(yyextra->pool_, yytext, yyleng)); C return tk::Identifier;
-
-(\.[0-9]+|(0|[1-9][0-9]*)(\.[0-9]*)?){Exponent}? yylval->number_ = new CYNumber(strtod(yytext, NULL)); C return tk::NumericLiteral;
-
-0[xX][0-9a-fA-F]+ C yylval->number_ = new CYNumber(strtoull(yytext + 2, NULL, 16)); return tk::NumericLiteral;
-
-0[bB][0-1]+ C yylval->number_ = new CYNumber(strtoull(yytext + 2, NULL, 2)); return tk::NumericLiteral;
-
-\"([^"\\\n]|{Escape})*\" C return tk::StringLiteral;
-'([^'\\\n]|{Escape})*' C return tk::StringLiteral;
-
-\n N
-[ \t] ;
+"&"    L C return tk::Ampersand;
+"&&"   L C return tk::AmpersandAmpersand;
+"&="   L C return tk::AmpersandEqual;
+"^"    L C return tk::Carrot;
+"^="   L C return tk::CarrotEqual;
+"="    L C return tk::Equal;
+"=="   L C return tk::EqualEqual;
+"==="  L C return tk::EqualEqualEqual;
+"!"    L C return tk::Exclamation;
+"!="   L C return tk::ExclamationEqual;
+"!=="  L C return tk::ExclamationEqualEqual;
+"-"    L C return tk::Hyphen;
+"-="   L C return tk::HyphenEqual;
+"--"   L C return yylval->newline_ ? tk::HyphenHyphen_ : tk::HyphenHyphen;
+"->"   L C return tk::HyphenRight;
+"<"    L C return tk::Left;
+"<="   L C return tk::LeftEqual;
+"<<"   L C return tk::LeftLeft;
+"<<="  L C return tk::LeftLeftEqual;
+"%"    L C return tk::Percent;
+"%="   L C return tk::PercentEqual;
+"."    L C return tk::Period;
+"|"    L C return tk::Pipe;
+"|="   L C return tk::PipeEqual;
+"||"   L C return tk::PipePipe;
+"+"    L C return tk::Plus;
+"+="   L C return tk::PlusEqual;
+"++"   L C return yylval->newline_ ? tk::PlusPlus_ : tk::PlusPlus;
+">"    L C return tk::Right;
+">="   L C return tk::RightEqual;
+">>"   L C return tk::RightRight;
+">>="  L C return tk::RightRightEqual;
+">>>"  L C return tk::RightRightRight;
+">>>=" L C return tk::RightRightRightEqual;
+"/"    L C return tk::Slash;
+"/="   L C return tk::SlashEqual;
+"*"    L C return tk::Star;
+"*="   L C return tk::StarEqual;
+"~"    L C return tk::Tilde;
+
+":"    L C return tk::Colon;
+","    L C return tk::Comma;
+"?"    L C return tk::Question;
+";"    L C return tk::SemiColon;
+
+"("    L C return tk::OpenParen;
+")"    L C return tk::CloseParen;
+
+"{"    L C return tk::OpenBrace;
+"}"    L C return tk::CloseBrace;
+
+"["    L C return tk::OpenBracket;
+"]"    L C return tk::CloseBracket;
+
+"@selector"  L C return tk::AtSelector;
+
+"break"      L R yylval->word_ = new CYWord("break"); return tk::Break;
+"case"       L C yylval->word_ = new CYWord("case"); return tk::Case;
+"catch"      L C yylval->word_ = new CYWord("catch"); return tk::Catch;
+"continue"   L R yylval->word_ = new CYWord("continue"); return tk::Continue;
+"default"    L C yylval->word_ = new CYWord("default"); return tk::Default;
+"delete"     L C yylval->word_ = new CYWord("delete"); return tk::Delete;
+"do"         L C yylval->word_ = new CYWord("do"); return tk::Do;
+"else"       L C yylval->word_ = new CYWord("else"); return tk::Else;
+"false"      L C yylval->false_ = new CYFalse(); return tk::False;
+"finally"    L C yylval->word_ = new CYWord("finally"); return tk::Finally;
+"for"        L C yylval->word_ = new CYWord("for"); return tk::For;
+"function"   L C yylval->word_ = new CYWord("function"); return tk::Function;
+"if"         L C yylval->word_ = new CYWord("if"); return tk::If;
+"in"         L C yylval->word_ = new CYWord("in"); return tk::In;
+"instanceof" L C yylval->word_ = new CYWord("instanceof"); return tk::InstanceOf;
+"new"        L C yylval->word_ = new CYWord("new"); return tk::New;
+"null"       L C yylval->null_ = new CYNull(); return tk::Null;
+"return"     L R yylval->word_ = new CYWord("return"); return tk::Return;
+"switch"     L C yylval->word_ = new CYWord("switch"); return tk::Switch;
+"this"       L C yylval->this_ = new CYThis(); return tk::This;
+"throw"      L R yylval->word_ = new CYWord("throw"); return tk::Throw;
+"true"       L C yylval->true_ = new CYTrue(); return tk::True;
+"try"        L C yylval->word_ = new CYWord("try"); return tk::Try;
+"typeof"     L C yylval->word_ = new CYWord("typeof"); return tk::TypeOf;
+"var"        L C yylval->word_ = new CYWord("var"); return tk::Var;
+"void"       L C yylval->word_ = new CYWord("void"); return tk::Void;
+"while"      L C yylval->word_ = new CYWord("while"); return tk::While;
+"with"       L C yylval->word_ = new CYWord("with"); return tk::With;
+
+[a-zA-Z$_][a-zA-Z$_0-9]* yylval->identifier_ = new CYIdentifier(apr_pstrmemdup(yyextra->pool_, yytext, yyleng)); L C return tk::Identifier;
+
+(\.[0-9]+|(0|[1-9][0-9]*)(\.[0-9]*)?){Exponent}? yylval->number_ = new CYNumber(strtod(yytext, NULL)); L C return tk::NumericLiteral;
+
+0[xX][0-9a-fA-F]+ L C yylval->number_ = new CYNumber(strtoull(yytext + 2, NULL, 16)); return tk::NumericLiteral;
+
+0[bB][0-1]+ L C yylval->number_ = new CYNumber(strtoull(yytext + 2, NULL, 2)); return tk::NumericLiteral;
+
+\"([^"\\\n]|{Escape})*\" L C return tk::StringLiteral;
+'([^'\\\n]|{Escape})*' L C return tk::StringLiteral;
+
+\n yylloc->end.lines(); yylloc->step(); N
+
+[ \t] L
+<<EOF>> L yyterminate();
 
 %%
 
 
 %type <clause_> DefaultClause
 %type <statement_> DoWhileStatement
 %type <expression_> Element
+%type <expression_> ElementOpt
 %type <element_> ElementList
-%type <element_> ElementList_
+%type <element_> ElementListOpt
 %type <statement_> ElseStatementOpt
 %type <statement_> EmptyStatement
 %type <expression_> EqualityExpression
 TerminatorOpt
     : ";"
     | "\n"
-    | error { yyerrok; }
+    | error { yyerrok; driver.errors_.pop_back(); }
     ;
 
 Terminator
     : ";"
     | "\n"
-    | error { if (yychar != 0 && yychar != cy::parser::token::CloseBrace && !yylval.newline_) YYABORT; else yyerrok; }
+    | error { if (yychar != 0 && yychar != cy::parser::token::CloseBrace && !yylval.newline_) YYABORT; else { yyerrok; driver.errors_.pop_back(); } }
     ;
 
 CommaOpt
 /* }}} */
 /* 11.1.4 Array Initialiser {{{ */
 ArrayLiteral
-    : "[" ElementList "]" { $$ = $2; }
+    : "[" ElementList "]" { $$ = new(driver.pool_) CYArray($2); }
     ;
 
 Element
     : AssignmentExpression { $$ = $1; }
+    ;
+
+ElementOpt
+    : Element { $$ = $1; }
     | { $$ = NULL; }
     ;
 
-ElementList_
-    : "," ElementList { $$ = $2; }
+ElementListOpt
+    : ElementList { $$ = $1; }
     | { $$ = NULL; }
     ;
 
 ElementList
-    : Element ElementList_ { $$ = new(driver.pool_) CYElement($1, $2); }
+    : ElementOpt "," ElementListOpt { $$ = new(driver.pool_) CYElement($1, $3); }
+    | Element { $$ = new(driver.pool_) CYElement($1, NULL); }
     ;
 /* }}} */
 /* 11.1.5 Object Initialiser {{{ */
 ObjectLiteral
-    : "{" PropertyNameAndValueListOpt "}" { $$ = new CYObject($2); }
+    : "{" PropertyNameAndValueListOpt "}" { $$ = new(driver.pool_) CYObject($2); }
     ;
 
 PropertyNameAndValueList_
     ;
 
 Block
-    : "{" "}" { $$ = new(driver.pool_) CYEmpty(); }
-    | "{" StatementList "}" { $$ = $2; }
+    : "{" StatementListOpt "}" { $$ = $2 ?: new(driver.pool_) CYEmpty(); }
     ;
 
 StatementList
     ;
 
 Program
-    : SourceElements { driver.source_.push_back($1); $$ = $1; }
+    : SourceElements { driver.source_ = $1; }
     ;
 
 SourceElements
     | { $$ = NULL; }
     ;
 
-/*Command
-    : SourceElement { driver.source_.push_back($2); if (driver.filename_.empty() && false) YYACCEPT; $2->Show(std::cout); }
-    ;*/
-
 SourceElement
     : Statement { $$ = $1; }
     | FunctionDeclaration { $$ = $1; }
     ;
 
 SelectorExpression_
-    : WordOpt ":" SelectorExpressionOpt { $$ = new CYSelector($1, true, $3); }
+    : WordOpt ":" SelectorExpressionOpt { $$ = new(driver.pool_) CYSelector($1, true, $3); }
     ;
 
 SelectorExpression
     : SelectorExpression_ { $$ = $1; }
-    | Word { $$ = new CYSelector($1, false, NULL); }
+    | Word { $$ = new(driver.pool_) CYSelector($1, false, NULL); }
     ;
 
 PrimaryExpression_
 
     ScannerDestroy();
 }
 
-void CYDriver::Clear() {
-    pool_.Clear();
-    state_ = CYClear;
-    data_ = NULL;
-    size_ = 0;
-    source_.clear();
-}
-
-void cy::parser::error(const cy::parser::location_type &loc, const std::string &msg) {
-    std::cerr << loc << ": " << msg << std::endl;
+void cy::parser::error(const cy::parser::location_type &location, const std::string &message) {
+    CYDriver::Error error;
+    error.location_ = location;
+    error.message_ = message;
+    driver.errors_.push_back(error);
 }
 
 void CYConsole(FILE *fin, FILE *fout, FILE *ferr) {
     __gnu_cxx::stdio_filebuf<char> bin(fin, std::ios::in);
     std::istream sin(&bin);
 
-    CYDriver driver("");
-
-    while (!feof(fin)) { _pooled
-        driver.Clear();
-
+    restart: while (!feof(fin)) { _pooled
         fputs("cy# ", fout);
         fflush(fout);
 
-        cy::parser parser(driver);
         std::string command;
+        std::vector<std::string> lines;
+
+      read:
+        if (!std::getline(sin, line))
+            break;
+
+        lines.push_back(line);
+        command += line;
+
+        CYDriver driver("");
+        cy::parser parser(driver);
+
+        driver.data_ = command.c_str();
+        driver.size_ = command.size();
+
+        if (parser.parse() != 0) {
+            for (CYDriver::Errors::const_iterator i(driver.errors_.begin()); i != driver.errors_.end(); ++i) {
+                cy::position begin(i->location_.begin);
+                if (begin.line != lines.size() || begin.column - 1 != lines.back().size()) {
+                    std::cerr << i->message_ << std::endl;
+                    goto restart;
+                }
+            }
+
+            driver.errors_.clear();
 
-        for (;;) {
-            if (!std::getline(sin, line))
-                return;
-            command += line;
-            driver.data_ = command.c_str();
-            driver.size_ = command.size();
-            if (parser.parse() == 0)
-                break;
             fputs("cy> ", fout);
             fflush(fout);
-        }
 
-        for (std::vector<CYSource *>::const_iterator i(driver.source_.begin()); i != driver.source_.end(); ++i) {
-            CYSource *source(*i);
+            command += '\n';
+            goto read;
+        }
 
-            std::ostringstream str;
-            source->Show(str);
+        if (driver.source_ == NULL)
+            goto restart;
 
-            std::string code(str.str());
-            std::cout << code << std::endl;
+        std::ostringstream str;
+        driver.source_->Show(str);
 
-            JSStringRef script(JSStringCreateWithUTF8CString(code.c_str()));
+        std::string code(str.str());
+        std::cout << code << std::endl;
 
-            JSContextRef context(JSGetContext());
+        JSStringRef script(JSStringCreateWithUTF8CString(code.c_str()));
 
-            JSValueRef exception(NULL);
-            JSValueRef result(JSEvaluateScript(context, script, NULL, NULL, 0, &exception));
-            JSStringRelease(script);
+        JSContextRef context(JSGetContext());
 
-            if (exception != NULL)
-                result = exception;
+        JSValueRef exception(NULL);
+        JSValueRef result(JSEvaluateScript(context, script, NULL, NULL, 0, &exception));
+        JSStringRelease(script);
 
-            if (!JSValueIsUndefined(context, result)) {
-                CFStringRef json;
+        if (exception != NULL)
+            result = exception;
 
-                @try { json:
-                    json = JSValueToJSONCopy(context, result);
-                } @catch (id error) {
-                    CYThrow(context, error, &result);
-                    goto json;
-                }
+        if (JSValueIsUndefined(context, result))
+            goto restart;
 
-                fputs([reinterpret_cast<const NSString *>(json) UTF8String], fout);
-                CFRelease(json);
+        CFStringRef json;
 
-                fputs("\n", fout);
-                fflush(fout);
-            }
+        @try { json:
+            json = JSValueToJSONCopy(context, result);
+        } @catch (id error) {
+            CYThrow(context, error, &result);
+            goto json;
         }
+
+        fputs([reinterpret_cast<const NSString *>(json) UTF8String], fout);
+        CFRelease(json);
+
+        fputs("\n", fout);
+        fflush(fout);
     }
+
+    fputs("\n", fout);
+    fflush(fout);
 }
 
 MSInitialize { _pooled