Implement expression computation by AST in StringCalc

This commit is contained in:
ChronosX88 2021-06-08 18:08:05 +03:00
parent 244099760e
commit d282ea8b8c
Signed by: ChronosXYZ
GPG Key ID: 085A69A82C8C511A
15 changed files with 243 additions and 476 deletions

1
StringCalc/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
out/

View File

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<resourceExtensions />
<wildcardResourcePatterns>
<entry name="!?*.java" />
<entry name="!?*.form" />
<entry name="!?*.class" />
<entry name="!?*.groovy" />
<entry name="!?*.scala" />
<entry name="!?*.flex" />
<entry name="!?*.kt" />
<entry name="!?*.clj" />
<entry name="!?*.aj" />
</wildcardResourcePatterns>
<annotationProcessing>
<profile default="true" name="Default" enabled="false">
<processorPath useClasspath="true" />
</profile>
</annotationProcessing>
</component>
</project>

View File

@ -1,3 +0,0 @@
<component name="CopyrightManager">
<settings default="" />
</component>

View File

@ -1 +0,0 @@
<html>Simple <b>Java</b> application that includes a class with <code>main()</code> method</html>

View File

@ -1,12 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="EntryPointsManager"> <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<entry_points version="2.0" />
</component>
<component name="ProjectKey">
<option name="state" value="project://e2804f05-5315-4fc6-a121-c522a6c26470" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" /> <output url="file://$PROJECT_DIR$/out" />
</component> </component>
</project> </project>

View File

@ -2,7 +2,7 @@
<project version="4"> <project version="4">
<component name="ProjectModuleManager"> <component name="ProjectModuleManager">
<modules> <modules>
<module fileurl="file://$PROJECT_DIR$/UnnamedCalc.iml" filepath="$PROJECT_DIR$/UnnamedCalc.iml" /> <module fileurl="file://$PROJECT_DIR$/StringCalc.iml" filepath="$PROJECT_DIR$/StringCalc.iml" />
</modules> </modules>
</component> </component>
</project> </project>

View File

@ -1,3 +0,0 @@
<template>
<input-field default="com.company">IJ_BASE_PACKAGE</input-field>
</template>

6
StringCalc/.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>

View File

