#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