714eea8347cf4736d28b904caeb8134ab522b46f — Simon Ser 6 months ago ba9a903
Fix associativity of sums and products

See https://eli.thegreenplace.net/2009/03/14/some-problems-of-recursive-descent-parsers
2 files changed, 43 insertions(+), 34 deletions(-)

M calc.c
M test.sh
M calc.c => calc.c +42 -34
@@ 118,25 118,29 @@ struct ast_node *expect_product(struct parser *parser) {
 		return NULL;
 	}
 
-	char chr = parser_peek_char(parser);
-	switch (chr) {
-	case '*':
-	case '/':
-		parser_read_char(parser);
+	while (1) {
+		char chr = parser_peek_char(parser);
+		switch (chr) {
+		case '*':
+		case '/':
+			parser_read_char(parser);
 
-		struct ast_node *right = expect_product(parser);
-		if (right == NULL) {
-			return NULL;
-		}
+			struct ast_node *right = expect_power(parser);
+			if (right == NULL) {
+				return NULL;
+			}
 
-		struct ast_binop *binop = calloc(1, sizeof(*binop));
-		binop->node.type = AST_BINOP;
-		binop->op = chr;
-		binop->left = n;
-		binop->right = right;
-		return &binop->node;
-	default:
-		return n;
+			struct ast_binop *binop = calloc(1, sizeof(*binop));
+			binop->node.type = AST_BINOP;
+			binop->op = chr;
+			binop->left = n;
+			binop->right = right;
+
+			n = &binop->node;
+			break;
+		default:
+			return n;
+		}
 	}
 }
 


@@ 146,25 150,29 @@ struct ast_node *expect_sum(struct parser *parser) {
 		return NULL;
 	}
 
-	char chr = parser_peek_char(parser);
-	switch (chr) {
-	case '+':
-	case '-':
-		parser_read_char(parser);
+	while (1) {
+		char chr = parser_peek_char(parser);
+		switch (chr) {
+		case '+':
+		case '-':
+			parser_read_char(parser);
 
-		struct ast_node *right = expect_sum(parser);
-		if (right == NULL) {
-			return NULL;
-		}
+			struct ast_node *right = expect_product(parser);
+			if (right == NULL) {
+				return NULL;
+			}
 
-		struct ast_binop *binop = calloc(1, sizeof(*binop));
-		binop->node.type = AST_BINOP;
-		binop->op = chr;
-		binop->left = n;
-		binop->right = right;
-		return &binop->node;
-	default:
-		return n;
+			struct ast_binop *binop = calloc(1, sizeof(*binop));
+			binop->node.type = AST_BINOP;
+			binop->op = chr;
+			binop->left = n;
+			binop->right = right;
+
+			n = &binop->node;
+			break;
+		default:
+			return n;
+		}
 	}
 }
 

M test.sh => test.sh +1 -0
@@ 18,6 18,7 @@ expect() {
 expect "1" 1
 expect "1+1" 2
 expect "1+2+3" 6
+expect "5-1-2" 2
 expect "2*3" 6
 expect "1+2*3" 7
 expect "2*3+1" 7