@ -1,240 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="1fea5f5f-b642-434d-a463-71cf57001c3e" name="Default" comment="" /> <list default="true" id="0d7153f8-0e49-471d-a8cf-5d96baa2b39c" name="Default Changelist" comment="">
<ignored path="UnnamedCalc.iws" /> <change afterPath="$PROJECT_DIR$/.idea/vcs.xml" afterDir="false" />
<ignored path=".idea/workspace.xml" /> <change afterPath="$PROJECT_DIR$/src/main/ASTNode.java" afterDir="false" />
<ignored path="$PROJECT_DIR$/out/" /> <change afterPath="$PROJECT_DIR$/src/main/OperatorType.java" afterDir="false" />
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" /> <change afterPath="$PROJECT_DIR$/src/main/Token.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/compiler.xml" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/copyright/profiles_settings.xml" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/description.html" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/misc.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/misc.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/modules.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/modules.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/project-template.xml" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/UnnamedCalc.iml" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/out/production/UnnamedCalc/main/Main.class" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/Main.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/Main.java" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" /> <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" /> <option name="LAST_RESOLUTION" value="IGNORE" />
</component> </component>
<component name="CreatePatchCommitExecutor"> <component name="Git.Settings">
<option name="PATCH_PATH" value="" /> <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/.." />
</component> </component>
<component name="FUSProjectUsageTrigger"> <component name="ProjectId" id="1tfdluWvUlOkVNAQsDv18I2SiD9" />
<session id="928510969"> <component name="ProjectLevelVcsManager" settingsEditedManually="true" />
<usages-collector id="statistics.lifecycle.project"> <component name="ProjectViewState">
<counts> <option name="hideEmptyMiddlePackages" value="true" />
<entry key="project.closed" value="3" /> <option name="showLibraryContents" value="true" />
<entry key="project.open.time.1" value="1" />
<entry key="project.open.time.7" value="1" />
<entry key="project.open.time.9" value="1" />
<entry key="project.opened" value="3" />
</counts>
</usages-collector>
<usages-collector id="statistics.file.extensions.edit">
<counts>
<entry key="java" value="1415" />
</counts>
</usages-collector>
<usages-collector id="statistics.file.types.edit">
<counts>
<entry key="JAVA" value="1415" />
</counts>
</usages-collector>
</session>
</component>
<component name="FavoritesManager">
<favorites_list name="UnnamedCalc" />
</component>
<component name="FileEditorManager">
<leaf />
</component>
<component name="IdeDocumentHistory">
<option name="CHANGED_PATHS">
<list>
<option value="$PROJECT_DIR$/src/main/Main.java" />
</list>
</option>
</component>
<component name="ProjectFrameBounds">
<option name="y" value="28" />
<option name="width" value="1366" />
<option name="height" value="712" />
</component>
<component name="ProjectView">
<navigator proportions="" version="1">
<foldersAlwaysOnTop value="true" />
</navigator>
<panes />
</component> </component>
<component name="PropertiesComponent"> <component name="PropertiesComponent">
<property name="last_opened_file_path" value="$PROJECT_DIR$" /> <property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
</component> <property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
<component name="RunDashboard">
<option name="ruleStates">
<list>
<RuleState>
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
</RuleState>
<RuleState>
<option name="name" value="StatusDashboardGroupingRule" />
</RuleState>
</list>
</option>
</component> </component>
<component name="RunManager"> <component name="RunManager">
<configuration default="true" type="AndroidRunConfigurationType" factoryName="Android Application"> <configuration name="Main" type="Application" factoryName="Application" temporary="true" nameIsGenerated="true">
<module name="" />
<option name="DEPLOY" value="true" />
<option name="ARTIFACT_NAME" value="" />
<option name="PM_INSTALL_OPTIONS" value="" />
<option name="ACTIVITY_EXTRA_FLAGS" value="" />
<option name="MODE" value="default_activity" />
<option name="TARGET_SELECTION_MODE" value="SHOW_DIALOG" />
<option name="PREFERRED_AVD" value="" />
<option name="CLEAR_LOGCAT" value="false" />
<option name="SHOW_LOGCAT_AUTOMATICALLY" value="true" />
<option name="SKIP_NOOP_APK_INSTALLATIONS" value="true" />
<option name="FORCE_STOP_RUNNING_APP" value="true" />
<option name="DEBUGGER_TYPE" value="Java" />
<option name="USE_LAST_SELECTED_DEVICE" value="false" />
<option name="PREFERRED_AVD" value="" />
<Java />
<Profilers>
<option name="GAPID_DISABLE_PCS" value="false" />
</Profilers>
<option name="DEEP_LINK" value="" />
<option name="ACTIVITY_CLASS" value="" />
<method>
<option name="Make" enabled="true" />
<option name="Android.Gradle.BeforeRunTask" enabled="true" />
</method>
</configuration>
<configuration default="true" type="AndroidTestRunConfigurationType" factoryName="Android Tests">
<module name="" />
<option name="TESTING_TYPE" value="0" />
<option name="INSTRUMENTATION_RUNNER_CLASS" value="" />
<option name="METHOD_NAME" value="" />
<option name="CLASS_NAME" value="" />
<option name="PACKAGE_NAME" value="" />
<option name="EXTRA_OPTIONS" value="" />
<option name="TARGET_SELECTION_MODE" value="SHOW_DIALOG" />
<option name="PREFERRED_AVD" value="" />
<option name="CLEAR_LOGCAT" value="false" />
<option name="SHOW_LOGCAT_AUTOMATICALLY" value="true" />
<option name="SKIP_NOOP_APK_INSTALLATIONS" value="true" />
<option name="FORCE_STOP_RUNNING_APP" value="true" />
<option name="DEBUGGER_TYPE" value="Java" />
<option name="USE_LAST_SELECTED_DEVICE" value="false" />
<option name="PREFERRED_AVD" value="" />
<Java />
<Profilers>
<option name="GAPID_DISABLE_PCS" value="false" />
</Profilers>
<method>
<option name="Make" enabled="true" />
<option name="Android.Gradle.BeforeRunTask" enabled="true" />
</method>
</configuration>
<configuration default="true" type="JUnitTestDiscovery" factoryName="JUnit Test Discovery" changeList="All">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<module name="" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PACKAGE_NAME" />
<option name="MAIN_CLASS_NAME" />
<option name="METHOD_NAME" />
<option name="TEST_OBJECT" value="class" />
<option name="VM_PARAMETERS" />
<option name="PARAMETERS" />
<option name="WORKING_DIRECTORY" />
<option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option>
<envs />
<patterns />
<method />
</configuration>
<configuration default="true" type="TestNGTestDiscovery" factoryName="TestNG Test Discovery" changeList="All">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<module name="" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="SUITE_NAME" />
<option name="PACKAGE_NAME" />
<option name="MAIN_CLASS_NAME" />
<option name="METHOD_NAME" />
<option name="GROUP_NAME" />
<option name="TEST_OBJECT" value="CLASS" />
<option name="VM_PARAMETERS" />
<option name="PARAMETERS" />
<option name="WORKING_DIRECTORY" />
<option name="OUTPUT_DIRECTORY" />
<option name="ANNOTATION_TYPE" />
<option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option>
<option name="USE_DEFAULT_REPORTERS" value="false" />
<option name="PROPERTIES_FILE" />
<envs />
<properties />
<listeners />
<method />
</configuration>
<configuration name="Main" type="Application" factoryName="Application" temporary="true">
<option name="MAIN_CLASS_NAME" value="main.Main" /> <option name="MAIN_CLASS_NAME" value="main.Main" />
<module name="UnnamedCalc" /> <module name="StringCalc" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" /> <extension name="coverage">
<RunnerSettings RunnerId="Run" /> <pattern>
<ConfigurationWrapper RunnerId="Run" /> <option name="PATTERN" value="main.*" />
<method v="2"> <option name="ENABLED" value="true" />
<option name="Make" enabled="true" /> </pattern>
</method> </extension>
</configuration>
<configuration default="true" type="JUnit" factoryName="JUnit">
<option name="VM_PARAMETERS" />
<option name="WORKING_DIRECTORY" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
<configuration default="true" type="KotlinStandaloneScriptRunConfigurationType" factoryName="Kotlin script">
<option name="filePath" />
<option name="vmParameters" />
<option name="alternativeJrePath" />
<option name="programParameters" />
<option name="passParentEnvs" value="true" />
<option name="workingDirectory" />
<option name="isAlternativeJrePathEnabled" value="false" />
<option name="VM_PARAMETERS" />
<option name="PROGRAM_PARAMETERS" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="MAIN_CLASS_NAME" />
<option name="WORKING_DIRECTORY" />
<module name="" />
<option name="filePath" />
<option name="vmParameters" />
<option name="alternativeJrePath" />
<option name="programParameters" />
<option name="passParentEnvs" value="true" />
<option name="workingDirectory" />
<option name="isAlternativeJrePathEnabled" value="false" />
<option name="VM_PARAMETERS" />
<option name="PROGRAM_PARAMETERS" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="MAIN_CLASS_NAME" />
<option name="WORKING_DIRECTORY" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
<configuration default="true" type="TestNG" factoryName="TestNG">
<option name="VM_PARAMETERS" />
<option name="WORKING_DIRECTORY" />
<properties />
<listeners />
<method v="2"> <method v="2">
<option name="Make" enabled="true" /> <option name="Make" enabled="true" />
</method> </method>
@ -245,164 +55,15 @@
</list> </list>
</recent_temporary> </recent_temporary>
</component> </component>
<component name="SvnConfiguration"> <component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
<configuration />
</component>
<component name="TaskManager"> <component name="TaskManager">
<task active="true" id="Default" summary="Default task"> <task active="true" id="Default" summary="Default task">
<changelist id="1fea5f5f-b642-434d-a463-71cf57001c3e" name="Default" comment="" /> <changelist id="0d7153f8-0e49-471d-a8cf-5d96baa2b39c" name="Default Changelist" comment="" />
<created>1537276489642</created> <created>1623164231258</created>
<option name="number" value="Default" /> <option name="number" value="Default" />
<option name="presentableId" value="Default" /> <option name="presentableId" value="Default" />
<updated>1537276489642</updated> <updated>1623164231258</updated>
</task> </task>
<servers /> <servers />
</component> </component>
<component name="ToolWindowManager">
<frame x="0" y="28" width="1366" height="712" extended-state="0" />
<layout>
<window_info content_ui="combo" id="Project" order="0" sideWeight="0.488" weight="0.25" />
<window_info id="Structure" order="1" weight="0.25" />
<window_info id="Capture Tool" order="2" />
<window_info id="UI Designer" order="3" />
<window_info id="Palette&#9;" order="4" />
<window_info id="Favorites" order="5" sideWeight="0.512" side_tool="true" weight="0.25" />
<window_info anchor="bottom" id="Message" order="0" />
<window_info anchor="bottom" id="Find" order="1" />
<window_info anchor="bottom" id="Run" order="2" weight="0.3281787" />
<window_info anchor="bottom" id="Debug" order="3" weight="0.39862543" />
<window_info anchor="bottom" id="Cvs" order="4" weight="0.25" />
<window_info anchor="bottom" id="Inspection" order="5" weight="0.4" />
<window_info anchor="bottom" id="TODO" order="6" />
<window_info anchor="bottom" id="Terminal" order="7" />
<window_info anchor="bottom" id="Event Log" order="8" side_tool="true" />
<window_info anchor="bottom" id="Version Control" order="9" show_stripe_button="false" />
<window_info anchor="bottom" id="Messages" order="10" weight="0.3281787" />
<window_info anchor="right" id="Commander" order="0" weight="0.4" />
<window_info anchor="right" id="Ant Build" order="1" weight="0.25" />
<window_info anchor="right" content_ui="combo" id="Hierarchy" order="2" weight="0.25" />
<window_info anchor="right" id="Palette" order="3" />
<window_info anchor="right" id="Capture Analysis" order="4" />
<window_info anchor="right" id="Designer" order="5" />
<window_info anchor="right" id="Maven Projects" order="6" />
</layout>
</component>
<component name="Vcs.Log.UiProperties">
<option name="RECENTLY_FILTERED_USER_GROUPS">
<collection />
</option>
<option name="RECENTLY_FILTERED_BRANCH_GROUPS">
<collection />
</option>
</component>
<component name="VcsContentAnnotationSettings">
<option name="myLimit" value="2678400000" />
</component>
<component name="XDebuggerManager">
<breakpoint-manager>
<breakpoints>
<line-breakpoint enabled="true" type="java-line">
<url>file://$PROJECT_DIR$/src/main/Main.java</url>
<line>25</line>
<properties />
<option name="timeStamp" value="38" />
</line-breakpoint>
<line-breakpoint enabled="true" type="java-line">
<url>file://$PROJECT_DIR$/src/main/Main.java</url>
<line>33</line>
<properties />
<option name="timeStamp" value="39" />
</line-breakpoint>
<line-breakpoint enabled="true" type="java-line">
<url>file://$PROJECT_DIR$/src/main/Main.java</url>
<line>80</line>
<properties />
<option name="timeStamp" value="40" />
</line-breakpoint>
<line-breakpoint enabled="true" type="java-line">
<url>file://$PROJECT_DIR$/src/main/Main.java</url>
<line>53</line>
<properties />
<option name="timeStamp" value="42" />
</line-breakpoint>
<line-breakpoint enabled="true" type="java-line">
<url>file://$PROJECT_DIR$/src/main/Main.java</url>
<line>54</line>
<properties />
<option name="timeStamp" value="43" />
</line-breakpoint>
<line-breakpoint enabled="true" type="java-line">
<url>file://$PROJECT_DIR$/src/main/Main.java</url>
<line>55</line>
<properties />
<option name="timeStamp" value="44" />
</line-breakpoint>
<line-breakpoint enabled="true" type="java-line">
<url>file://$PROJECT_DIR$/src/main/Main.java</url>
<line>57</line>
<properties />
<option name="timeStamp" value="45" />
</line-breakpoint>
<line-breakpoint enabled="true" type="java-line">
<url>file://$PROJECT_DIR$/src/main/Main.java</url>
<line>58</line>
<properties />
<option name="timeStamp" value="46" />
</line-breakpoint>
<line-breakpoint enabled="true" type="java-line">
<url>file://$PROJECT_DIR$/src/main/Main.java</url>
<line>59</line>
<properties />
<option name="timeStamp" value="49" />
</line-breakpoint>
<line-breakpoint enabled="true" type="java-line">
<url>file://$PROJECT_DIR$/src/main/Main.java</url>
<line>63</line>
<properties />
<option name="timeStamp" value="51" />
</line-breakpoint>
<line-breakpoint enabled="true" type="java-line">
<url>file://$PROJECT_DIR$/src/main/Main.java</url>
<line>67</line>
<properties />
<option name="timeStamp" value="53" />
</line-breakpoint>
<line-breakpoint enabled="true" type="java-line">
<url>file://$PROJECT_DIR$/src/main/Main.java</url>
<line>71</line>
<properties />
<option name="timeStamp" value="56" />
</line-breakpoint>
<line-breakpoint enabled="true" type="java-line">
<url>file://$PROJECT_DIR$/src/main/Main.java</url>
<line>76</line>
<properties />
<option name="timeStamp" value="58" />
</line-breakpoint>
</breakpoints>
</breakpoint-manager>
</component>
<component name="antWorkspaceConfiguration">
<option name="IS_AUTOSCROLL_TO_SOURCE" value="false" />
<option name="FILTER_TARGETS" value="false" />
</component>
<component name="editorHistoryManager">
<entry file="jar:///usr/lib/jvm/java-8-oracle/src.zip!/java/lang/String.java">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-1386">
<caret line="110" column="19" selection-start-line="110" selection-start-column="19" selection-end-line="110" selection-end-column="19" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/src/main/Main.java">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="286">
<caret line="77" column="26" selection-start-line="77" selection-start-column="26" selection-end-line="77" selection-end-column="26" />
<folding>
<element signature="imports" expanded="true" />
</folding>
</state>
</provider>
</entry>
</component>
</project> </project>

