Index: uspace/app/sbi/src/parse.c
===================================================================
--- uspace/app/sbi/src/parse.c	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
+++ uspace/app/sbi/src/parse.c	(revision a95310e6c21b65da8082d89519635d2b9cf8168c)
@@ -84,4 +84,8 @@
 	parse->cur_mod = parse->program->module;
 	parse->lex = lex;
+
+	parse->error = b_false;
+	parse->error_bailout = b_false;
+
 	lex_next(parse->lex);
 }
@@ -93,5 +97,5 @@
 	stree_modm_t *modm;
 
-	while (lcur_lc(parse) != lc_eof) {
+	while (lcur_lc(parse) != lc_eof && !parse_is_error(parse)) {
 		switch (lcur_lc(parse)) {
 		case lc_class:
@@ -155,5 +159,5 @@
 
 	/* Parse class, struct or interface members. */
-	while (lcur_lc(parse) != lc_end) {
+	while (lcur_lc(parse) != lc_end && !parse_is_error(parse)) {
 		csimbr = parse_csimbr(parse, csi);
 		list_append(&csi->members, csimbr);
@@ -235,5 +239,5 @@
 
 		/* Parse formal parameters. */
-		while (b_true) {
+		while (!parse_is_error(parse)) {
 			arg = parse_proc_arg(parse);
 
@@ -264,5 +268,5 @@
 
 	/* Parse attributes. */
-	while (lcur_lc(parse) == lc_comma) {
+	while (lcur_lc(parse) == lc_comma && !parse_is_error(parse)) {
 		lskip(parse);
 		attr = parse_symbol_attr(parse);
@@ -281,5 +285,5 @@
 			symbol_print_fqn(symbol);
 			printf("' has no body.\n");
-			exit(1);
+			parse_note_error(parse);
 		}
 		fun->proc->body = NULL;
@@ -345,5 +349,5 @@
 
 		/* Parse formal parameters. */
-		while (b_true) {
+		while (!parse_is_error(parse)) {
 			arg = parse_proc_arg(parse);
 			if (stree_arg_has_attr(arg, aac_packed)) {
@@ -370,5 +374,5 @@
 	lmatch(parse, lc_is);
 
-	while (lcur_lc(parse) != lc_end) {
+	while (lcur_lc(parse) != lc_end && !parse_is_error(parse)) {
 		switch (lcur_lc(parse)) {
 		case lc_get:
@@ -377,5 +381,8 @@
 			if (prop->getter != NULL) {
 				printf("Error: Duplicate getter.\n");
-				exit(1);
+				(void) parse_block(parse); /* XXX Free */
+				lmatch(parse, lc_end);
+				parse_note_error(parse);
+				break;
 			}
 
@@ -395,5 +402,7 @@
 			if (prop->setter != NULL) {
 				printf("Error: Duplicate setter.\n");
-				exit(1);
+				(void) parse_block(parse); /* XXX Free */
+				lmatch(parse, lc_end);
+				parse_note_error(parse);
 			}
 
@@ -424,5 +433,5 @@
 		lem_print(lcur(parse));
 		printf("'.\n");
-		exit(1);
+		parse_note_error(parse);
 	}
 
@@ -447,5 +456,5 @@
 
 	/* Parse attributes. */
-	while (lcur_lc(parse) == lc_comma) {
+	while (lcur_lc(parse) == lc_comma && !parse_is_error(parse)) {
 		lskip(parse);
 		attr = parse_arg_attr(parse);
@@ -468,5 +477,5 @@
 		lem_print(lcur(parse));
 		printf("'.\n");
-		exit(1);
+		parse_note_error(parse);
 	}
 
@@ -486,5 +495,11 @@
 	list_init(&block->stats);
 
-	while (terminates_block(lcur_lc(parse)) != b_true) {
+	/* Avoid peeking if there is an error condition. */
+	if (parse_is_error(parse))
+		return block;
+
+	while (terminates_block(lcur_lc(parse)) != b_true &&
+	    !parse_is_error(parse)) {
+
 		stat = parse_stat(parse);
 		list_append(&block->stats, stat);
@@ -508,4 +523,7 @@
 	stree_exps_t *exp_s;
 
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parse statement.\n");
+#endif
 	switch (lcur_lc(parse)) {
 	case lc_var:
@@ -590,4 +608,7 @@
 	stree_if_t *if_s;
 
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parse 'if' statement.\n");
+#endif
 	if_s = stree_if_new();
 
@@ -613,4 +634,7 @@
 	stree_while_t *while_s;
 
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parse 'while' statement.\n");
+#endif
 	while_s = stree_while_new();
 
@@ -629,4 +653,7 @@
 	stree_for_t *for_s;
 
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parse 'for' statement.\n");
+#endif
 	for_s = stree_for_new();
 
@@ -649,4 +676,7 @@
 	stree_raise_t *raise_s;
 
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parse 'raise' statement.\n");
+#endif
 	raise_s = stree_raise_new();
 	lmatch(parse, lc_raise);
@@ -662,4 +692,7 @@
 	stree_return_t *return_s;
 
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parse 'return' statement.\n");
+#endif
 	return_s = stree_return_new();
 
@@ -677,4 +710,7 @@
 	stree_except_t *except_c;
 
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parse WEF statement.\n");
+#endif
 	wef_s = stree_wef_new();
 	list_init(&wef_s->except_clauses);
@@ -692,5 +728,5 @@
 	wef_s->with_block = parse_block(parse);
 
-	while (lcur_lc(parse) == lc_except) {
+	while (lcur_lc(parse) == lc_except && !parse_is_error(parse)) {
 		except_c = parse_except(parse);
 		list_append(&wef_s->except_clauses, except_c);
@@ -716,4 +752,7 @@
 	stree_exps_t *exps;
 
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parse expression statement.\n");
+#endif
 	expr = parse_expr(parse);
 	lmatch(parse, lc_scolon);
@@ -730,4 +769,7 @@
 	stree_except_t *except_c;
 
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parse 'except' statement.\n");
+#endif
 	except_c = stree_except_new();
 
@@ -748,4 +790,7 @@
 	stree_ident_t *ident;
 
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parse identifier.\n");
+#endif
 	lcheck(parse, lc_ident);
 	ident = stree_ident_new();
@@ -756,7 +801,41 @@
 }
 
+/** Signal a parse error, start bailing out from parser. */
+void parse_raise_error(parse_t *parse)
+{
+	parse->error = b_true;
+	parse->error_bailout = b_true;
+}
+
+/** Note a parse error that has been immediately recovered. */
+void parse_note_error(parse_t *parse)
+{
+	parse->error = b_true;
+}
+
+/** Check if we are currently bailing out of parser due to a parse error. */
+bool_t parse_is_error(parse_t *parse)
+{
+	return parse->error_bailout;
+}
+
+/** Recover from parse error bailout.
+ *
+ * Still remember that there was an error, but stop bailing out.
+ */
+void parse_recover_error(parse_t *parse)
+{
+	assert(parse->error == b_true);
+	assert(parse->error_bailout == b_true);
+
+	parse->error_bailout = b_false;
+}
+
 /** Return current lem. */
 lem_t *lcur(parse_t *parse)
 {
+#ifdef DEBUG_LPARSE_TRACE
+	printf("lcur()\n");
+#endif
 	return lex_get_current(parse->lex);
 }
@@ -767,4 +846,15 @@
 	lem_t *lem;
 
+	/*
+	 * This allows us to skip error checking in many places. If there is an
+	 * active error, lcur_lc() returns lc_invalid without reading input.
+	 *
+	 * Without this measure we would have to check for error all the time
+	 * or risk requiring extra input from the user (in interactive mode)
+	 * before actually bailing out from the parser.
+	 */
+	if (parse_is_error(parse))
+		return lc_invalid;
+
 	lem = lcur(parse);
 	return lem->lclass;
@@ -774,4 +864,7 @@
 void lskip(parse_t *parse)
 {
+#ifdef DEBUG_LPARSE_TRACE
+	printf("lskip()\n");
+#endif
 	lex_next(parse->lex);
 }
@@ -780,4 +873,9 @@
 void lcheck(parse_t *parse, lclass_t lc)
 {
+#ifdef DEBUG_LPARSE_TRACE
+	printf("lcheck(");
+	lclass_print(lc);
+	printf(")\n");
+#endif
 	if (lcur(parse)->lclass != lc) {
 		lem_print_coords(lcur(parse));
@@ -785,5 +883,5 @@
 		printf("', got '"); lem_print(lcur(parse));
 		printf("'.\n");
-		exit(1);
+		parse_raise_error(parse);
 	}
 }
@@ -792,4 +890,20 @@
 void lmatch(parse_t *parse, lclass_t lc)
 {
+#ifdef DEBUG_LPARSE_TRACE
+	printf("lmatch(");
+	lclass_print(lc);
+	printf(")\n");
+#endif
+	/*
+	 * This allows us to skip error checking in many places. If there is an
+	 * active error, lmatch() does nothing (similar to parse_block(), etc.
+	 *
+	 * Without this measure we would have to check for error all the time
+	 * or risk requiring extra input from the user (in interactive mode)
+	 * before actually bailing out from the parser.
+	 */
+	if (parse_is_error(parse))
+		return;
+
 	lcheck(parse, lc);
 	lskip(parse);
@@ -803,5 +917,5 @@
 	lem_print(lcur(parse));
 	printf("'.\n");
-	exit(1);
+	parse_raise_error(parse);
 }
 
