1/*******************************************************************************
2 * Copyright (c) 2009, 2017 Mountainminds GmbH & Co. KG and Contributors
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 *    Marc R. Hoffmann - initial API and implementation
10 *
11 *******************************************************************************/
12package org.jacoco.examples.parser;
13
14import static java.io.StreamTokenizer.TT_EOF;
15import static java.io.StreamTokenizer.TT_NUMBER;
16
17import java.io.IOException;
18import java.io.StreamTokenizer;
19import java.io.StringReader;
20
21import org.jacoco.examples.expressions.Add;
22import org.jacoco.examples.expressions.Const;
23import org.jacoco.examples.expressions.Div;
24import org.jacoco.examples.expressions.IExpression;
25import org.jacoco.examples.expressions.Mul;
26import org.jacoco.examples.expressions.Sub;
27
28public class ExpressionParser {
29
30	private final StreamTokenizer tokenizer;
31
32	public ExpressionParser(final String s) throws IOException {
33		tokenizer = new StreamTokenizer(new StringReader(s));
34		tokenizer.ordinaryChar('(');
35		tokenizer.ordinaryChar(')');
36		tokenizer.ordinaryChar('+');
37		tokenizer.ordinaryChar('-');
38		tokenizer.ordinaryChar('*');
39		tokenizer.ordinaryChar('/');
40	}
41
42	public IExpression parse() throws IOException {
43		tokenizer.nextToken();
44		final IExpression e = term();
45		expect(TT_EOF);
46		return e;
47	}
48
49	private IExpression term() throws IOException {
50		IExpression e = product();
51		while (true) {
52			if (accept('+')) {
53				e = new Add(e, product());
54			} else if (accept('-')) {
55				e = new Sub(e, product());
56			} else {
57				return e;
58			}
59		}
60	}
61
62	private IExpression product() throws IOException {
63		IExpression e = factor();
64		while (true) {
65			if (accept('*')) {
66				e = new Mul(e, factor());
67			} else if (accept('/')) {
68				e = new Div(e, factor());
69			} else {
70				return e;
71			}
72		}
73	}
74
75	private IExpression factor() throws IOException {
76		final IExpression e;
77		if (accept('(')) {
78			e = term();
79			expect(')');
80		} else {
81			expect(TT_NUMBER);
82			e = new Const(tokenizer.nval);
83		}
84		return e;
85	}
86
87	private boolean accept(final int type) throws IOException {
88		if (tokenizer.ttype == type) {
89			tokenizer.nextToken();
90			return true;
91		}
92		return false;
93	}
94
95	private void expect(final int type) throws IOException {
96		if (tokenizer.ttype != type) {
97			throw new IOException("Invalid Syntax.");
98		}
99		tokenizer.nextToken();
100	}
101
102}
103