View File

@ -9,4 +9,3 @@
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
</component> </component>
</module> </module>

View File

@ -0,0 +1,25 @@
package main;
class ASTNode {
ASTNode left;
ASTNode right;
Token token;
public ASTNode(Token token, ASTNode left, ASTNode right) {
this.left = left;
this.right = right;
this.token = token;
}
public ASTNode(Token token) {
this(token, null, null);
}
@Override
public String toString() {
if (right == null && left == null) {
return String.format("ASTNode{token=%s}", token);
}
return String.format("ASTNode{token=%s,left=%s,right=%s}", token, left, right);
}
}

View File

@ -1,88 +1,153 @@
package main; package main;
import java.util.Scanner; import java.util.*;
import java.util.Stack; import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class Main { public class Main {
public static void main(String[] args) { public static void main(String[] args) {
Scanner scanner = new Scanner(System.in); Scanner scanner = new Scanner(System.in);
String line; String line;
Stack<String> operators = new Stack<>();
Stack<Float> numbers = new Stack<>();
line = scanner.nextLine(); line = scanner.nextLine();
line = line.replace(" ", "");
char[] lineArray = new char[line.length()]; line = line.replace("+-", "-");
line = line.replace("--", "+");
char[] lineArray;
lineArray = line.toCharArray(); lineArray = line.toCharArray();
List<Token> tokens = tokenize(lineArray);
System.out.println(calcExpression(lineArray, operators, numbers)); System.out.println("[\n"+tokens.stream()
.map(item -> "\t"+item)
.collect(Collectors.joining(",\n"))+"\n]");
ASTNode node = parse(tokens);
System.out.println(node.toString());
int result = evaluateAST(node);
System.out.println(result);
} }
static float calcExpression(char[] charArr, Stack<String> operators, Stack<Float> numbers) { static List<Token> tokenize(char[] charArr) {
for(int i = 0; i < charArr.length; i++) { List<Token> tokens = new ArrayList<>();
StringBuilder tmpNumStr = new StringBuilder();
String operatorTemp; boolean isLastCharOperator = false;
float numberTemp; for (int i = 0; i < charArr.length; i++) {
char c = charArr[i];
if (charArr == null) Token token = new Token(TokenType.Unknown, null);
throw new IllegalArgumentException("Num не должен быть null"); if (Character.isDigit(c) || c == '-' && isLastCharOperator) {
isLastCharOperator = false;
switch(charArr[i]) { tmpNumStr.append(c);
// if next char is also digit, then, instead of creating token, parse next digit
// if it's the end of array, then just create token and finish
if (i+1 != charArr.length) {
if(Character.isDigit(charArr[i+1])) {
continue;
}
}
token = new Token(TokenType.Number, Integer.parseInt(tmpNumStr.toString()));
tmpNumStr = new StringBuilder();
} else {
switch (c) {
case '(': { case '(': {
token = new Token(TokenType.Operator, OperatorType.LeftParenthesis);
break; break;
} }
case '+': { case '+': {
operators.push("+"); token = new Token(TokenType.Operator, OperatorType.Add);
break; break;
} }
case '-': { case '-': {
operators.push("-"); token = new Token(TokenType.Operator, OperatorType.Sub);
break; break;
} }
case '*': { case '*': {
operators.push("*"); token = new Token(TokenType.Operator, OperatorType.Mul);
break; break;
} }
case '/': { case '/': {
operators.push("/"); token = new Token(TokenType.Operator, OperatorType.Div);
break; break;
} }
case ')': { case ')': {
operatorTemp = operators.pop(); token = new Token(TokenType.Operator, OperatorType.RightParenthesis);
numberTemp = numbers.pop(); break;
}
}
isLastCharOperator = true;
}
tokens.add(token);
}
switch(operatorTemp) { return tokens;
case "+": { }
numberTemp = numbers.pop() + numberTemp;
static ASTNode parse(List<Token> tokens) {
Stack<ASTNode> output = new Stack<>();
Stack<Token> ops = new Stack<>();
for (Token token : tokens) {
// https://en.wikipedia.org/wiki/Shunting-yard_algorithm
if (token.type == TokenType.Number) {
output.add(new ASTNode(token));
continue;
}
if (token.type == TokenType.Operator) {
if (token.value == OperatorType.LeftParenthesis) {
ops.push(token);
continue;
}
while (ops.size() != 0) {
if (ops.peek().value == OperatorType.LeftParenthesis) {
break; break;
} }
case "-": {
numberTemp = numbers.pop() - numberTemp; if (token.value != OperatorType.RightParenthesis) {
break; if (OperatorType.getPrecedence((OperatorType) ops.peek().value) < OperatorType.getPrecedence((OperatorType) token.value)) {
}
case "*": {
numberTemp = numbers.pop() * numberTemp;
break;
}
case "/": {
numberTemp = numbers.pop() / numberTemp;
break; break;
} }
} }
numbers.push(numberTemp); Token op = ops.pop();
break; ASTNode right = output.pop();
ASTNode left = output.pop();
output.push(new ASTNode(op, left, right));
} }
default: { if (token.value == OperatorType.RightParenthesis) {
numbers.push(Float.parseFloat(String.valueOf(charArr[i]))); ops.pop();
} else {
ops.push(token);
} }
} }
} }
return numbers.pop(); while(ops.size() != 0) {
Token op = ops.pop();
ASTNode right = output.pop();
ASTNode left = output.pop();
output.push(new ASTNode(op, left, right));
}
return output.pop();
}
static int evaluateAST(ASTNode node) {
int val = 0;
if (node.token.type == TokenType.Operator) {
switch ((OperatorType) node.token.value) {
case Add:
val = evaluateAST(node.left) + evaluateAST(node.right);
break;
case Sub:
val = evaluateAST(node.left) - evaluateAST(node.right);
break;
case Mul:
val = evaluateAST(node.left) * evaluateAST(node.right);
break;
case Div:
val = evaluateAST(node.left) / evaluateAST(node.right);
break;
}
} else {
val = (int) node.token.value;
}
return val;
} }
} }

View File

@ -0,0 +1,23 @@
package main;
public enum OperatorType {
Add,
Sub,
Mul,
Div,
LeftParenthesis,
RightParenthesis;
public static int getPrecedence(OperatorType type) {
switch (type) {
case Add:
case Sub:
return 0;
case Mul:
case Div:
return 1;
default:
return -1;
}
}
}

View File

@ -0,0 +1,22 @@
package main;
enum TokenType {
Number,
Operator,
Unknown
}
class Token {
TokenType type;
Object value;
public Token(TokenType type, Object value) {
this.type = type;
this.value = value;
}
@Override
public String toString() {
return "Token{type="+type+", value="+value+"}";
}
}