Index: uspace/app/sbi/src/parse.c
===================================================================
--- uspace/app/sbi/src/parse.c	(revision 38aaacc20a85af2361a0240ac2e7d643e086ecfa)
+++ uspace/app/sbi/src/parse.c	(revision 640ffe664a867642b35d372f9cf26c5898381793)
@@ -48,9 +48,14 @@
 
 /*
- * Module members
+ * Module and CSI members
  */
 static stree_csi_t *parse_csi(parse_t *parse, lclass_t dclass,
     stree_csi_t *outer_csi);
 static stree_csimbr_t *parse_csimbr(parse_t *parse, stree_csi_t *outer_csi);
+
+static stree_ctor_t *parse_ctor(parse_t *parse, stree_csi_t *outer_csi);
+
+static stree_enum_t *parse_enum(parse_t *parse, stree_csi_t *outer_csi);
+static stree_embr_t *parse_embr(parse_t *parse, stree_enum_t *outer_enum);
 
 static stree_deleg_t *parse_deleg(parse_t *parse, stree_csi_t *outer_csi);
@@ -76,4 +81,5 @@
 static stree_for_t *parse_for(parse_t *parse);
 static stree_raise_t *parse_raise(parse_t *parse);
+static stree_break_t *parse_break(parse_t *parse);
 static stree_return_t *parse_return(parse_t *parse);
 static stree_wef_t *parse_wef(parse_t *parse);
