Crossfire JXClient, Trunk
ExpressionParser.java
Go to the documentation of this file.
1 /*
2  * This file is part of JXClient, the Fullscreen Java Crossfire Client.
3  *
4  * JXClient is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * JXClient is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with JXClient; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17  *
18  * Copyright (C) 2005-2008 Yann Chachkoff
19  * Copyright (C) 2006-2017,2019-2023 Andreas Kirschbaum
20  * Copyright (C) 2010-2012,2014-2018,2020-2023 Nicolas Weeger
21  */
22 
23 package com.realtime.crossfire.jxclient.skin.io;
24 
26 import java.io.IOException;
27 import java.util.regex.Matcher;
28 import java.util.regex.Pattern;
29 import org.jetbrains.annotations.NotNull;
30 
35 public class ExpressionParser {
36 
40  @NotNull
41  private static final Pattern PATTERN_EXPR = Pattern.compile("(.+?) *([+-]) *(.+)");
42 
46  @NotNull
47  private static final Pattern PATTERN_TERM1 = Pattern.compile("([0-9.]+) *[*] *([A-Z_]+)");
48 
52  @NotNull
53  private static final Pattern PATTERN_TERM2 = Pattern.compile("([A-Z_]+) *[*] *([0-9.]+)");
54 
58  private ExpressionParser() {
59  }
60 
68  public static int parseInt(@NotNull final String str) throws IOException {
69  return parseExpression(str).evaluateConstant();
70  }
71 
79  @NotNull
80  public static Expression parseExpression(@NotNull final String str) throws IOException {
81  Matcher matcherExpr = PATTERN_EXPR.matcher(str);
82  if (!matcherExpr.matches()) {
83  return parseTerm(str);
84  }
85 
86  Expression expr = parseTerm(matcherExpr.group(1));
87  while (true) {
88  final boolean negative = switch (matcherExpr.group(2)) {
89  case "+" -> false;
90  case "-" -> true;
91  default -> throw new AssertionError("unrecognized operator: "+matcherExpr.group(2));
92  };
93 
94  final Matcher matcherExpr2 = PATTERN_EXPR.matcher(matcherExpr.group(3));
95  if (!matcherExpr2.matches()) {
96  return new Expression(expr, negative, parseTerm(matcherExpr.group(3)));
97  }
98 
99  matcherExpr = matcherExpr2;
100  expr = new Expression(expr, negative, parseTerm(matcherExpr.group(1)));
101  }
102  }
103 
110  @NotNull
111  private static Expression parseTerm(@NotNull final String str) throws IOException {
112  try {
113  return new Expression(Integer.parseInt(str), 0, 0, 0, 0);
114  } catch (final NumberFormatException ignored) {
115  }
116 
117  switch (str) {
118  case "WIDTH":
119  return new Expression(0, 1, 0, 0, 0);
120 
121  case "HEIGHT":
122  return new Expression(0, 0, 1, 0, 0);
123 
124  case "PREF_WIDTH":
125  return new Expression(0, 0, 0, 1, 0);
126 
127  case "PREF_HEIGHT":
128  return new Expression(0, 0, 0, 0, 1);
129 
130  case "WIDTH/2":
131  return new Expression(0, 0.5F, 0, 0, 0);
132 
133  case "HEIGHT/2":
134  return new Expression(0, 0, 0.5F, 0, 0);
135 
136  case "PREF_WIDTH/2":
137  return new Expression(0, 0, 0, 0.5F, 0);
138 
139  case "PREF_HEIGHT/2":
140  return new Expression(0, 0, 0, 0, 0.5F);
141  }
142 
143  final Matcher matcherTerm1 = PATTERN_TERM1.matcher(str);
144  if (matcherTerm1.matches()) {
145  return parseTerm(matcherTerm1.group(1), matcherTerm1.group(2));
146  }
147 
148  final Matcher matcherTerm2 = PATTERN_TERM2.matcher(str);
149  if (matcherTerm2.matches()) {
150  return parseTerm(matcherTerm2.group(2), matcherTerm2.group(1));
151  }
152 
153  throw new IOException("syntax error in '"+str+"'");
154  }
155 
164  @NotNull
165  private static Expression parseTerm(@NotNull final String factor, @NotNull final String constant) throws IOException {
166  final float factor2;
167  try {
168  factor2 = Float.parseFloat(factor);
169  } catch (final NumberFormatException ex) {
170  throw new IOException("invalid value '"+factor+"'", ex);
171  }
172 
173  switch (constant) {
174  case "WIDTH":
175  return new Expression(0, factor2, 0, 0, 0);
176 
177  case "HEIGHT":
178  return new Expression(0, 0, factor2, 0, 0);
179 
180  case "PREF_WIDTH":
181  return new Expression(0, 0, 0, factor2, 0);
182 
183  case "PREF_HEIGHT":
184  return new Expression(0, 0, 0, 0, factor2);
185  }
186 
187  throw new IOException("invalid constant '"+constant+"'");
188  }
189 
190 }
com.realtime.crossfire.jxclient.skin.io.ExpressionParser.PATTERN_TERM1
static final Pattern PATTERN_TERM1
Pattern that matches a simple term.
Definition: ExpressionParser.java:47
com.realtime.crossfire.jxclient
com.realtime.crossfire.jxclient.skin.io.ExpressionParser.ExpressionParser
ExpressionParser()
Private constructor to prevent instantiation.
Definition: ExpressionParser.java:58
com.realtime.crossfire.jxclient.skin.io.ExpressionParser.parseExpression
static Expression parseExpression(@NotNull final String str)
Parses an integer constant.
Definition: ExpressionParser.java:80
com.realtime.crossfire.jxclient.skin.io.ExpressionParser.parseInt
static int parseInt(@NotNull final String str)
Parses an integer constant.
Definition: ExpressionParser.java:68
com.realtime.crossfire.jxclient.gui.gui.Expression
An expression yielding an integer value derived from a screen resolution.
Definition: Expression.java:31
com.realtime.crossfire.jxclient.skin.io.ExpressionParser.parseTerm
static Expression parseTerm(@NotNull final String str)
Parses a term which contains no operators.
Definition: ExpressionParser.java:111
com.realtime.crossfire.jxclient.skin.io.ExpressionParser
Parser for integer expressions.
Definition: ExpressionParser.java:35
com.realtime.crossfire.jxclient.skin.io.ExpressionParser.PATTERN_TERM2
static final Pattern PATTERN_TERM2
Pattern that matches a simple term.
Definition: ExpressionParser.java:53
com.realtime.crossfire.jxclient.gui
com.realtime.crossfire.jxclient.skin.io.ExpressionParser.PATTERN_EXPR
static final Pattern PATTERN_EXPR
Pattern that matches an expression consisting of multiple terms.
Definition: ExpressionParser.java:41
com.realtime.crossfire.jxclient.gui.gui
Definition: AbstractGUIElement.java:23
com.realtime.crossfire
com.realtime.crossfire.jxclient.gui.gui.Expression.evaluateConstant
int evaluateConstant()
Evaluates the expression into a constant.
Definition: Expression.java:106
com.realtime
com
com.realtime.crossfire.jxclient.skin.io.ExpressionParser.parseTerm
static Expression parseTerm(@NotNull final String factor, @NotNull final String constant)
Constructs an Expression consisting of a factor which is applied to a named constant.
Definition: ExpressionParser.java:165