@@ -123,4 +129,5 @@
 {
 	stree_csi_t *csi;
+	stree_enum_t *enum_d;
 	stree_modm_t *modm;
 
@@ -136,4 +143,11 @@
 			list_append(&parse->cur_mod->members, modm);
 			break;
+		case lc_enum:
+			enum_d = parse_enum(parse, NULL);
+			modm = stree_modm_new(mc_enum);
+			modm->u.enum_d = enum_d;
+
+			list_append(&parse->cur_mod->members, modm);
+			break;
 		default:
 			lunexpected_error(parse);
@@ -223,5 +237,5 @@
  *
  * @param parse		Parser object.
- * @param outer_csi	CSI containing this declaration or @c NULL if global.
+ * @param outer_csi	CSI containing this declaration.
  * @return		New syntax tree node. In case of parse error,
  *			@c NULL may (but need not) be returned.
@@ -232,5 +246,7 @@
 
 	stree_csi_t *csi;
+	stree_ctor_t *ctor;
 	stree_deleg_t *deleg;
+	stree_enum_t *enum_d;
 	stree_fun_t *fun;
 	stree_var_t *var;
@@ -245,4 +261,9 @@
 		csimbr->u.csi = csi;
 		break;
+	case lc_new:
+		ctor = parse_ctor(parse, outer_csi);
+		csimbr = stree_csimbr_new(csimbr_ctor);
+		csimbr->u.ctor = ctor;
+		break;
 	case lc_deleg:
 		deleg = parse_deleg(parse, outer_csi);
@@ -250,4 +271,9 @@
 		csimbr->u.deleg = deleg;
 		break;
+	case lc_enum:
+		enum_d = parse_enum(parse, outer_csi);
+		csimbr = stree_csimbr_new(csimbr_enum);
+		csimbr->u.enum_d = enum_d;
+		break;
 	case lc_fun:
 		fun = parse_fun(parse, outer_csi);
@@ -273,4 +299,142 @@
 
 	return csimbr;
+}
+
+/** Parse constructor.
+ *
+ * @param parse		Parser object.
+ * @param outer_csi	CSI containing this declaration or @c NULL if global.
+ * @return		New syntax tree node.
+ */
+static stree_ctor_t *parse_ctor(parse_t *parse, stree_csi_t *outer_csi)
+{
+	stree_ctor_t *ctor;
+	stree_symbol_t *symbol;
+	stree_symbol_attr_t *attr;
+
+	ctor = stree_ctor_new();
+	symbol = stree_symbol_new(sc_ctor);
+
+	symbol->u.ctor = ctor;
+	symbol->outer_csi = outer_csi;
+	ctor->symbol = symbol;
+
+	lmatch(parse, lc_new);
+
+	/* Fake identifier. */
+	ctor->name = stree_ident_new();
+	ctor->name->sid = strtab_get_sid(CTOR_IDENT);
+	ctor->name->cspan = lprev_span(parse);
+
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parsing constructor of CSI '");
+	symbol_print_fqn(csi_to_symbol(outer_csi));
+	printf("'.\n");
+#endif
+	ctor->sig = parse_fun_sig(parse);
+	if (ctor->sig->rtype != NULL) {
+		printf("Error: Constructor of CSI '");
+		symbol_print_fqn(csi_to_symbol(outer_csi));
+		printf("' has a return type.\n");
+		parse_note_error(parse);
+	}
+
+	list_init(&symbol->attr);
+
+	/* Parse attributes. */
+	while (lcur_lc(parse) == lc_comma && !parse_is_error(parse)) {
+		lskip(parse);
+		attr = parse_symbol_attr(parse);
+		list_append(&symbol->attr, attr);
+	}
+
+	ctor->proc = stree_proc_new();
+	ctor->proc->outer_symbol = symbol;
+
+	if (lcur_lc(parse) == lc_scolon) {
+		lskip(parse);
+
+		/* This constructor has no body. */
+		printf("Error: Constructor of CSI '");
+		symbol_print_fqn(csi_to_symbol(outer_csi));
+		printf("' has no body.\n");
+		parse_note_error(parse);
+
+		ctor->proc->body = NULL;
+	} else {
+		lmatch(parse, lc_is);
+		ctor->proc->body = parse_block(parse);
+		lmatch(parse, lc_end);
+	}
+
+	return ctor;
+}
+
+/** Parse @c enum declaration.
+ *
+ * @param parse		Parser object.
+ * @param outer_csi	CSI containing this declaration or @c NULL if global.
+ * @return		New syntax tree node.
+ */
+static stree_enum_t *parse_enum(parse_t *parse, stree_csi_t *outer_csi)
+{
+	stree_enum_t *enum_d;
+	stree_symbol_t *symbol;
+	stree_embr_t *embr;
+
+	enum_d = stree_enum_new();
+	symbol = stree_symbol_new(sc_enum);
+
+	symbol->u.enum_d = enum_d;
+	symbol->outer_csi = outer_csi;
+	enum_d->symbol = symbol;
+
+	lmatch(parse, lc_enum);
+	enum_d->name = parse_ident(parse);
+	list_init(&enum_d->members);
+
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parse enum '%s'.\n", strtab_get_str(enum_d->name->sid));
+#endif
+	lmatch(parse, lc_is);
+
+	/* Parse enum members. */
+	while (lcur_lc(parse) != lc_end && !parse_is_error(parse)) {
+		embr = parse_embr(parse, enum_d);
+		if (embr == NULL)
+			break;
+
+		list_append(&enum_d->members, embr);
+	}
+
+	if (list_is_empty(&enum_d->members)) {
+		printf("Error: Enum type '%s' has no members.\n",
+		    strtab_get_str(enum_d->name->sid));
+		parse_note_error(parse);
+	}
+
+	lmatch(parse, lc_end);
+
+	return enum_d;
+}
+
+/** Parse enum member.
+ *
+ * @param parse		Parser object.
+ * @param outer_enum	Enum containing this declaration.
+ * @return		New syntax tree node. In case of parse error,
+ *			@c NULL may (but need not) be returned.
+ */
+static stree_embr_t *parse_embr(parse_t *parse, stree_enum_t *outer_enum)
+{
+	stree_embr_t *embr;
+
+	embr = stree_embr_new();
+	embr->outer_enum = outer_enum;
+	embr->name = parse_ident(parse);
+
+	lmatch(parse, lc_scolon);
+
+	return embr;
 }
 
@@ -681,4 +845,5 @@
 	stree_for_t *for_s;
 	stree_raise_t *raise_s;
+	stree_break_t *break_s;
 	stree_return_t *return_s;
 	stree_wef_t *wef_s;
@@ -714,4 +879,9 @@
 		stat->u.raise_s = raise_s;
 		break;
+	case lc_break:
+		break_s = parse_break(parse);
+		stat = stree_stat_new(st_break);
+		stat->u.break_s = break_s;
+		break;
 	case lc_return:
 		return_s = parse_return(parse);
@@ -777,4 +947,5 @@
 {
 	stree_if_t *if_s;
+	stree_if_clause_t *if_c;
 
 #ifdef DEBUG_PARSE_TRACE
@@ -782,10 +953,28 @@
 #endif
 	if_s = stree_if_new();
-
+	list_init(&if_s->if_clauses);
+
+	/* Parse @c if clause. */
 	lmatch(parse, lc_if);
-	if_s->cond = parse_expr(parse);
+
+	if_c = stree_if_clause_new();
+	if_c->cond = parse_expr(parse);
 	lmatch(parse, lc_then);
-	if_s->if_block = parse_block(parse);
-
+	if_c->block = parse_block(parse);
+
+	list_append(&if_s->if_clauses, if_c);
+
+	/* Parse @c elif clauses. */
+	while (lcur_lc(parse) == lc_elif) {
+		lskip(parse);
+		if_c = stree_if_clause_new();
+		if_c->cond = parse_expr(parse);
+		lmatch(parse, lc_then);
+		if_c->block = parse_block(parse);
+
+		list_append(&if_s->if_clauses, if_c);
+	}
+
+	/* Parse @c else clause. */
 	if (lcur_lc(parse) == lc_else) {
 		lskip(parse);
@@ -867,4 +1056,24 @@
 }
 
+/** Parse @c break statement.
+ *
+ * @param parse		Parser object.
+ * @return		New syntax tree node.
+ */
+static stree_break_t *parse_break(parse_t *parse)
+{
+	stree_break_t *break_s;
+
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parse 'break' statement.\n");
+#endif
+	break_s = stree_break_new();
+
+	lmatch(parse, lc_break);
+	lmatch(parse, lc_scolon);
+
+	return break_s;
+}
+
 /** Parse @c return statement.
  *
@@ -882,5 +1091,8 @@
 
 	lmatch(parse, lc_return);
-	return_s->expr = parse_expr(parse);
+
+	if (lcur_lc(parse) != lc_scolon)
+		return_s->expr = parse_expr(parse);
+
 	lmatch(parse, lc_scolon);
 
@@ -996,4 +1208,5 @@
 	ident = stree_ident_new();
 	ident->sid = lcur(parse)->u.ident.sid;
+	ident->cspan = lcur_span(parse);
 	lskip(parse);
 
@@ -1059,6 +1272,6 @@
 /** Return current lem lclass.
  *
- * @param parse		Parser object.
- * @return		Lclass of the current lem.
+ * @param parse		Parser object
+ * @return		Lclass of the current lem
  */
 lclass_t lcur_lc(parse_t *parse)
@@ -1081,4 +1294,42 @@
 }
 
+/** Return coordinate span of current lem.
+ *
+ * @param parse		Parser object
+ * @return		Coordinate span of current lem or @c NULL if a
+ *			parse error is active
+ */
+cspan_t *lcur_span(parse_t *parse)
+{
+	lem_t *lem;
+
+	if (parse_is_error(parse))
+		return NULL;
+
+	lem = lcur(parse);
+	return lem->cspan;
+}
+
+/** Return coordinate span of previous lem.
+ *
+ * @param parse		Parser object
+ * @return		Coordinate span of previous lem or @c NULL if
+ * 			parse error is active or previous lem is not
+ *			available.
+ */
+cspan_t *lprev_span(parse_t *parse)
+{
+	lem_t *lem;
+
+	if (parse_is_error(parse))
+		return NULL;
+
+	lem = lex_peek_prev(parse->lex);
+	if (lem == NULL)
+		return NULL;
+
+	return lem->cspan;
+}
+
 /** Skip to next lem.
  *
@@ -1170,4 +1421,5 @@
 {
 	switch (lclass) {
+	case lc_elif:
 	case lc_else:
 	case lc_end:
